static void WakeWaiters(BuildQueue* queue, int count) { if (count > 1) CondBroadcast(&queue->m_WorkAvailable); else CondSignal(&queue->m_WorkAvailable); }
void BuildQueueDestroy(BuildQueue* queue) { Log(kDebug, "destroying build queue"); const BuildQueueConfig* config = &queue->m_Config; MutexLock(&queue->m_Lock); queue->m_QuitSignalled = true; MutexUnlock(&queue->m_Lock); CondBroadcast(&queue->m_WorkAvailable); for (int i = 0, thread_count = config->m_ThreadCount; i < thread_count; ++i) { if (i > 0) { Log(kDebug, "joining with build thread %d", i); ThreadJoin(queue->m_Threads[i]); } ThreadStateDestroy(&queue->m_ThreadState[i]); } // Deallocate storage. MemAllocHeap* heap = queue->m_Config.m_Heap; HeapFree(heap, queue->m_ExpensiveWaitList); HeapFree(heap, queue->m_Queue); CondDestroy(&queue->m_WorkAvailable); MutexDestroy(&queue->m_Lock); // Unblock all signals on the main thread. SignalHandlerSetCondition(nullptr); SignalBlockThread(false); }
int main() { TThread loggingThread; TThread *loggerThreads = (TThread*)malloc(sizeof(TThread) * numThreadsToStart); unsigned int i = 0; printf("Creating threads\n"); /* fire off the consumer thread */ ThreadCreate(&loggingThread, log_error_thread, 0); sleep(1); /* fire off the producer threads */ for (i=0; i<numThreadsToStart; ++i) { int *thrNum = (int*)malloc(sizeof(int)); *thrNum = i; ThreadCreate(&loggerThreads[i], testLoggingThread, thrNum); } sleep(1); printf("Signalling START\n"); /* signal that the threads can start */ MutexLock(&cond_mutex); start_flag = 1; CondBroadcast(&start_cond); MutexUnlock(&cond_mutex); printf("Waiting for threads to complete\n"); MutexLock(&threadCountLock); while (threadCount) { CondWait(&threadCountCond, &threadCountLock); } MutexUnlock(&threadCountLock); sleep(10); printf("See ya later, alligator\n"); return EXIT_SUCCESS; }
BuildResult::Enum BuildQueueBuildNodeRange(BuildQueue* queue, int start_index, int count, int pass_index) { // Make sure none of the build threads see in-progress state due to a spurious wakeup. MutexLock(&queue->m_Lock); CHECK(start_index + count <= queue->m_Config.m_MaxNodes); queue->m_CurrentPassIndex = pass_index; // Initialize build queue with index range to build int32_t *build_queue = queue->m_Queue; NodeState *node_states = queue->m_Config.m_NodeState; for (int i = 0; i < count; ++i) { NodeState* state = node_states + start_index + i; NodeStateFlagQueued(state); // Verify node hasn't been touched already CHECK(state->m_Progress == BuildProgress::kInitial); build_queue[i] = start_index + i; } queue->m_PendingNodeCount = count; queue->m_FailedNodeCount = 0; queue->m_QueueWriteIndex = count; queue->m_QueueReadIndex = 0; MutexUnlock(&queue->m_Lock); CondBroadcast(&queue->m_WorkAvailable); // This thread is thread 0. BuildLoop(&queue->m_ThreadState[0]); if (SignalGetReason()) return BuildResult::kInterrupted; else if (queue->m_FailedNodeCount) return BuildResult::kBuildError; else return BuildResult::kOk; }
static void AdvanceNode(BuildQueue* queue, ThreadState* thread_state, NodeState* node, Mutex* queue_lock) { Log(kSpam, "T=%d, [%d] Advancing %s\n", thread_state->m_ThreadIndex, node->m_Progress, node->m_MmapData->m_Annotation.Get()); CHECK(!NodeStateIsCompleted(node)); CHECK(NodeStateIsActive(node)); CHECK(!NodeStateIsQueued(node)); for (;;) { switch (node->m_Progress) { case BuildProgress::kInitial: node->m_Progress = SetupDependencies(queue, node); if (BuildProgress::kBlocked == node->m_Progress) { // Set ourselves as inactive until our dependencies are ready. NodeStateFlagInactive(node); return; } else break; case BuildProgress::kBlocked: CHECK(AllDependenciesReady(queue, node)); node->m_Progress = BuildProgress::kUnblocked; break; case BuildProgress::kUnblocked: node->m_Progress = CheckInputSignature(queue, thread_state, node, queue_lock); break; case BuildProgress::kRunAction: node->m_Progress = RunAction(queue, thread_state, node, queue_lock); // If we couldn't make progress, we're a parked expensive node. // Another expensive job will put us back on the queue later when it // has finshed. if (BuildProgress::kRunAction == node->m_Progress) return; // Otherwise, we just ran our action. If we were an expensive node, // make sure to let other expensive nodes on to the cores now. if (node->m_MmapData->m_Flags & NodeData::kFlagExpensive) { --queue->m_ExpensiveRunning; CHECK(queue->m_ExpensiveRunning >= 0); // We were an expensive job. We can unpark another expensive job if // anything is waiting. UnparkExpensiveNode(queue); } break; case BuildProgress::kSucceeded: case BuildProgress::kUpToDate: node->m_BuildResult = 0; node->m_Progress = BuildProgress::kCompleted; break; case BuildProgress::kFailed: queue->m_FailedNodeCount++; CondBroadcast(&queue->m_WorkAvailable); node->m_BuildResult = 1; node->m_Progress = BuildProgress::kCompleted; break; case BuildProgress::kCompleted: queue->m_PendingNodeCount--; UnblockWaiters(queue, node); CondBroadcast(&queue->m_WorkAvailable); return; default: Croak("invalid node state progress"); break; } } }