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 | |
9 | int mu_create_semaphore(mu_semaphore *sem) |
10 | { |
11 | return 1; /* Just Error */ |
12 | } |
13 | |
14 | void mu_destroy_semaphore(mu_semaphore *sem) |
15 | { |
16 | } |
17 | |
18 | int mu_trigger_semaphore(mu_semaphore *sem) |
19 | { |
20 | abort(); |
21 | return 1; |
22 | } |
23 | |
24 | int mu_wait_semaphore(mu_semaphore *sem) |
25 | { |
26 | abort(); |
27 | return 1; |
28 | } |
29 | |
30 | int mu_create_thread(mu_thread *th, mu_thread_fn *fn, void *arg) |
31 | { |
32 | return 1; |
33 | } |
34 | |
35 | void mu_destroy_thread(mu_thread *th) |
36 | { |
37 | } |
38 | |
39 | int mu_create_mutex(mu_mutex *mutex) |
40 | { |
41 | return 1; |
42 | } |
43 | |
44 | void mu_destroy_mutex(mu_mutex *mutex) |
45 | { |
46 | } |
47 | |
48 | void mu_lock_mutex(mu_mutex *mutex) |
49 | { |
50 | abort(); |
51 | } |
52 | |
53 | void mu_unlock_mutex(mu_mutex *mutex) |
54 | { |
55 | abort(); |
56 | } |
57 | |
58 | #elif MU_THREAD_IMPL_TYPE == 1 |
59 | |
60 | /* Windows threads */ |
61 | int mu_create_semaphore(mu_semaphore *sem) |
62 | { |
63 | sem->handle = CreateSemaphore(NULL, 0, 1, NULL); |
64 | return (sem->handle == NULL); |
65 | } |
66 | |
67 | void 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 | |
75 | int 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 | |
83 | int 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 | |
91 | static 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 | |
100 | int 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 | |
109 | void 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 | |
119 | int mu_create_mutex(mu_mutex *mutex) |
120 | { |
121 | InitializeCriticalSection(&mutex->mutex); |
122 | return 0; /* Magic function, never fails */ |
123 | } |
124 | |
125 | void 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 | |
134 | void mu_lock_mutex(mu_mutex *mutex) |
135 | { |
136 | EnterCriticalSection(&mutex->mutex); |
137 | } |
138 | |
139 | void 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 | |
157 | struct mu_sempahore |
158 | { |
159 | int count; |
160 | pthread_mutex_t mutex; |
161 | pthread_cond_t cond; |
162 | }; |
163 | |
164 | int |
165 | mu_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 | |
182 | void |
183 | mu_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 | |
194 | int |
195 | mu_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 | |
215 | int |
216 | mu_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 | |
231 | static 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 | |
240 | int 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 | |
247 | void 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 | |
258 | int mu_create_mutex(mu_mutex *mutex) |
259 | { |
260 | return pthread_mutex_init(&mutex->mutex, NULL); |
261 | } |
262 | |
263 | void 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 | |
274 | void mu_lock_mutex(mu_mutex *mutex) |
275 | { |
276 | (void)pthread_mutex_lock(&mutex->mutex); |
277 | } |
278 | |
279 | void 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 | |