1#include "mupdf/helpers/mu-threads.h"
2
3#ifdef DISABLE_MUTHREADS
4
5#include <stdlib.h>
6
7/* Null implementation. Just error out. */
8
9int mu_create_semaphore(mu_semaphore *sem)
10{
11 return 1; /* Just Error */
12}
13
14void mu_destroy_semaphore(mu_semaphore *sem)
15{
16}
17
18int mu_trigger_semaphore(mu_semaphore *sem)
19{
20 abort();
21 return 1;
22}
23
24int mu_wait_semaphore(mu_semaphore *sem)
25{
26 abort();
27 return 1;
28}
29
30int mu_create_thread(mu_thread *th, mu_thread_fn *fn, void *arg)
31{
32 return 1;
33}
34
35void mu_destroy_thread(mu_thread *th)
36{
37}
38
39int mu_create_mutex(mu_mutex *mutex)
40{
41 return 1;
42}
43
44void mu_destroy_mutex(mu_mutex *mutex)
45{
46}
47
48void mu_lock_mutex(mu_mutex *mutex)
49{
50 abort();
51}
52
53void mu_unlock_mutex(mu_mutex *mutex)
54{
55 abort();
56}
57
58#elif MU_THREAD_IMPL_TYPE == 1
59
60/* Windows threads */
61int mu_create_semaphore(mu_semaphore *sem)
62{
63 sem->handle = CreateSemaphore(NULL, 0, 1, NULL);
64 return (sem->handle == NULL);
65}
66
67void mu_destroy_semaphore(mu_semaphore *sem)
68{
69 if (sem->handle == NULL)
70 return;
71 /* We can't sensibly handle this failing */
72 (void)CloseHandle(sem->handle);
73}
74
75int mu_trigger_semaphore(mu_semaphore *sem)
76{
77 if (sem->handle == NULL)
78 return 0;
79 /* We can't sensibly handle this failing */
80 return !ReleaseSemaphore(sem->handle, 1, NULL);
81}
82
83int mu_wait_semaphore(mu_semaphore *sem)
84{
85 if (sem->handle == NULL)
86 return 0;
87 /* We can't sensibly handle this failing */
88 return !WaitForSingleObject(sem->handle, INFINITE);
89}
90
91static DWORD WINAPI thread_starter(LPVOID arg)
92{
93 mu_thread *th = (mu_thread *)arg;
94
95 th->fn(th->arg);
96
97 return 0;
98}
99
100int mu_create_thread(mu_thread *th, mu_thread_fn *fn, void *arg)
101{
102 th->fn = fn;
103 th->arg = arg;
104 th->handle = CreateThread(NULL, 0, thread_starter, th, 0, NULL);
105
106 return (th->handle == NULL);
107}
108
109void mu_destroy_thread(mu_thread *th)
110{
111 if (th->handle == NULL)
112 return;
113 /* We can't sensibly handle this failing */
114 (void)WaitForSingleObject(th->handle, INFINITE);
115 (void)CloseHandle(th->handle);
116 th->handle = NULL;
117}
118
119int mu_create_mutex(mu_mutex *mutex)
120{
121 InitializeCriticalSection(&mutex->mutex);
122 return 0; /* Magic function, never fails */
123}
124
125void mu_destroy_mutex(mu_mutex *mutex)
126{
127 const static CRITICAL_SECTION empty = { 0 };
128 if (memcmp(&mutex->mutex, &empty, sizeof(empty)) == 0)
129 return;
130 DeleteCriticalSection(&mutex->mutex);
131 mutex->mutex = empty;
132}
133
134void mu_lock_mutex(mu_mutex *mutex)
135{
136 EnterCriticalSection(&mutex->mutex);
137}
138
139void mu_unlock_mutex(mu_mutex *mutex)
140{
141 LeaveCriticalSection(&mutex->mutex);
142}
143
144#elif MU_THREAD_IMPL_TYPE == 2
145
146/*
147 PThreads - without working unnamed semaphores.
148
149 Neither ios nor OSX supports unnamed semaphores.
150 Named semaphores are a pain to use, so we implement
151 our own sempahores using condition variables and
152 mutexes.
153*/
154
155#include <string.h>
156
157struct mu_sempahore
158{
159 int count;
160 pthread_mutex_t mutex;
161 pthread_cond_t cond;
162};
163
164int
165mu_create_semaphore(mu_semaphore *sem)
166{
167 int scode;
168
169 sem->count = 0;
170 scode = pthread_mutex_init(&sem->mutex, NULL);
171 if (scode == 0)
172 {
173 scode = pthread_cond_init(&sem->cond, NULL);
174 if (scode)
175 pthread_mutex_destroy(&sem->mutex);
176 }
177 if (scode)
178 memset(sem, 0, sizeof(*sem));
179 return scode;
180}
181
182void
183mu_destroy_semaphore(mu_semaphore *sem)
184{
185 const static mu_semaphore empty = { 0 };
186
187 if (memcmp(sem, &empty, sizeof(empty)) == 0)
188 return;
189 (void)pthread_cond_destroy(&sem->cond);
190 (void)pthread_mutex_destroy(&sem->mutex);
191 *sem = empty;
192}
193
194int
195mu_wait_semaphore(mu_semaphore *sem)
196{
197 int scode, scode2;
198
199 scode = pthread_mutex_lock(&sem->mutex);
200 if (scode)
201 return scode;
202 while (sem->count == 0) {
203 scode = pthread_cond_wait(&sem->cond, &sem->mutex);
204 if (scode)
205 break;
206 }
207 if (scode == 0)
208 --sem->count;
209 scode2 = pthread_mutex_unlock(&sem->mutex);
210 if (scode == 0)
211 scode = scode2;
212 return scode;
213}
214
215int
216mu_trigger_semaphore(mu_semaphore * sem)
217{
218 int scode, scode2;
219
220 scode = pthread_mutex_lock(&sem->mutex);
221 if (scode)
222 return scode;
223 if (sem->count++ == 0)
224 scode = pthread_cond_signal(&sem->cond);
225 scode2 = pthread_mutex_unlock(&sem->mutex);
226 if (scode == 0)
227 scode = scode2;
228 return scode;
229}
230
231static void *thread_starter(void *arg)
232{
233 mu_thread *th = (mu_thread *)arg;
234
235 th->fn(th->arg);
236
237 return NULL;
238}
239
240int mu_create_thread(mu_thread *th, mu_thread_fn *fn, void *arg)
241{
242 th->fn = fn;
243 th->arg = arg;
244 return pthread_create(&th->thread, NULL, thread_starter, th);
245}
246
247void mu_destroy_thread(mu_thread *th)
248{
249 const static mu_thread empty; /* static objects are always initialized to zero */
250
251 if (memcmp(th, &empty, sizeof(empty)) == 0)
252 return;
253
254 (void)pthread_join(th->thread, NULL);
255 *th = empty;
256}
257
258int mu_create_mutex(mu_mutex *mutex)
259{
260 return pthread_mutex_init(&mutex->mutex, NULL);
261}
262
263void mu_destroy_mutex(mu_mutex *mutex)
264{
265 const static mu_mutex empty; /* static objects are always initialized to zero */
266
267 if (memcmp(mutex, &empty, sizeof(empty)) == 0)
268 return;
269
270 (void)pthread_mutex_destroy(&mutex->mutex);
271 *mutex = empty;
272}
273
274void mu_lock_mutex(mu_mutex *mutex)
275{
276 (void)pthread_mutex_lock(&mutex->mutex);
277}
278
279void mu_unlock_mutex(mu_mutex *mutex)
280{
281 (void)pthread_mutex_unlock(&mutex->mutex);
282}
283
284#else
285#error Unknown MU_THREAD_IMPL_TYPE setting
286#endif
287