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