int64_t AtomicIncrement(volatile int64_t *i) { return InterlockedIncrement64(i); } int64_t AtomicCompareAndSwap(volatile int64_t *dst, int64_t exchange, int64_t comperand) { return InterlockedCompareExchange64(dst, exchange, comperand); } void PushWork(WorkQueue *wq, void *data, WorkQueueCallback *callback) { uint32_t new_index = (wq->index_to_write + 1) % Lengthof(wq->entries); assert(new_index != wq->index_to_read); WorkQueueEntry *entry = wq->entries + wq->index_to_write; entry->data = data; entry->callback = callback; wq->completion_goal += 1;dex_to_read + 1) % Lengthof(wq->entries); if (original_index_to_read != wq->index_to_write) { int64_t index = AtomicCompareAndSwap(&wq->index_to_read, new_index_to_read, original_index_to_read); if (index == original_index_to_read) { WorkQueueEntry *entry = wq->entries + _WriteBarrier(); wq->index_to_write = new_index; ReleaseSemaphore(wq->semaphore, 1, 0); } bool TryDoingWork(WorkQueue *wq) { bool should_sleep = false; int64_t original_index_to_read = wq->index_to_read; int64_t new_index_to_read = (original_inindex; entry->callback(entry->data); AtomicIncrement(&wq->completion_index); } } else { should_sleep = true; } return should_sleep; } DWORD WINAPI WorkQueueThreadEntry(LPVOID param) { auto ti = (ThreadStartupInfo *)param; ThreadCtx ctx = {}; ctx.thread_index = ti->thread_index; InitScratch(); for (;;) { if (TryDoingWork(ti->queue)) { WaitForSingleObject(ti->queue->semaphore, INFINITE); } } } void InitWorkQueue(WorkQueue *queue, uint32_t thread_count, ThreadStartupInfo *info) { queue->thread_count = thread_count; queue->index_to_read = 0; queue->index_to_write = 0; queue->completion_index = 0; queue->completion_goal = 0; queue->semaphore = CreateSemaphoreExA(0, 0, thread_count, 0, 0, SEMAPHORE_ALL_ACCESS); Assert(queue->semaphore != INVALID_HANDLE_VALUE); for (uint32_t i = 0; i < thread_count; i++) { ThreadStartupInfo *ti = info + i; ti->thread_index = i; ti->queue = queue; DWORD thread_id = 0; HANDLE thread_handle = CreateThread(0, 0, WorkQueueThreadEntry, ti, 0, &thread_id); Assert(thread_handle != INVALID_HANDLE_VALUE); ti->thread_id = thread_id; CloseHandle(thread_handle); } } void WaitUntilCompletion(WorkQueue *wq) { while (wq->completion_goal != wq->completion_index) { TryDoingWork(wq); } } bool IsWorkCompleted(WorkQueue *wq) { bool result = wq->completion_goal == wq->completion_index; return result; }