Esempio n. 1
0
/**
 * Deallocates the system resources used by the lock.
 */
void RWLOCK_Destroy(RWLock * lock) 
{
    QEntry * e;
    ASSERT(!lock->locks);
    ASSERT(!lock->entriesInUse);
    ASSERT(!lock->entriesActive);
    ASSERT(!lock->shareWaiters.size);
    ASSERT(!lock->exclusiveWaiters.size);
    MUTEX_Destroy(&lock->mutex);
    EVENT_Destroy(&lock->shareEvent);
    EVENT_Destroy(&lock->exclusiveEvent);

    /* free dynamically allocated entries */
    if (lock->moreEntries) {
        MEM_Free(lock->moreEntries);
        lock->moreEntries = NULL;
    }

    /* free waiter cache */
    while ((e = QUEUE_RemoveHead(&lock->waiterCache)) != NULL) {
        RWLockWaiter * w = QCAST(e,RWLockWaiter,entry);
        MEM_Free(w);
    }

    /* free dynamically allocated events */
    while (lock->eventsInCache > 0) {
        lock->eventsInCache--;
        ASSERT(lock->eventCache[lock->eventsInCache]);
        EVENT_Delete(lock->eventCache[lock->eventsInCache]);
        lock->eventCache[lock->eventsInCache] = NULL;
    }

    lock->numEntries = 0;
    lock->locks = -1;  /* to cause ASSERT if destroyed twice */
}
Esempio n. 2
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;
}
Esempio n. 3
0
/**
 * Actually submits the XRPC calls from the work thread.
 */
STATIC void GWENG_AsyncXRpc(WorkItem * w, void* arg)
{
    QEntry* e;
    MidpSession* session = arg;
    MUTEX_Lock(&session->xrpcMutex);
    while ((e = QUEUE_RemoveHead(&session->xrpcQueue)) != NULL) {
        AsyncXRpcEntry* a = QCAST(e,AsyncXRpcEntry,entry);
        MUTEX_Unlock(&session->xrpcMutex);
        XRPC_Notify(XRPC_GetClient(session->key.xrpcSession), 
            ECMTGW_SEI_PROTOCOL, a->method, 
            XRPC_ContainerToElement(a->params));
        XRPC_FreeContainer(a->params);
        MEM_Free(a);
        MUTEX_Lock(&session->xrpcMutex);
    }
    MUTEX_Unlock(&session->xrpcMutex);
}
Esempio n. 4
0
/**
 * Cancels all pending work items in the work queue.
 */
void WKQ_Cancel(WorkQueue * q)
{
    if (MUTEX_Lock(&q->mutex)) {
        QEntry * e;
        while ((e = QUEUE_RemoveHead(&q->submit)) != NULL) {
            WorkItem * w = QCAST(e,WorkItem,submitQ);
            w->flags |= WKI_CANCELED;
            if (w->flags & WKI_DETACHED) {
                ASSERT(!w->waiters);
                QUEUE_RemoveEntry(&w->itemsQ);
                WKQ_ReleaseWorkItem(&WKQ, w);
            } else {
                WKI_Signal(w);
            }
        }
        MUTEX_Unlock(&q->mutex);
    }
}
Esempio n. 5
0
/**
 * Deallocates the MIDP session context.
 */
STATIC void GWENG_MidpFree(EcmtGateway* gw, MidpSession* midp)
{
    if (midp) {
        QEntry* e;
        VERIFY(HASH_Remove(&gw->midpSessionMap, &midp->key));
        HASH_Remove(&gw->ecmtSessionMap, (HashKey)midp->sid);
        HASH_Destroy(&midp->connMap);
        WKI_Cancel(midp->xrpcWorkItem);
        WKI_Detach(midp->xrpcWorkItem);
        WKQ_Delete(midp->xrpcWorkThread);
        MUTEX_Destroy(&midp->xrpcMutex);
        while ((e = QUEUE_RemoveHead(&midp->xrpcQueue)) != NULL) {
            AsyncXRpcEntry* a = QCAST(e,AsyncXRpcEntry,entry);
            XRPC_FreeContainer(a->params);
            MEM_Free(a);
        }
        MEM_Free(midp);
    }
}
Esempio n. 6
0
void WKQ_Shutdown()
{
    if ((--WKQ.initcount) == 0) {
        while (WKQ.waitpool) {
            Waiter * next = WKQ.waitpool->next;
            EVENT_Destroy(&WKQ.waitpool->event);
            MEM_Free(WKQ.waitpool);
            WKQ.waitpool = next;
            WKQ.nwait--;
        }
        ASSERT(WKQ.nwait == 0);
        while (!QUEUE_IsEmpty(&WKQ.itempool)) {
            QEntry * e = QUEUE_RemoveHead(&WKQ.itempool);
            WorkItem * w = QCAST(e,WorkItem,itemsQ);
            MEM_Free(w);
        }
        MUTEX_Destroy(&WKQ.mutex);
        THREAD_Shutdown();
    }
}
Esempio n. 7
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;
}
Esempio n. 8
0
/**
 * The worker thread
 */
