/** * Queues a work item to a work queue. * * \param WorkQueue A work queue object. * \param Function A function to execute. * \param Context A user-defined value to pass to the function. * \param DeleteFunction A callback function that is executed when the work queue item is about to be freed. */ VOID PhQueueItemWorkQueueEx( _Inout_ PPH_WORK_QUEUE WorkQueue, _In_ PUSER_THREAD_START_ROUTINE Function, _In_opt_ PVOID Context, _In_opt_ PPH_WORK_QUEUE_ITEM_DELETE_FUNCTION DeleteFunction ) { PPH_WORK_QUEUE_ITEM workQueueItem; workQueueItem = PhpCreateWorkQueueItem(Function, Context, DeleteFunction); // Enqueue the work item. PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); InsertTailList(&WorkQueue->QueueListHead, &workQueueItem->ListEntry); _InterlockedIncrement(&WorkQueue->BusyCount); PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); // Signal the semaphore once to let a worker thread continue. NtReleaseSemaphore(PhpGetSemaphoreWorkQueue(WorkQueue), 1, NULL); PHLIB_INC_STATISTIC(WqWorkItemsQueued); // Check if all worker threads are currently busy, and if we can create more threads. if (WorkQueue->BusyCount >= WorkQueue->CurrentThreads && WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) { // Lock and re-check. PhAcquireQueuedLockExclusive(&WorkQueue->StateLock); if (WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) PhpCreateWorkQueueThread(WorkQueue); PhReleaseQueuedLockExclusive(&WorkQueue->StateLock); } }
/** * Queues a work item to a work queue. * * \param WorkQueue A work queue object. * \param Function A function to execute. * \param Context A user-defined value to pass to the function. */ VOID PhQueueItemWorkQueue( __inout PPH_WORK_QUEUE WorkQueue, __in PTHREAD_START_ROUTINE Function, __in_opt PVOID Context ) { PPH_WORK_QUEUE_ITEM workQueueItem; workQueueItem = PhAllocateFromFreeList(&PhWorkQueueItemFreeList); PhpInitializeWorkQueueItem(workQueueItem, Function, Context); // Enqueue the work item. PhAcquireQueuedLockExclusive(&WorkQueue->QueueLock); InsertTailList(&WorkQueue->QueueListHead, &workQueueItem->ListEntry); PhReleaseQueuedLockExclusive(&WorkQueue->QueueLock); // Signal the semaphore once to let a worker thread continue. NtReleaseSemaphore(WorkQueue->SemaphoreHandle, 1, NULL); PHLIB_INC_STATISTIC(WqWorkItemsQueued); // Check if all worker threads are currently busy, // and if we can create more threads. if ( WorkQueue->BusyThreads == WorkQueue->CurrentThreads && WorkQueue->CurrentThreads < WorkQueue->MaximumThreads ) { // Lock and re-check. PhAcquireQueuedLockExclusive(&WorkQueue->StateLock); if (WorkQueue->CurrentThreads < WorkQueue->MaximumThreads) { PhpCreateWorkQueueThread(WorkQueue); } PhReleaseQueuedLockExclusive(&WorkQueue->StateLock); } }