X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;f=thread.h;h=85e5200140eb73d522a53c2ebcd24f5b8511dfbf;hb=ed17b0043966690a70381680a95b0e51891efa40;hp=7f590a47dd62f355e89be3435adb4da0ea33540d;hpb=0c38a45ad8a3f7e14631f17983a7fcd5239309c2;p=xonotic%2Fdarkplaces.git diff --git a/thread.h b/thread.h index 7f590a47..85e52001 100644 --- a/thread.h +++ b/thread.h @@ -6,6 +6,9 @@ // use recursive mutex (non-posix) extensions in thread_pthread #define THREADRECURSIVE +typedef int Thread_SpinLock; +typedef struct {int value;} Thread_Atomic; + #define Thread_CreateMutex() (_Thread_CreateMutex(__FILE__, __LINE__)) #define Thread_DestroyMutex(m) (_Thread_DestroyMutex(m, __FILE__, __LINE__)) #define Thread_LockMutex(m) (_Thread_LockMutex(m, __FILE__, __LINE__)) @@ -20,6 +23,14 @@ #define Thread_CreateBarrier(count) (_Thread_CreateBarrier(count, __FILE__, __LINE__)) #define Thread_DestroyBarrier(barrier) (_Thread_DestroyBarrier(barrier, __FILE__, __LINE__)) #define Thread_WaitBarrier(barrier) (_Thread_WaitBarrier(barrier, __FILE__, __LINE__)) +#define Thread_AtomicGet(a) (_Thread_AtomicGet(a, __FILE__, __LINE__)) +#define Thread_AtomicSet(a, v) (_Thread_AtomicSet(a, v, __FILE__, __LINE__)) +#define Thread_AtomicAdd(a, v) (_Thread_AtomicAdd(a, v, __FILE__, __LINE__)) +#define Thread_AtomicIncRef(a) (_Thread_AtomicIncRef(a, __FILE__, __LINE__)) +#define Thread_AtomicDecRef(a) (_Thread_AtomicDecRef(a, __FILE__, __LINE__)) +#define Thread_AtomicTryLock(lock) (_Thread_AtomicTryLock(lock, __FILE__, __LINE__)) +#define Thread_AtomicLock(lock) (_Thread_AtomicLock(lock, __FILE__, __LINE__)) +#define Thread_AtomicUnlock(lock) (_Thread_AtomicUnlock(lock, __FILE__, __LINE__)) int Thread_Init(void); void Thread_Shutdown(void); @@ -38,5 +49,63 @@ int _Thread_WaitThread(void *thread, int retval, const char *filename, int filel void *_Thread_CreateBarrier(unsigned int count, const char *filename, int fileline); void _Thread_DestroyBarrier(void *barrier, const char *filename, int fileline); void _Thread_WaitBarrier(void *barrier, const char *filename, int fileline); +int _Thread_AtomicGet(Thread_Atomic *ref, const char *filename, int fileline); +int _Thread_AtomicSet(Thread_Atomic *ref, int v, const char *filename, int fileline); +int _Thread_AtomicAdd(Thread_Atomic *ref, int v, const char *filename, int fileline); +void _Thread_AtomicIncRef(Thread_Atomic *ref, const char *filename, int fileline); +qboolean _Thread_AtomicDecRef(Thread_Atomic *ref, const char *filename, int fileline); +qboolean _Thread_AtomicTryLock(Thread_SpinLock *lock, const char *filename, int fileline); +void _Thread_AtomicLock(Thread_SpinLock *lock, const char *filename, int fileline); +void _Thread_AtomicUnlock(Thread_SpinLock *lock, const char *filename, int fileline); + +typedef struct taskqueue_task_s +{ + // doubly linked list + struct taskqueue_task_s * volatile prev; + struct taskqueue_task_s * volatile next; + + // if not NULL, this task must be done before this one will dequeue (faster than simply Yielding immediately) + struct taskqueue_task_s *preceding; + + // see TaskQueue_IsDone() to use proper atomics to poll done status + volatile int started; + volatile int done; + + // function to call, and parameters for it to use + void(*func)(struct taskqueue_task_s *task); + void *p[4]; + size_t i[4]; + + // stats: + unsigned int yieldcount; // number of times this task has been requeued +} +taskqueue_task_t; + +// immediately execute any pending tasks if threading is disabled (or if force is true) +// TRY NOT TO USE THIS IF POSSIBLE - poll task->done instead. +void TaskQueue_Execute(qboolean force); + +// queue the tasks to be executed, or executes them immediately if threading is disabled. +void TaskQueue_Enqueue(int numtasks, taskqueue_task_t *tasks); + +// if the task can not be completed due yet to preconditions, just enqueue it again... +void TaskQueue_Yield(taskqueue_task_t *t); + +// polls for status of task and returns the result immediately - use this instead of checking ->done directly, as this uses atomics +qboolean TaskQueue_IsDone(taskqueue_task_t *t); + +// polls for status of task and waits for it to be done +void TaskQueue_WaitForTaskDone(taskqueue_task_t *t); + +// updates thread count based on the cvar. +void TaskQueue_Frame(qboolean shutdown); + +// convenience function for setting up a task structure. Does not do the Enqueue, just fills in the struct. +void TaskQueue_Setup(taskqueue_task_t *t, taskqueue_task_t *preceding, void(*func)(taskqueue_task_t *), size_t i0, size_t i1, void *p0, void *p1); + +// general purpose tasks +// t->i[0] = number of tasks in array +// t->p[0] = array of taskqueue_task_t to check +void TaskQueue_Task_CheckTasksDone(taskqueue_task_t *t); #endif