WGL client can now use DPSOFTRAST, added thread_win.c to avoid SDL dependency for...
[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(void)
20 {
21         return (void *)CreateMutex(NULL, FALSE, NULL);
22 }
23
24 void Thread_DestroyMutex(void *mutex)
25 {
26         CloseHandle(mutex);
27 }
28
29 int Thread_LockMutex(void *mutex)
30 {
31         return (WaitForSingleObject(mutex, INFINITE) == WAIT_FAILED) ? -1 : 0;
32 }
33
34 int Thread_UnlockMutex(void *mutex)
35 {
36         return (ReleaseMutex(mutex) == FALSE) ? -1 : 0;
37 }
38
39 typedef struct thread_semaphore_s
40 {
41         HANDLE semaphore;
42         volatile LONG value;
43 }
44 thread_semaphore_t;
45
46 static thread_semaphore_t *Thread_CreateSemaphore(unsigned int v)
47 {
48         thread_semaphore_t *s = (thread_semaphore_t *)calloc(sizeof(*s), 1);
49         s->semaphore = CreateSemaphore(NULL, v, 32768, NULL);
50         s->value = v;
51         return s;
52 }
53
54 static void Thread_DestroySemaphore(thread_semaphore_t *s)
55 {
56         CloseHandle(s->semaphore);
57         free(s);
58 }
59
60 static int Thread_WaitSemaphore(thread_semaphore_t *s, unsigned int msec)
61 {
62         int r = WaitForSingleObject(s->semaphore, msec);
63         if (r == WAIT_OBJECT_0)
64         {
65                 InterlockedDecrement(&s->value);
66                 return 0;
67         }
68         if (r == WAIT_TIMEOUT)
69                 return 1;
70         return -1;
71 }
72
73 static int Thread_PostSemaphore(thread_semaphore_t *s)
74 {
75         InterlockedIncrement(&s->value);
76         if (ReleaseSemaphore(s->semaphore, 1, NULL))
77                 return 0;
78         InterlockedDecrement(&s->value);
79         return -1;
80 }
81
82 typedef struct thread_cond_s
83 {
84         HANDLE mutex;
85         int waiting;
86         int signals;
87         thread_semaphore_t *sem;
88         thread_semaphore_t *done;
89 }
90 thread_cond_t;
91
92 void *Thread_CreateCond(void)
93 {
94         thread_cond_t *c = (thread_cond_t *)calloc(sizeof(*c), 1);
95         c->mutex = CreateMutex(NULL, FALSE, NULL);
96         c->sem = Thread_CreateSemaphore(0);
97         c->done = Thread_CreateSemaphore(0);
98         c->waiting = 0;
99         c->signals = 0;
100         return c;
101 }
102
103 void Thread_DestroyCond(void *cond)
104 {
105         thread_cond_t *c = (thread_cond_t *)cond;
106         Thread_DestroySemaphore(c->sem);
107         Thread_DestroySemaphore(c->done);
108         CloseHandle(c->mutex);
109 }
110
111 int Thread_CondSignal(void *cond)
112 {
113         thread_cond_t *c = (thread_cond_t *)cond;
114         int n;
115         WaitForSingleObject(c->mutex, INFINITE);
116         n = c->waiting - c->signals;
117         if (n > 0)
118         {
119                 c->signals++;
120                 Thread_PostSemaphore(c->sem);
121         }
122         ReleaseMutex(c->mutex);
123         if (n > 0)
124                 Thread_WaitSemaphore(c->done, INFINITE);
125         return 0;
126 }
127
128 int Thread_CondBroadcast(void *cond)
129 {
130         thread_cond_t *c = (thread_cond_t *)cond;
131         int i = 0;
132         int n = 0;
133         WaitForSingleObject(c->mutex, INFINITE);
134         n = c->waiting - c->signals;
135         if (n > 0)
136         {
137                 c->signals += n;
138                 for (i = 0;i < n;i++)
139                         Thread_PostSemaphore(c->sem);
140         }
141         ReleaseMutex(c->mutex);
142         for (i = 0;i < n;i++)
143                 Thread_WaitSemaphore(c->done, INFINITE);
144         return 0;
145 }
146
147 int Thread_CondWait(void *cond, void *mutex)
148 {
149         thread_cond_t *c = (thread_cond_t *)cond;
150         int waitresult;
151
152         WaitForSingleObject(c->mutex, INFINITE);
153         c->waiting++;
154         ReleaseMutex(c->mutex);
155
156         ReleaseMutex(mutex);
157
158         waitresult = Thread_WaitSemaphore(c->sem, INFINITE);
159         WaitForSingleObject(c->mutex, INFINITE);
160         if (c->signals > 0)
161         {
162                 if (waitresult > 0)
163                         Thread_WaitSemaphore(c->sem, INFINITE);
164                 Thread_PostSemaphore(c->done);
165                 c->signals--;
166         }
167         c->waiting--;
168         ReleaseMutex(c->mutex);
169
170         WaitForSingleObject(mutex, INFINITE);
171         return waitresult;
172 }
173
174 typedef struct threadwrapper_s
175 {
176         HANDLE handle;
177         unsigned int threadid;
178         int result;
179         int (*fn)(void *);
180         void *data;
181 }
182 threadwrapper_t;
183
184 unsigned int __stdcall Thread_WrapperFunc(void *d)
185 {
186         threadwrapper_t *w = (threadwrapper_t *)d;
187         w->result = w->fn(w->data);
188         _endthreadex(w->result);
189         return w->result;
190 }
191
192 void *Thread_CreateThread(int (*fn)(void *), void *data)
193 {
194         threadwrapper_t *w = (threadwrapper_t *)calloc(sizeof(*w), 1);
195         w->fn = fn;
196         w->data = data;
197         w->threadid = 0;
198         w->result = 0;
199         w->handle = (HANDLE)_beginthreadex(NULL, 0, Thread_WrapperFunc, (void *)w, 0, &w->threadid);
200         return (void *)w;
201 }
202
203 int Thread_WaitThread(void *d, int retval)
204 {
205         threadwrapper_t *w = (threadwrapper_t *)d;
206         WaitForSingleObject(w->handle, INFINITE);
207         CloseHandle(w->handle);
208         retval = w->result;
209         free(w);
210         return retval;
211 }