Example #1
0
/**
 * Puts work item to the global pool or deallocates it. Also deallocates 
 * the events associated with the work item. NOTE: this code is designed 
 * to be efficient, not compact
 */
STATIC void WKQ_ReleaseWorkItem(WorkQueueModule * module, WorkItem * w)
{
    Bool locked = False;

    ASSERT(module->initcount > 0);
    ASSERT(!w->submitQ.queue);
    ASSERT(!w->itemsQ.queue);

    /* deallocate waiters */
    while (w->waiters) {
        Waiter * waiter = w->waiters;
        Waiter * next = waiter->next;

        if (module->nwait < module->maxwait) {
            if (locked) {
                WKQ_WaiterToPool(module, waiter);
                waiter = NULL;
            } else {
                locked = MUTEX_Lock(&module->mutex);
                if (module->nwait < module->maxwait) {                    
                    WKQ_WaiterToPool(module, waiter);
                    waiter = NULL;
                }
            }
        }

        if (waiter) {
            EVENT_Destroy(&waiter->event);
            MEM_Free(waiter);
        }

        w->waiters = next;
    }

    if (QUEUE_Size(&module->itempool) < module->maxitems) {
        if (locked) {
            w->flags = WKI_DETACHED;
            QUEUE_InsertTail(&module->itempool, &w->itemsQ);
        } else {
            locked = MUTEX_Lock(&module->mutex);
            if (QUEUE_Size(&module->itempool) < module->maxitems) {
                w->flags = WKI_DETACHED;
                QUEUE_InsertTail(&module->itempool, &w->itemsQ);
            } else {
                MEM_Free(w);
            }
        }
    } else {
        MEM_Free(w);
    }

    if (locked) {
        MUTEX_Unlock(&module->mutex);
    }
}
Example #2
0
/**
 * Submits asynchronous XRPC call. Doesn't wait until the call completes.
 * This resolves the deadlock between Ecmt Gateway and emulator.exe
 */
STATIC void GWENG_SubmitAsyncCall(MidpSession* midp, 
                                  XRpcString method,
                                  XRpcContainer* params)
{
    if (params) {
        AsyncXRpcEntry* a = MEM_New(AsyncXRpcEntry);
        if (a) {
            memset(a, 0, sizeof(*a));
            a->method = method;
            a->params = params;

            MUTEX_Lock(&midp->xrpcMutex);
            QUEUE_InsertTail(&midp->xrpcQueue, &a->entry);
            MUTEX_Unlock(&midp->xrpcMutex);

            if (!WKI_Submit(midp->xrpcWorkItem)) {

                /* 
                 * The work item is busy processing pending calls. It
                 * could be that GWENG_AsyncXRpc callback has already
                 * exited the loop but hasn't returned yet. In that case,
                 * this asynchronous call would remain in the queue until
                 * we submit the next one. That's not good. Try to "kick"
                 * it with another work item.
                 */
                WKQ_InvokeLater(midp->xrpcWorkThread, GWENG_AsyncXRpc, midp);
            }
        } else {
            XRPC_FreeContainer(params);
        }
    }
}
Example #3
0
/**
 * Gets a RWLockWaiter structure for a shared waiter from the cache or 
 * allocates a new one. Must be called under synchronization
 */
STATIC RWLockWaiter * RWLOCK_GetShareWaiter(RWLock * lock)
{
    RWLockWaiter * w = RWLOCK_GetWaiter(lock);
    if (w) {
        w->event = &lock->shareEvent;
        QUEUE_InsertTail(&lock->shareWaiters, &w->entry);
    }
    return w;
}
Example #4
0
/**
 * Puts RWLockWaiter structure into the cache or deallocates it. This is
 * enough for a shared waiter but not for exclusive waiter (see function
 * below). Must be used under synchronization.
 */
