+void TaskQueue_DistributeTasks(void)\r
+{\r
+ Thread_AtomicLock(&taskqueue_state.command_lock);\r
+ if (taskqueue_state.numthreads > 0)\r
+ {\r
+ unsigned int attempts = taskqueue_state.numthreads;\r
+ while (attempts-- > 0 && taskqueue_state.queue_enqueueposition != taskqueue_state.queue_dequeueposition)\r
+ {\r
+ taskqueue_task_t *t = taskqueue_state.queue_data[taskqueue_state.queue_dequeueposition];\r
+ if (t->preceding && t->preceding->done == 0)\r
+ {\r
+ // task is waiting on something\r
+ // first dequeue it properly\r
+ taskqueue_state.queue_data[taskqueue_state.queue_dequeueposition] = NULL;\r
+ taskqueue_state.queue_dequeueposition++;\r
+ if (taskqueue_state.queue_dequeueposition >= taskqueue_state.queue_size)\r
+ taskqueue_state.queue_dequeueposition = 0;\r
+ // now put it back in the distributor queue - we know there is room because we just made room\r
+ taskqueue_state.queue_data[taskqueue_state.queue_enqueueposition] = t;\r
+ taskqueue_state.queue_enqueueposition++;\r
+ if (taskqueue_state.queue_enqueueposition >= taskqueue_state.queue_size)\r
+ taskqueue_state.queue_enqueueposition = 0;\r
+ // we do not refresh the attempt counter here to avoid deadlock - quite often the only things sitting in the distributor queue are waiting on other tasks\r
+ }\r
+ else\r
+ {\r
+ taskqueue_state_thread_t *s = &taskqueue_state.threads[taskqueue_state.enqueuethread];\r
+ if (s->enqueueposition - s->dequeueposition < THREADTASKS)\r
+ {\r
+ // add the task to the thread's queue\r
+ s->queue[(s->enqueueposition++) % THREADTASKS] = t;\r
+ // since we succeeded in assigning the task, advance the distributor queue\r
+ taskqueue_state.queue_data[taskqueue_state.queue_dequeueposition] = NULL;\r
+ taskqueue_state.queue_dequeueposition++;\r
+ if (taskqueue_state.queue_dequeueposition >= taskqueue_state.queue_size)\r
+ taskqueue_state.queue_dequeueposition = 0;\r
+ // refresh our attempt counter because we did manage to assign something to a thread\r
+ attempts = taskqueue_state.numthreads;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ Thread_AtomicUnlock(&taskqueue_state.command_lock);\r
+ // execute one pending task on the distributor queue, this matters if numthreads is 0\r
+ if (taskqueue_state.queue_dequeueposition != taskqueue_state.queue_enqueueposition)\r
+ {\r
+ taskqueue_task_t *t = taskqueue_state.queue_data[taskqueue_state.queue_dequeueposition];\r
+ taskqueue_state.queue_dequeueposition++;\r
+ if (taskqueue_state.queue_dequeueposition >= taskqueue_state.queue_size)\r
+ taskqueue_state.queue_dequeueposition = 0;\r
+ if (t)\r
+ TaskQueue_ExecuteTask(t);\r
+ }\r
+}\r
+\r