]> git.xonotic.org Git - xonotic/darkplaces.git/blob - thread_win.c
thread_pthread now uses recursive mutex (THREADRECURSIVE)
[xonotic/darkplaces.git] / thread_win.c
1 #include "quakedef.h"
2 #include "thread.h"
3 #include <process.h>
4
5 int Thread_Init(void)
6 {
7         return 0;
8 }
9
10 void Thread_Shutdown(void)
11 {
12 }
13
14 qboolean Thread_HasThreads(void)
15 {
16         return true;
17 }
18
19 void *_Thread_CreateMutex(const char *filename, int fileline)
20 {
21         void *mutex = (void *)CreateMutex(NULL, FALSE, NULL);
22 #ifdef THREADDEBUG
23         Sys_PrintfToTerminal("%p mutex create %s:%i\n" , mutex, filename, fileline);
24 #endif
25         return mutex;
26 }
27
28 void _Thread_DestroyMutex(void *mutex, const char *filename, int fileline)
29 {
30 #ifdef THREADDEBUG
31         Sys_PrintfToTerminal("%p mutex destroy %s:%i\n", mutex, filename, fileline);
32 #endif
33         CloseHandle(mutex);
34 }
35
36 int _Thread_LockMutex(void *mutex, const char *filename, int fileline)
37 {
38 #ifdef THREADDEBUG
39         Sys_PrintfToTerminal("%p mutex lock %s:%i\n"   , mutex, filename, fileline);
40 #endif
41         return (WaitForSingleObject(mutex, INFINITE) == WAIT_FAILED) ? -1 : 0;
42 }
43
44 int _Thread_UnlockMutex(void *mutex, const char *filename, int fileline)
45 {
46 #ifdef THREADDEBUG
47         Sys_PrintfToTerminal("%p mutex unlock %s:%i\n" , mutex, filename, fileline);
48 #endif
49         return (ReleaseMutex(mutex) == FALSE) ? -1 : 0;
50 }
51
52 typedef struct thread_semaphore_s
53 {
54         HANDLE semaphore;
55         volatile LONG value;
56 }
57 thread_semaphore_t;
58
59 static thread_semaphore_t *Thread_CreateSemaphore(unsigned int v)
60 {
61         thread_semaphore_t *s = (thread_semaphore_t *)calloc(sizeof(*s), 1);
62         s->semaphore = CreateSemaphore(NULL, v, 32768, NULL);
63         s->value = v;
64         return s;
65 }
66
67 static void Thread_DestroySemaphore(thread_semaphore_t *s)
68 {
69         CloseHandle(s->semaphore);
70         free(s);
71 }
72
73 static int Thread_WaitSemaphore(thread_semaphore_t *s, unsigned int msec)
74 {
75         int r = WaitForSingleObject(s->semaphore, msec);
76         if (r == WAIT_OBJECT_0)
77         {
78                 InterlockedDecrement(&s->value);
79                 return 0;
80         }
81         if (r == WAIT_TIMEOUT)
82                 return 1;
83         return -1;
84 }
85
86 static int Thread_PostSemaphore(thread_semaphore_t *s)
87 {
88         InterlockedIncrement(&s->value);
89         if (ReleaseSemaphore(s->semaphore, 1, NULL))
90                 return 0;
91         InterlockedDecrement(&s->value);
92         return -1;
93 }
94
95 typedef struct thread_cond_s
96 {
97         HANDLE mutex;
98         int waiting;
99         int signals;
100         thread_semaphore_t *sem;
101         thread_semaphore_t *done;
102 }
103 thread_cond_t;
104
105 void *_Thread_CreateCond(const char *filename, int fileline)
106 {
107         thread_cond_t *c = (thread_cond_t *)calloc(sizeof(*c), 1);
108         c->mutex = CreateMutex(NULL, FALSE, NULL);
109         c->sem = Thread_CreateSemaphore(0);
110         c->done = Thread_CreateSemaphore(0);
111         c->waiting = 0;
112         c->signals = 0;
113 #ifdef THREADDEBUG
114         Sys_PrintfToTerminal("%p cond create %s:%i\n"   , c, filename, fileline);
115 #endif
116         return c;
117 }
118
119 void _Thread_DestroyCond(void *cond, const char *filename, int fileline)
120 {
121         thread_cond_t *c = (thread_cond_t *)cond;
122 #ifdef THREADDEBUG
123         Sys_PrintfToTerminal("%p cond destroy %s:%i\n"   , cond, filename, fileline);
124 #endif
125         Thread_DestroySemaphore(c->sem);
126         Thread_DestroySemaphore(c->done);
127         CloseHandle(c->mutex);
128 }
129
130 int _Thread_CondSignal(void *cond, const char *filename, int fileline)
131 {
132         thread_cond_t *c = (thread_cond_t *)cond;
133         int n;
134 #ifdef THREADDEBUG
135         Sys_PrintfToTerminal("%p cond signal %s:%i\n"   , cond, filename, fileline);
136 #endif
137         WaitForSingleObject(c->mutex, INFINITE);
138         n = c->waiting - c->signals;
139         if (n > 0)
140         {
141                 c->signals++;
142                 Thread_PostSemaphore(c->sem);
143         }
144         ReleaseMutex(c->mutex);
145         if (n > 0)
146                 Thread_WaitSemaphore(c->done, INFINITE);
147         return 0;
148 }
149
150 int _Thread_CondBroadcast(void *cond, const char *filename, int fileline)
151 {
152         thread_cond_t *c = (thread_cond_t *)cond;
153         int i = 0;
154         int n = 0;
155 #ifdef THREADDEBUG
156         Sys_PrintfToTerminal("%p cond broadcast %s:%i\n"   , cond, filename, fileline);
157 #endif
158         WaitForSingleObject(c->mutex, INFINITE);
159         n = c->waiting - c->signals;
160         if (n > 0)
161         {
162                 c->signals += n;
163                 for (i = 0;i < n;i++)
164                         Thread_PostSemaphore(c->sem);
165         }
166         ReleaseMutex(c->mutex);
167         for (i = 0;i < n;i++)
168                 Thread_WaitSemaphore(c->done, INFINITE);
169         return 0;
170 }
171
172 int _Thread_CondWait(void *cond, void *mutex, const char *filename, int fileline)
173 {
174         thread_cond_t *c = (thread_cond_t *)cond;
175         int waitresult;
176 #ifdef THREADDEBUG
177         Sys_PrintfToTerminal("%p cond wait %s:%i\n"   , cond, filename, fileline);
178 #endif
179
180         WaitForSingleObject(c->mutex, INFINITE);
181         c->waiting++;
182         ReleaseMutex(c->mutex);
183
184         ReleaseMutex(mutex);
185
186         waitresult = Thread_WaitSemaphore(c->sem, INFINITE);
187         WaitForSingleObject(c->mutex, INFINITE);
188         if (c->signals > 0)
189         {
190                 if (waitresult > 0)
191                         Thread_WaitSemaphore(c->sem, INFINITE);
192                 Thread_PostSemaphore(c->done);
193                 c->signals--;
194         }
195         c->waiting--;
196         ReleaseMutex(c->mutex);
197
198         WaitForSingleObject(mutex, INFINITE);
199         return waitresult;
200 }
201
202 typedef struct threadwrapper_s
203 {
204         HANDLE handle;
205         unsigned int threadid;
206         int result;
207         int (*fn)(void *);
208         void *data;
209 }
210 threadwrapper_t;
211
212 unsigned int __stdcall Thread_WrapperFunc(void *d)
213 {
214         threadwrapper_t *w = (threadwrapper_t *)d;
215         w->result = w->fn(w->data);
216         _endthreadex(w->result);
217         return w->result;
218 }
219
220 void *_Thread_CreateThread(int (*fn)(void *), void *data, const char *filename, int fileline)
221 {
222         threadwrapper_t *w = (threadwrapper_t *)calloc(sizeof(*w), 1);
223 #ifdef THREADDEBUG
224         Sys_PrintfToTerminal("%p thread create %s:%i\n"   , w, filename, fileline);
225 #endif
226         w->fn = fn;
227         w->data = data;
228         w->threadid = 0;
229         w->result = 0;
230         w->handle = (HANDLE)_beginthreadex(NULL, 0, Thread_WrapperFunc, (void *)w, 0, &w->threadid);
231         return (void *)w;
232 }
233
234 int _Thread_WaitThread(void *d, int retval, const char *filename, int fileline)
235 {
236         threadwrapper_t *w = (threadwrapper_t *)d;
237 #ifdef THREADDEBUG
238         Sys_PrintfToTerminal("%p thread wait %s:%i\n"   , w, filename, fileline);
239 #endif
240         WaitForSingleObject(w->handle, INFINITE);
241         CloseHandle(w->handle);
242         retval = w->result;
243         free(w);
244         return retval;
245 }