STATIC void WKQ_Thread(void * par) 
{
    WorkQueue * q = (WorkQueue *)par;
    TRACE("WKQ: starting\n");
    
    /* start the loop */
    MUTEX_Lock(&q->mutex);
    q->lastActivity = TIME_Now();
    while ((q->flags & WKQ_ACTIVE) || !QUEUE_IsEmpty(&q->submit)) {
        QEntry * e;
        while ((e = QUEUE_RemoveHead(&q->submit)) != NULL) {
            WorkItem * w = QCAST(e,WorkItem,submitQ);
            ASSERT(!(w->flags & (WKI_DONE|WKI_CANCELED)));

            /*
             * NULL callback may be used by dummy work items whose purpose
             * is to wait until all pending work items have been processed
             */
            if (w->proc) {

                /* update flags */
                w->flags |= WKI_CALL;

                /* invoke the handler */
                MUTEX_Unlock(&q->mutex);
                w->proc(w, w->param);
                MUTEX_Lock(&q->mutex);

                q->lastActivity = TIME_Now();
                if (w->flags & WKI_DETACHED) {
                
                    /* put the work item to the pool or deallocate it */
                    ASSERT(!w->waiters);
                    QUEUE_RemoveEntry(&w->itemsQ);
                    WKQ_ReleaseWorkItem(&WKQ, w);

                } else {

                    /* 
                     * update flags. Note that we released the mutex when 
                     * were invoking the callback. Therefore, this work 
                     * item could be re-submitted to the queue. Or it could
                     * be re-submitted and then canceled. In such cases we
                     * don't need to set the WKI_DONE flag.
                     */
                    w->flags &= ~WKI_CALL;
                    if (!(w->flags & WKI_CANCELED) && !w->submitQ.queue) {
                        w->flags |= WKI_DONE;
                    }

                    /* signal the events associated with the work item */
                    WKI_Signal(w);
                }
            } else {
                
                /* it's a dummy work item. Just release the waiters */
                WKI_Signal(w);
            }
        }

        /* wait for a signal */
        if (q->flags & WKQ_ACTIVE) {
            EVENT_Reset(&q->event);
            if (q->idleProc) {

                /* we have an idle timeout */
                IdleProc idle = q->idleProc;
                void * param = q->idleParam;
                Time now = TIME_Now();
                Time deadline = q->lastActivity + q->idleTimeout;
                if (deadline > now) {
                    MUTEX_Unlock(&q->mutex);
                    switch (EVENT_TimeWait(&q->event,(long)(deadline-now))) {

                    case WAIT_STATE_OK:
                        /* don't invoke idle callback */
                        MUTEX_Lock(&q->mutex);
                        break;

                    case WAIT_STATE_TIMEOUT:
                        /* invoke idle callback */
                        MUTEX_Lock(&q->mutex);
                        now = TIME_Now();
                        deadline = q->lastActivity + q->idleTimeout;
                        if (deadline <= now) {
                            MUTEX_Unlock(&q->mutex);
                            q->lastActivity = now;
                            idle(q, param);
                            MUTEX_Lock(&q->mutex);
                        }
                        break;

                    default:
                    case WAIT_STATE_ERROR:
                        /* terminate the thread on error */
                        MUTEX_Lock(&q->mutex);
                        q->flags &= ~WKQ_ACTIVE;
                        break;
                    }
                } else {
                    q->lastActivity = now;
                    MUTEX_Unlock(&q->mutex);
                    idle(q, param);
                    MUTEX_Lock(&q->mutex);
                }

            } else {

                /* wait forever */
                MUTEX_Unlock(&q->mutex);
                EVENT_Wait(&q->event);
                MUTEX_Lock(&q->mutex);
            }
        }
    }

    /* cleanup */
    MUTEX_Unlock(&q->mutex);
    TRACE("WKQ: done\n");
    if (q->flags & WKQ_KILLME) {
        TRACE1("WKQ: killing WorkQueue %p\n",q);
        WKQ_Free(q);
    }
}