void CBThreadPoolQueueAdd(CBThreadPoolQueue * self, CBQueueItem * item){ item->next = NULL; item->active = false; item->cleared = false; // Find worker with least items to process uint16_t workerI = 0; for (uint16_t x = 1; x < self->numThreads; x++){ CBMutexLock(self->workers[x].queueMutex); if (self->workers[x].queue.itemNum < self->workers[workerI].queue.itemNum) workerI = x; CBMutexUnlock(self->workers[x].queueMutex); // Queue may change in the meantime but this wont cause any problems } CBWorker * worker = self->workers + workerI; CBMutexLock(self->finishMutex); self->finished = false; CBMutexLock(worker->queueMutex); worker->queue.itemNum++; if (!worker->queue.start) { worker->queue.end = worker->queue.start = item; // We have added the first item to the queue so wake up the thread. assert(worker->queue.itemNum); CBConditionSignal(worker->waitCond); }else worker->queue.end = worker->queue.end->next = item; CBMutexUnlock(worker->queueMutex); CBMutexUnlock(self->finishMutex); }
void CBThreadPoolQueueClear(CBThreadPoolQueue * self){ CBMutexLock(self->finishMutex); for (uint16_t x = 0; x < self->numThreads; x++) { CBMutexLock(self->workers[x].queueMutex); // Empty queue CBFreeQueue(&self->workers[x].queue, self->destroy); self->workers[x].queue.itemNum = 0; CBMutexUnlock(self->workers[x].queueMutex); } self->finished = true; CBConditionSignal(self->finishCond); CBMutexUnlock(self->finishMutex); }
void CBThreadPoolQueueThreadLoop(void * vself){ CBWorker * self = vself; CBMutexLock(self->queueMutex); for (;;) { while (self->queue.itemNum == 0 && !self->threadPoolQueue->shutdown) // Wait for more items to process. We require a loop because when the condition is signaled, the mutex is unlocked but may not be given to this thread. Another thread may use the mutex to clear the queue again, so check in a loop. CBConditionWait(self->waitCond, self->queueMutex); assert(self->queue.itemNum || self->threadPoolQueue->shutdown); // Check to see if the thread should terminate if (self->threadPoolQueue->shutdown){ CBMutexUnlock(self->queueMutex); return; } // Process the next item. CBQueueItem * item = self->queue.start; item->active = true; // Prevent deletion. CBMutexUnlock(self->queueMutex); self->threadPoolQueue->process(self->threadPoolQueue, item); // Now we have finished with the item, remove it from the queue CBMutexLock(self->queueMutex); // Maybe we cleared the queue. Check that it hasn't been. if (!item->cleared) { self->queue.start = item->next; if (--self->queue.itemNum == 0){ // Look for complete emptiness CBMutexLock(self->threadPoolQueue->finishMutex); bool empty = true; for (uint16_t x = 0; x < self->threadPoolQueue->numThreads; x++) if (self->threadPoolQueue->workers[x].queue.itemNum) { empty = false; break; } if (empty){ self->threadPoolQueue->finished = true; CBConditionSignal(self->threadPoolQueue->finishCond); } CBMutexUnlock(self->threadPoolQueue->finishMutex); } } // Now we can destroy the item. self->threadPoolQueue->destroy(item); free(item); } }
void CBDestroyNode(void * vself){ CBNode * self = vself; // Exit thread. self->shutDownThread = true; CBMutexLock(self->messageProcessMutex); if (self->messageQueue == NULL) // The thread is waiting for messages so wake it. CBConditionSignal(self->messageProcessWaitCond); CBMutexUnlock(self->messageProcessMutex); CBThreadJoin(self->messageProcessThread); CBFreeBlockChainStorage(self->blockChainStorage); CBFreeAccounterStorage(self->accounterStorage); CBReleaseObject(self->validator); CBFreeMutex(self->blockAndTxMutex); CBFreeMutex(self->messageProcessMutex); CBFreeCondition(self->messageProcessWaitCond); CBFreeThread(self->messageProcessThread); CBDestroyNetworkCommunicator(vself); }
void CBDestroyThreadPoolQueue(CBThreadPoolQueue * self){ self->shutdown = true; for (uint16_t x = 0; x < self->numThreads; x++) { CBMutexLock(self->workers[x].queueMutex); if (self->workers[x].queue.itemNum == 0) // The thread is waiting for items, so wake it. CBConditionSignal(self->workers[x].waitCond); CBMutexUnlock(self->workers[x].queueMutex); CBThreadJoin(self->workers[x].thread); CBFreeThread(self->workers[x].thread); CBFreeCondition(self->workers[x].waitCond); CBFreeMutex(self->workers[x].queueMutex); // Free queue CBFreeQueue(&self->workers[x].queue, self->destroy); } CBFreeCondition(self->finishCond); CBFreeMutex(self->finishMutex); free(self->workers); }
CBOnMessageReceivedAction CBNodeOnMessageReceived(CBNetworkCommunicator * comm, CBPeer * peer, CBMessage * message){ CBNode * self = CBGetNode(comm); // Add message to queue CBRetainObject(message); CBRetainObject(peer); CBMutexLock(self->messageProcessMutex); if (self->messageQueue == NULL) self->messageQueue = self->messageQueueBack = malloc(sizeof(*self->messageQueueBack)); else{ self->messageQueueBack->next = malloc(sizeof(*self->messageQueueBack)); self->messageQueueBack = self->messageQueueBack->next; } self->messageQueueBack->peer = peer; self->messageQueueBack->message = message; self->messageQueueBack->next = NULL; // Wakeup thread if this is the first in the queue if (self->messageQueue == self->messageQueueBack) // We have just added a block to the queue when there was not one before so wake-up the processing thread. CBConditionSignal(self->messageProcessWaitCond); CBMutexUnlock(self->messageProcessMutex); return CB_MESSAGE_ACTION_CONTINUE; }