STATIC void RWLOCK_ReleaseWaiter(RWLock * lock, RWLockWaiter * w)
{
    QUEUE_RemoveEntry(&w->entry);
    if (QUEUE_Size(&lock->waiterCache) < MAX_WAITER_CACHE_SIZE) {
        w->index = 0;
        w->event = NULL;
        QUEUE_InsertTail(&lock->waiterCache, &w->entry);
    } else {
        MEM_Free(w);
    }
}
Example #5
0
/**
 * Moves all the entries from the source queue to the tail of the destination
 * queue. DOES NOT remove the entries that are already in the destination 
 * queue. Returns number of moved entries.
 */
int QUEUE_Move(Queue * dest, Queue * src)
{
    int n = 0;
    if (src && src != dest && QUEUE_Size(src) > 0) {
        QEntry * e;
        while ((e = QUEUE_RemoveHead(src)) != NULL) {
            QUEUE_InsertTail(dest, e);
            n++;
        }
        ASSERT(QUEUE_Size(src) == 0);
    }
    return n;
}
Example #6
0
/**
 * Gets a RWLockWaiter structure for an exclusive waiter from the cache or 
 * allocates a new one. Adds the waiter to the tail of the queue. 
 * Must be called under synchronization
 */
STATIC RWLockWaiter * RWLOCK_GetExclusiveWaiter(RWLock * lock)
{
    RWLockWaiter * w = RWLOCK_GetWaiter(lock);
    if (w) {
        if (lock->flags & RWLOCK_FLAG_EXCLUSIVE_EVENT_IN_USE) {
            ASSERT(w->index);
            w->event = RWLOCK_GetExclusiveEvent(lock);
            if (!w->event) {
                RWLOCK_ReleaseWaiter(lock, w);
                return NULL;
            }
        } else {
            lock->flags |= RWLOCK_FLAG_EXCLUSIVE_EVENT_IN_USE;
            w->event = &lock->exclusiveEvent;
        }
        QUEUE_InsertTail(&lock->exclusiveWaiters, &w->entry);
        return w;
    }
    return NULL;
}
Example #7
0
/**
 * Submits a work item to the specified work queue. Re-submitting the same
 * work before it has been executed just moves it to the tail of the work
 * queue. It does NOT schedule it to run twice.
 */
Bool WKI_Submit(WorkItem * w)
{
    WorkQueue * q = WKI_GetQueue(w);
    ASSERT(q);
    ASSERT(!(w->flags & WKI_DETACHED));
    if (q) {
        if (MUTEX_Lock(&q->mutex)) {
            if (q->flags & WKQ_ACTIVE) {
                w->flags &= ~(WKI_DONE | WKI_CANCELED);
                QUEUE_RemoveEntry(&w->submitQ);
                QUEUE_InsertTail(&q->submit, &w->submitQ);
                EVENT_Set(&q->event);
                MUTEX_Unlock(&q->mutex);
                return True;
            }
            MUTEX_Unlock(&q->mutex);
            /* fall through and return False */
        }
    }
    return False;
}
Example #8
0
/**
 * Returns work item from the pool, allocates a new one if needed.
 */
STATIC WorkItem *
WKQ_GetWorkItem(WorkQueueModule * mod, WorkQueue * q, 
    WorkProc cb, WorkProc2 cb2, void * p1, void * p2)
{
    WorkItem * w = NULL;

    ASSERT(mod->initcount > 0);
    /* can't use QUEUE_IsEmpty without synchronization */
    if (!mod->itempool.size) {
        MUTEX_Lock(&mod->mutex);
        if (!QUEUE_IsEmpty(&mod->itempool)) {
            w = QCAST(QUEUE_RemoveHead(&mod->itempool),WorkItem,itemsQ);
            w->flags = 0;
        }
        MUTEX_Unlock(&mod->mutex);
    }

    if (!w) {
        w = MEM_New(WorkItem);
        if (w) {
            memset(w, 0, sizeof(*w));
        }
    }

    if (w) {
        if (MUTEX_Lock(&q->mutex)) {
            w->proc = cb;
            w->proc2 = cb2;
            w->param = p1;
            w->param2 = p2;
            QUEUE_InsertTail(&q->items,&w->itemsQ);
            MUTEX_Unlock(&q->mutex);
            return w;
        }
        MEM_Free(w);
    }

    return NULL;
}