/** * 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 */ }
/** * Creates and starts n worker thread */ WorkQueue * WKQ_CreatePool(int n) { size_t size = sizeof(WorkQueue) + sizeof(ThrID)*(MAX(n,1)-1); WorkQueue * q = MEM_Alloc(size); if (q) { ASSERT(WKQ.initcount > 0); if (WKQ.initcount == 0) WKQ_InitModule(); memset(q, 0, size); q->nthreads = n; if (MUTEX_Init(&q->mutex)) { if (EVENT_Init(&q->event)) { if (EVENT_Init(&q->stopEvent)) { if (EVENT_Reset(&q->stopEvent)) { int i; q->flags = WKQ_ACTIVE; QUEUE_Init(&q->items); QUEUE_Init(&q->submit); for (i=0; i<n; i++) { if (!THREAD_Create(q->threads+i, WKQ_Thread, q)) { WKQ_Delete(q); return NULL; } } return q; } EVENT_Destroy(&q->stopEvent); } EVENT_Destroy(&q->event); } MUTEX_Destroy(&q->mutex); } MEM_Free(q); } return NULL; }
/** * Deallocates the work queue */ STATIC void WKQ_Free(WorkQueue * q) { ASSERT(QUEUE_IsEmpty(&q->submit)); ASSERT(QUEUE_IsEmpty(&q->items)); ASSERT(q->flags & WKQ_DEAD); EVENT_Destroy(&q->stopEvent); EVENT_Destroy(&q->event); MUTEX_Destroy(&q->mutex); MEM_Free(q); }
/** * Deletes and deallocates the event previously allocated with * EVENT_Create() */ void EVENT_Delete(Event * e) { if (e) { EVENT_Destroy(e); MEM_Free(e); } }
/** * 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); } }
/** * Decrements the reference count and deallocates the ThrData structure * when it reaches zero. */ STATIC void THREAD_Deref(ThrData* thr) { ASSERT(thr->refCount > 0); ASSERT(thr->signature == ThrData_Signature); if (InterlockedDecrement(&thr->refCount) == 0) { ASSERT(!thr->cleanupList.data); if (!CloseHandle(thr->handle)) WIN32_FAILURE(CloseHandle); EVENT_Destroy(&thr->exitEvent); thr->signature = 0; MEM_Free(thr); } }
/** * Puts event back to the pool or deallocates it. */ STATIC void WKQ_ReleaseWaiter(WorkQueueModule * module, Waiter * waiter) { ASSERT(module->initcount > 0); if (module->nwait < module->maxwait) { MUTEX_Lock(&module->mutex); if (module->nwait < module->maxwait) { WKQ_WaiterToPool(module, waiter); waiter = NULL; } MUTEX_Unlock(&module->mutex); } if (waiter) { EVENT_Destroy(&waiter->event); MEM_Free(waiter); } }
/** * Create a new thread, returning True on success */ Bool THREAD_Create(ThrID* id, ThrProc proc, void * arg) { ThrData * thr = NULL; ASSERT(THREAD_IsInited()); if (id) *id = NULL; if (!THREAD_IsInited()) return False; /* allocate thread data */ thr = MEM_New(ThrData); if (thr) { memset(thr, 0, sizeof(*thr)); if (EVENT_Init(&thr->exitEvent)) { InterlockedIncrement(&WIN32_ThreadCount); thr->signature = ThrData_Signature; thr->refCount = 2; thr->proc = proc; thr->arg = arg; /* create Win32 thread */ thr->handle = CreateThread(NULL, 0, WIN32_ThreadProc, thr, CREATE_SUSPENDED, &thr->thrid); ASSERT(thr->handle); if (thr->handle) { if (ResumeThread(thr->handle) != (DWORD)-1) { if (id) *id = thr; return True; } else { WIN32_FAILURE(ResumeThread); VERIFY(CloseHandle(thr->handle)); } } else { WIN32_FAILURE(CreateThread); } EVENT_Destroy(&thr->exitEvent); InterlockedDecrement(&WIN32_ThreadCount); } MEM_Free(thr); } return False; }
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(); } }
/** * Initialize the lock. */ Bool RWLOCK_Init(RWLock * lock) { LOCK_InitCheck(); memset(lock, 0, sizeof(*lock)); if (MUTEX_Init(&lock->mutex)) { if (EVENT_Init(&lock->shareEvent)) { if (EVENT_Init(&lock->exclusiveEvent)) { QUEUE_Init(&lock->shareWaiters); QUEUE_Init(&lock->exclusiveWaiters); QUEUE_Init(&lock->waiterCache); lock->numEntries = COUNT(lock->staticEntries); lock->lock.type = &LockType_RWLock; return True; } EVENT_Destroy(&lock->shareEvent); } MUTEX_Destroy(&lock->mutex); } return False; }
/** * The program entry point */ int main(int argc, char * argv[]) { int mask = ECMTGW_LISTEN_DEFAULT_MASK; Bool traceReceive = False; Bool traceSend = False; Str host = NULL; Str file = NULL; CmdLine* c; GwTrace trace; XRpcRegistry * r; /* Initialize the XRPC library */ XRPC_Init(); /* First step of initializing GwTrace context */ memset(&trace, 0, sizeof(trace)); VECTOR_Init(&trace.includeUid, 0, NULL, NULL); VECTOR_Init(&trace.excludeUid, 0, NULL, NULL); /* Parse command line */ c = CMDLINE_Create(pname); if (c) { CmdOpt* includeOpt; CmdOpt* excludeOpt; Bool done = False; Bool help = False; CMDLINE_SetMaxArgs(c, 1); CMDLINE_AddTrueOpt(c,'h',"help", "print this help and exit",&help); CMDLINE_AddTrueOpt(c,'s',"sent", "trace packets sent to the handset",&traceSend); CMDLINE_AddTrueOpt(c,'r',"receive", "trace packets received from the handset",&traceReceive); includeOpt = CMDLINE_AddOpt(c,'u',"include", "include this UID in the trace (repeatable)", GWTRACE_ParseUidOpt, &trace.includeUid, "UID"); excludeOpt = CMDLINE_AddOpt(c,'x',"exclude", "exclude this UID from the trace (repeatable)", GWTRACE_ParseUidOpt, &trace.excludeUid, "UID"); CMDLINE_SetParamName(CMDLINE_AddStrOpt(c,'o',"output", "write binary Ecmt messages into a file",&file),"FILE"); CMDLINE_SetRepeatable(includeOpt); CMDLINE_SetRepeatable(excludeOpt); CMDLINE_Exclude(includeOpt, excludeOpt); if (!CMDLINE_Parse1(c,argv+1,argc-1,0,&host) || help) { CMDLINE_Usage(c, "[HOST]", 0); CMDLINE_Delete(c); VECTOR_Destroy(&trace.includeUid); VECTOR_Destroy(&trace.excludeUid); XRPC_Deinit(); return 0; } CMDLINE_Delete(c); } if (traceReceive || traceSend) { mask = 0; if (traceReceive) mask |= ECMTGW_LISTEN_MASK_RECEIVE; if (traceSend) mask |= ECMTGW_LISTEN_MASK_SEND; } /* connect to the registry */ r = XREG_ConnectRegistry(host, XREG_DEFAULT_PORT); if (r) { /* find the server port */ XRpcPort gwPort = 0; XREG_List(r, ECMTGW_PROTOCOL, GWTRACE_ListCB, &gwPort); XREG_FreeRegistry(r); if (gwPort) { if (EVENT_Init(&exitEvent)) { if (GWTRACE_Init(&trace, host, gwPort, file)) { /* Install signal handlers */ #ifndef _WIN32 signal(SIGPIPE, GWTRACE_Interrupt); #endif /* _WIN32 */ signal(SIGINT, GWTRACE_Interrupt); /* Enable notifications */ XRPC_FormatNotify(XRPC_GetClient(trace.session), ECMTGW_PROTOCOL, ECMTGW_REGISTER_LISTENER_METHOD,"%" ECMTGW_LISTENER_PROTOCOL_PARAM"!s%" ECMTGW_LISTENER_MASK_PARAM"!i", ECMTGW_LISTENER_PROTOCOL, mask); /* Wait */ EVENT_Wait(&exitEvent); /* cleanup */ XRPC_FreeSession(trace.session); XRPC_FreeServer(trace.server); if (trace.file) FILE_Close(trace.file); } EVENT_Destroy(&exitEvent); } } else { PRINT_Error("%s: Ecmt Gateway is not running.\n",pname); } } else if (host) { PRINT_Verbose("%s: XRPC registry is not running on %s\n",pname,host); PRINT_Error("%s: Ecmt Gateway is not running on %s.\n",pname,host); } else { PRINT_Verbose("%s: XRPC registry is not running\n",pname); PRINT_Error("%s: Ecmt Gateway is not running.\n",pname); } VECTOR_Destroy(&trace.includeUid); VECTOR_Destroy(&trace.excludeUid); /* Deinitialize the XRPC library */ XRPC_Deinit(); return 0; }