1 /**********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 /* utility */
19 #include "log.h"
20 #include "mem.h"
21 #include "support.h"
22
23 #include "fcthread.h"
24
25 #ifdef FREECIV_HAVE_C11_THREADS
26
27 struct fc_thread_wrap_data {
28 void *arg;
29 void (*func)(void *arg);
30 };
31
32 /**********************************************************************
33 Wrapper which fingerprint matches one required by pthread_create().
34 Calls function which matches fingerprint required by fc_thread_start()
35 ***********************************************************************/
fc_thread_wrapper(void * arg)36 static int fc_thread_wrapper(void *arg)
37 {
38 struct fc_thread_wrap_data *data = (struct fc_thread_wrap_data *) arg;
39
40 data->func(data->arg);
41
42 free(data);
43
44 return EXIT_SUCCESS;
45 }
46
47 /**********************************************************************
48 Create new thread
49 ***********************************************************************/
fc_thread_start(fc_thread * thread,void (* function)(void * arg),void * arg)50 int fc_thread_start(fc_thread *thread, void (*function) (void *arg),
51 void *arg)
52 {
53 int ret;
54
55 /* Freed by child thread once it's finished with data */
56 struct fc_thread_wrap_data *data = fc_malloc(sizeof(*data));
57
58 data->arg = arg;
59 data->func = function;
60
61 ret = thrd_create(thread, &fc_thread_wrapper, data);
62
63 return ret != thrd_success;
64 }
65
66 /**********************************************************************
67 Wait for thread to finish
68 ***********************************************************************/
fc_thread_wait(fc_thread * thread)69 void fc_thread_wait(fc_thread *thread)
70 {
71 int *return_value = NULL;
72
73 thrd_join(*thread, return_value);
74 }
75
76 /**********************************************************************
77 Initialize mutex
78 ***********************************************************************/
fc_init_mutex(fc_mutex * mutex)79 void fc_init_mutex(fc_mutex *mutex)
80 {
81 mtx_init(mutex, mtx_plain|mtx_recursive);
82 }
83
84 /**********************************************************************
85 Destroy mutex
86 ***********************************************************************/
fc_destroy_mutex(fc_mutex * mutex)87 void fc_destroy_mutex(fc_mutex *mutex)
88 {
89 mtx_destroy(mutex);
90 }
91
92 /**********************************************************************
93 Lock mutex
94 ***********************************************************************/
fc_allocate_mutex(fc_mutex * mutex)95 void fc_allocate_mutex(fc_mutex *mutex)
96 {
97 mtx_lock(mutex);
98 }
99
100 /**********************************************************************
101 Release mutex
102 ***********************************************************************/
fc_release_mutex(fc_mutex * mutex)103 void fc_release_mutex(fc_mutex *mutex)
104 {
105 mtx_unlock(mutex);
106 }
107
108 /**********************************************************************
109 Initialize condition
110 ***********************************************************************/
fc_thread_cond_init(fc_thread_cond * cond)111 void fc_thread_cond_init(fc_thread_cond *cond)
112 {
113 cnd_init(cond);
114 }
115
116 /**********************************************************************
117 Destroy condition
118 ***********************************************************************/
fc_thread_cond_destroy(fc_thread_cond * cond)119 void fc_thread_cond_destroy(fc_thread_cond *cond)
120 {
121 cnd_destroy(cond);
122 }
123
124 /**********************************************************************
125 Wait for condition to be fulfilled
126 ***********************************************************************/
fc_thread_cond_wait(fc_thread_cond * cond,fc_mutex * mutex)127 void fc_thread_cond_wait(fc_thread_cond *cond, fc_mutex *mutex)
128 {
129 cnd_wait(cond, mutex);
130 }
131
132 /**********************************************************************
133 Signal other thread to continue on fulfilled condition
134 ***********************************************************************/
fc_thread_cond_signal(fc_thread_cond * cond)135 void fc_thread_cond_signal(fc_thread_cond *cond)
136 {
137 cnd_signal(cond);
138 }
139
140 #elif defined(FREECIV_HAVE_PTHREAD)
141
142 struct fc_thread_wrap_data {
143 void *arg;
144 void (*func)(void *arg);
145 };
146
147 /**********************************************************************
148 Wrapper which fingerprint matches one required by pthread_create().
149 Calls function which matches fingerprint required by fc_thread_start()
150 ***********************************************************************/
fc_thread_wrapper(void * arg)151 static void *fc_thread_wrapper(void *arg)
152 {
153 struct fc_thread_wrap_data *data = (struct fc_thread_wrap_data *) arg;
154
155 data->func(data->arg);
156
157 free(data);
158
159 return NULL;
160 }
161
162 /**********************************************************************
163 Create new thread
164 ***********************************************************************/
fc_thread_start(fc_thread * thread,void (* function)(void * arg),void * arg)165 int fc_thread_start(fc_thread *thread, void (*function) (void *arg),
166 void *arg)
167 {
168 int ret;
169 pthread_attr_t attr;
170
171 /* Freed by child thread once it's finished with data */
172 struct fc_thread_wrap_data *data = fc_malloc(sizeof(*data));
173
174 data->arg = arg;
175 data->func = function;
176
177 /* Explicitly set thread as joinable to maximize portability
178 between pthread implementations */
179 pthread_attr_init(&attr);
180 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
181
182 ret = pthread_create(thread, &attr, &fc_thread_wrapper, data);
183
184 pthread_attr_destroy(&attr);
185
186 return ret;
187 }
188
189 /**********************************************************************
190 Wait for thread to finish
191 ***********************************************************************/
fc_thread_wait(fc_thread * thread)192 void fc_thread_wait(fc_thread *thread)
193 {
194 void **return_value = NULL;
195
196 pthread_join(*thread, return_value);
197 }
198
199 /**********************************************************************
200 Initialize mutex
201 ***********************************************************************/
fc_init_mutex(fc_mutex * mutex)202 void fc_init_mutex(fc_mutex *mutex)
203 {
204 pthread_mutexattr_t attr;
205
206 pthread_mutexattr_init(&attr);
207 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
208
209 pthread_mutex_init(mutex, &attr);
210
211 pthread_mutexattr_destroy(&attr);
212 }
213
214 /**********************************************************************
215 Destroy mutex
216 ***********************************************************************/
fc_destroy_mutex(fc_mutex * mutex)217 void fc_destroy_mutex(fc_mutex *mutex)
218 {
219 pthread_mutex_destroy(mutex);
220 }
221
222 /**********************************************************************
223 Lock mutex
224 ***********************************************************************/
fc_allocate_mutex(fc_mutex * mutex)225 void fc_allocate_mutex(fc_mutex *mutex)
226 {
227 pthread_mutex_lock(mutex);
228 }
229
230 /**********************************************************************
231 Release mutex
232 ***********************************************************************/
fc_release_mutex(fc_mutex * mutex)233 void fc_release_mutex(fc_mutex *mutex)
234 {
235 pthread_mutex_unlock(mutex);
236 }
237
238 /**********************************************************************
239 Initialize condition
240 ***********************************************************************/
fc_thread_cond_init(fc_thread_cond * cond)241 void fc_thread_cond_init(fc_thread_cond *cond)
242 {
243 pthread_cond_init(cond, NULL);
244 }
245
246 /**********************************************************************
247 Destroy condition
248 ***********************************************************************/
fc_thread_cond_destroy(fc_thread_cond * cond)249 void fc_thread_cond_destroy(fc_thread_cond *cond)
250 {
251 pthread_cond_destroy(cond);
252 }
253
254 /**********************************************************************
255 Wait for condition to be fulfilled
256 ***********************************************************************/
fc_thread_cond_wait(fc_thread_cond * cond,fc_mutex * mutex)257 void fc_thread_cond_wait(fc_thread_cond *cond, fc_mutex *mutex)
258 {
259 pthread_cond_wait(cond, mutex);
260 }
261
262 /**********************************************************************
263 Signal other thread to continue on fulfilled condition
264 ***********************************************************************/
fc_thread_cond_signal(fc_thread_cond * cond)265 void fc_thread_cond_signal(fc_thread_cond *cond)
266 {
267 pthread_cond_signal(cond);
268 }
269
270 #elif defined(FREECIV_HAVE_WINTHREADS)
271
272 struct fc_thread_wrap_data {
273 void *arg;
274 void (*func)(void *arg);
275 };
276
277 /**********************************************************************
278 Wrapper which fingerprint matches one required by CreateThread().
279 Calls function which matches fingerprint required by fc_thread_start()
280 ***********************************************************************/
fc_thread_wrapper(LPVOID arg)281 static DWORD WINAPI fc_thread_wrapper(LPVOID arg)
282 {
283 struct fc_thread_wrap_data *data = (struct fc_thread_wrap_data *) arg;
284
285 data->func(data->arg);
286
287 free(data);
288
289 return 0;
290 }
291
292 /**********************************************************************
293 Create new thread
294 ***********************************************************************/
fc_thread_start(fc_thread * thread,void (* function)(void * arg),void * arg)295 int fc_thread_start(fc_thread *thread, void (*function) (void *arg), void *arg)
296 {
297 /* Freed by child thread once it's finished with data */
298 struct fc_thread_wrap_data *data = fc_malloc(sizeof(*data));
299
300 data->arg = arg;
301 data->func = function;
302
303 *thread = CreateThread(NULL, 0, &fc_thread_wrapper, data, 0, NULL);
304
305 if (*thread == NULL) {
306 return 1;
307 }
308
309 return 0;
310 }
311
312 /**********************************************************************
313 Wait for thread to finish
314 ***********************************************************************/
fc_thread_wait(fc_thread * thread)315 void fc_thread_wait(fc_thread *thread)
316 {
317 DWORD exit_code;
318
319 GetExitCodeThread(*thread, &exit_code);
320
321 while (exit_code == STILL_ACTIVE) {
322 fc_usleep(1000);
323 GetExitCodeThread(*thread, &exit_code);
324 }
325
326 CloseHandle(*thread);
327 }
328
329 /**********************************************************************
330 Initialize mutex
331 ***********************************************************************/
fc_init_mutex(fc_mutex * mutex)332 void fc_init_mutex(fc_mutex *mutex)
333 {
334 *mutex = CreateMutex(NULL, FALSE, NULL);
335 }
336
337 /**********************************************************************
338 Destroy mutex
339 ***********************************************************************/
fc_destroy_mutex(fc_mutex * mutex)340 void fc_destroy_mutex(fc_mutex *mutex)
341 {
342 CloseHandle(*mutex);
343 }
344
345 /**********************************************************************
346 Lock mutex
347 ***********************************************************************/
fc_allocate_mutex(fc_mutex * mutex)348 void fc_allocate_mutex(fc_mutex *mutex)
349 {
350 WaitForSingleObject(*mutex, INFINITE);
351 }
352
353 /**********************************************************************
354 Release mutex
355 ***********************************************************************/
fc_release_mutex(fc_mutex * mutex)356 void fc_release_mutex(fc_mutex *mutex)
357 {
358 ReleaseMutex(*mutex);
359 }
360
361 /* TODO: Windows thread condition variable support.
362 * Currently related functions are always dummy ones below
363 * (see #ifndef FREECIV_HAVE_THREAD_COND) */
364
365 #else /* No thread implementation */
366
367 #error "No working thread implementation"
368
369 #endif /* FREECIV_HAVE_PTHREAD || FREECIV_HAVE_WINTHREADS */
370
371
372 #ifndef FREECIV_HAVE_THREAD_COND
373
374 /* Dummy thread condition variable functions */
375
376 /**********************************************************************
377 Dummy fc_thread_cond_init()
378 ***********************************************************************/
fc_thread_cond_init(fc_thread_cond * cond)379 void fc_thread_cond_init(fc_thread_cond *cond)
380 {}
381
382 /**********************************************************************
383 Dummy fc_thread_cond_destroy()
384 ***********************************************************************/
fc_thread_cond_destroy(fc_thread_cond * cond)385 void fc_thread_cond_destroy(fc_thread_cond *cond)
386 {}
387
388 /**********************************************************************
389 Dummy fc_thread_cond_wait()
390 ***********************************************************************/
fc_thread_cond_wait(fc_thread_cond * cond,fc_mutex * mutex)391 void fc_thread_cond_wait(fc_thread_cond *cond, fc_mutex *mutex)
392 {}
393
394 /**********************************************************************
395 Dummy fc_thread_cond_signal()
396 ***********************************************************************/
fc_thread_cond_signal(fc_thread_cond * cond)397 void fc_thread_cond_signal(fc_thread_cond *cond)
398 {}
399
400 #endif /* !FREECIV_HAVE_THREAD_COND */
401
402 /**********************************************************************
403 Has freeciv thread condition variable implementation
404 ***********************************************************************/
has_thread_cond_impl(void)405 bool has_thread_cond_impl(void)
406 {
407 #ifdef FREECIV_HAVE_THREAD_COND
408 return TRUE;
409 #else
410 return FALSE;
411 #endif
412 }
413