1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | #ifndef _GDK_SYSTEM_H_ |
10 | #define _GDK_SYSTEM_H_ |
11 | |
12 | #ifdef WIN32 |
13 | #ifndef LIBGDK |
14 | #define gdk_export extern __declspec(dllimport) |
15 | #else |
16 | #define gdk_export extern __declspec(dllexport) |
17 | #endif |
18 | #else |
19 | #define gdk_export extern |
20 | #endif |
21 | |
22 | /* if __has_attribute is not known to the preprocessor, we ignore |
23 | * attributes completely; if it is known, use it to find out whether |
24 | * specific attributes that we use are known */ |
25 | #ifndef __has_attribute |
26 | #ifndef __GNUC__ |
27 | #define __has_attribute(attr) 0 |
28 | #ifndef __attribute__ |
29 | #define __attribute__(attr) /* empty */ |
30 | #endif |
31 | #else |
32 | /* older GCC does have attributes, but not __has_attribute and not all |
33 | * attributes that we use are known */ |
34 | #define __has_attribute__alloc_size__ 1 |
35 | #define __has_attribute__cold__ 1 |
36 | #define __has_attribute__format__ 1 |
37 | #define __has_attribute__malloc__ 1 |
38 | #define __has_attribute__noreturn__ 1 |
39 | #define __has_attribute__returns_nonnull__ 0 |
40 | #define __has_attribute__visibility__ 1 |
41 | #define __has_attribute__warn_unused_result__ 1 |
42 | #define __has_attribute(attr) __has_attribute##attr |
43 | #endif |
44 | #endif |
45 | #if !__has_attribute(__warn_unused_result__) |
46 | #define __warn_unused_result__ |
47 | #endif |
48 | #if !__has_attribute(__malloc__) |
49 | #define __malloc__ |
50 | #endif |
51 | #if !__has_attribute(__alloc_size__) |
52 | #define __alloc_size__(a) |
53 | #endif |
54 | #if !__has_attribute(__format__) |
55 | #define __format__(a,b,c) |
56 | #endif |
57 | #if !__has_attribute(__noreturn__) |
58 | #define __noreturn__ |
59 | #endif |
60 | /* these are used in some *private.h files */ |
61 | #if !__has_attribute(__visibility__) |
62 | #define __visibility__(a) |
63 | #elif defined(__CYGWIN__) |
64 | #define __visibility__(a) |
65 | #endif |
66 | #if !__has_attribute(__cold__) |
67 | #define __cold__ |
68 | #endif |
69 | |
70 | /* also see gdk.h for these */ |
71 | #define THRDMASK (1) |
72 | #define THRDDEBUG if (GDKdebug & THRDMASK) |
73 | #define TEMMASK (1<<10) |
74 | #define TEMDEBUG if (GDKdebug & TEMMASK) |
75 | |
76 | /* |
77 | * @- pthreads Includes and Definitions |
78 | */ |
79 | #ifdef HAVE_PTHREAD_H |
80 | /* don't re-include config.h; on Windows, don't redefine pid_t in an |
81 | * incompatible way */ |
82 | #undef HAVE_CONFIG_H |
83 | #ifdef pid_t |
84 | #undef pid_t |
85 | #endif |
86 | #include <sched.h> |
87 | #include <pthread.h> |
88 | #endif |
89 | |
90 | #ifdef HAVE_SEMAPHORE_H |
91 | # include <semaphore.h> |
92 | #endif |
93 | |
94 | #ifdef HAVE_DISPATCH_DISPATCH_H |
95 | #include <dispatch/dispatch.h> |
96 | #endif |
97 | |
98 | #ifdef HAVE_SYS_PARAM_H |
99 | # include <sys/param.h> /* prerequisite of sys/sysctl on OpenBSD */ |
100 | #endif |
101 | #ifdef BSD /* BSD macro is defined in sys/param.h */ |
102 | # include <sys/sysctl.h> |
103 | #endif |
104 | |
105 | /* new pthread interface, where the thread id changed to a struct */ |
106 | #ifdef PTW32_VERSION |
107 | #define PTW32 1 |
108 | #endif |
109 | |
110 | /* debug and errno integers */ |
111 | gdk_export int GDKdebug; |
112 | gdk_export void GDKsetdebug(int debug); |
113 | gdk_export int GDKverbose; |
114 | gdk_export void GDKsetverbose(int verbosity); |
115 | |
116 | gdk_export int GDKnr_threads; |
117 | |
118 | /* API */ |
119 | |
120 | /* |
121 | * @- sleep |
122 | */ |
123 | |
124 | gdk_export void MT_sleep_ms(unsigned int ms); |
125 | |
126 | /* |
127 | * @- MT Thread Api |
128 | */ |
129 | typedef size_t MT_Id; /* thread number. will not be zero */ |
130 | |
131 | enum MT_thr_detach { MT_THR_JOINABLE, MT_THR_DETACHED }; |
132 | |
133 | gdk_export bool MT_thread_init(void); |
134 | gdk_export int MT_create_thread(MT_Id *t, void (*function) (void *), |
135 | void *arg, enum MT_thr_detach d, |
136 | const char *threadname); |
137 | gdk_export const char *MT_thread_getname(void); |
138 | gdk_export void *MT_thread_getdata(void); |
139 | gdk_export void MT_thread_setdata(void *data); |
140 | gdk_export void MT_exiting_thread(void); |
141 | gdk_export MT_Id MT_getpid(void); |
142 | gdk_export int MT_join_thread(MT_Id t); |
143 | |
144 | #if SIZEOF_VOID_P == 4 |
145 | /* "limited" stack size on 32-bit systems */ |
146 | /* to avoid address space fragmentation */ |
147 | #define THREAD_STACK_SIZE ((size_t)1024*1024) |
148 | #else |
149 | /* "increased" stack size on 64-bit systems */ |
150 | /* since some compilers seem to require this */ |
151 | /* for burg-generated code in pathfinder */ |
152 | /* and address space fragmentation is no issue */ |
153 | #define THREAD_STACK_SIZE ((size_t)2*1024*1024) |
154 | #endif |
155 | |
156 | |
157 | /* |
158 | * @- MT Lock API |
159 | */ |
160 | #include "matomic.h" |
161 | |
162 | /* define this to keep lock statistics (can be expensive) */ |
163 | /* #define LOCK_STATS */ |
164 | |
165 | /* define this if you want to use pthread (or Windows) locks instead |
166 | * of atomic instructions for locking (latching) */ |
167 | #ifndef WIN32 |
168 | /* on Linux (and in general pthread using systems) use native locks; |
169 | * on Windows use locks based on atomic instructions and sleeps since |
170 | * the Windows lock implementations (Mutex and CriticalSection) are |
171 | * too heavy and impossible to initialize statically */ |
172 | #define USE_NATIVE_LOCKS 1 |
173 | #endif |
174 | |
175 | #ifdef LOCK_STATS |
176 | |
177 | #define _DBG_LOCK_COUNT_0(l) \ |
178 | do { \ |
179 | (void) ATOMIC_INC(&GDKlockcnt); \ |
180 | TEMDEBUG fprintf(stderr, "#%s: %s: locking %s...\n", \ |
181 | MT_thread_getname(), __func__, (l)->name); \ |
182 | } while (0) |
183 | |
184 | #define _DBG_LOCK_LOCKER(l) \ |
185 | do { \ |
186 | (l)->locker = __func__; \ |
187 | (l)->thread = MT_thread_getname(); \ |
188 | } while (0) |
189 | |
190 | #define _DBG_LOCK_UNLOCKER(l) \ |
191 | do { \ |
192 | (l)->locker = __func__; \ |
193 | (l)->thread = NULL; \ |
194 | TEMDEBUG fprintf(stderr, "#%s: %s: unlocking %s\n", \ |
195 | MT_thread_getname(), __func__, (l)->name); \ |
196 | } while (0) |
197 | |
198 | #define _DBG_LOCK_CONTENTION(l) \ |
199 | do { \ |
200 | TEMDEBUG fprintf(stderr, "#%s: %s: lock %s contention\n", \ |
201 | MT_thread_getname(), __func__, (l)->name); \ |
202 | (void) ATOMIC_INC(&GDKlockcontentioncnt); \ |
203 | (void) ATOMIC_INC(&(l)->contention); \ |
204 | } while (0) |
205 | |
206 | #define _DBG_LOCK_SLEEP(l) ((void) ATOMIC_INC(&(l)->sleep)) |
207 | |
208 | #define _DBG_LOCK_COUNT_2(l) \ |
209 | do { \ |
210 | (l)->count++; \ |
211 | if ((l)->next == (struct MT_Lock *) -1) { \ |
212 | while (ATOMIC_TAS(&GDKlocklistlock) != 0) \ |
213 | ; \ |
214 | (l)->next = GDKlocklist; \ |
215 | GDKlocklist = (l); \ |
216 | ATOMIC_CLEAR(&GDKlocklistlock); \ |
217 | } \ |
218 | TEMDEBUG fprintf(stderr, "#%s: %s: locking %s complete\n", \ |
219 | MT_thread_getname(), __func__, (l)->name); \ |
220 | } while (0) |
221 | |
222 | #define _DBG_LOCK_INIT(l) \ |
223 | do { \ |
224 | (l)->count = 0; \ |
225 | ATOMIC_INIT(&(l)->contention, 0); \ |
226 | ATOMIC_INIT(&(l)->sleep, 0); \ |
227 | (l)->locker = NULL; \ |
228 | (l)->thread = NULL; \ |
229 | /* if name starts with "sa_" don't link in GDKlocklist */ \ |
230 | /* since the lock is in memory that is governed by the */ \ |
231 | /* SQL storage allocator, and hence we have no control */ \ |
232 | /* over when the lock is destroyed and the memory freed */ \ |
233 | if (strncmp((l)->name, "sa_", 3) != 0) { \ |
234 | MT_Lock * volatile _p; \ |
235 | while (ATOMIC_TAS(&GDKlocklistlock) != 0) \ |
236 | ; \ |
237 | for (_p = GDKlocklist; _p; _p = _p->next) \ |
238 | assert(_p != (l)); \ |
239 | (l)->next = GDKlocklist; \ |
240 | GDKlocklist = (l); \ |
241 | ATOMIC_CLEAR(&GDKlocklistlock); \ |
242 | } else { \ |
243 | (l)->next = NULL; \ |
244 | } \ |
245 | } while (0) |
246 | |
247 | #define _DBG_LOCK_DESTROY(l) \ |
248 | do { \ |
249 | /* if name starts with "sa_" don't link in GDKlocklist */ \ |
250 | /* since the lock is in memory that is governed by the */ \ |
251 | /* SQL storage allocator, and hence we have no control */ \ |
252 | /* over when the lock is destroyed and the memory freed */ \ |
253 | if (strncmp((l)->name, "sa_", 3) != 0) { \ |
254 | MT_Lock * volatile *_p; \ |
255 | while (ATOMIC_TAS(&GDKlocklistlock) != 0) \ |
256 | ; \ |
257 | for (_p = &GDKlocklist; *_p; _p = &(*_p)->next) \ |
258 | if ((l) == *_p) { \ |
259 | *_p = (l)->next; \ |
260 | break; \ |
261 | } \ |
262 | ATOMIC_CLEAR(&GDKlocklistlock); \ |
263 | ATOMIC_DESTROY(&(l)->contention); \ |
264 | ATOMIC_DESTROY(&(l)->sleep); \ |
265 | } \ |
266 | } while (0) |
267 | |
268 | #else |
269 | |
270 | #define _DBG_LOCK_COUNT_0(l) ((void) 0) |
271 | #define _DBG_LOCK_CONTENTION(l) ((void) 0) |
272 | #define _DBG_LOCK_SLEEP(l) ((void) 0) |
273 | #define _DBG_LOCK_COUNT_2(l) ((void) 0) |
274 | #define _DBG_LOCK_INIT(l) ((void) 0) |
275 | #define _DBG_LOCK_DESTROY(l) ((void) 0) |
276 | #define _DBG_LOCK_LOCKER(l) ((void) 0) |
277 | #define _DBG_LOCK_UNLOCKER(l) ((void) 0) |
278 | |
279 | #endif |
280 | |
281 | #ifdef USE_NATIVE_LOCKS |
282 | |
283 | #if !defined(HAVE_PTHREAD_H) && defined(WIN32) |
284 | typedef struct MT_Lock { |
285 | HANDLE lock; |
286 | char name[16]; |
287 | #ifdef LOCK_STATS |
288 | size_t count; |
289 | ATOMIC_TYPE contention; |
290 | ATOMIC_TYPE sleep; |
291 | struct MT_Lock * volatile next; |
292 | const char *locker; |
293 | const char *thread; |
294 | #endif |
295 | } MT_Lock; |
296 | |
297 | #ifdef LOCK_STATS |
298 | #define MT_LOCK_INITIALIZER(n) { .lock = NULL, .name = n, .next = (struct MT_Lock *) -1, } |
299 | #else |
300 | #define MT_LOCK_INITIALIZER(n) { .lock = NULL, .name = n, } |
301 | #endif |
302 | |
303 | #pragma intrinsic(_InterlockedCompareExchangePointer) |
304 | |
305 | #define MT_lock_init(l, n) \ |
306 | do { \ |
307 | assert((l)->lock == NULL); \ |
308 | (l)->lock = CreateMutex(NULL, 0, NULL); \ |
309 | strcpy_len((l)->name, (n), sizeof((l)->name)); \ |
310 | _DBG_LOCK_INIT(l); \ |
311 | } while (0) |
312 | |
313 | static bool inline |
314 | MT_lock_try(MT_Lock *l) |
315 | { |
316 | if (l->lock == NULL) { |
317 | HANDLE p = CreateMutex(NULL, 0, NULL); |
318 | if (_InterlockedCompareExchangePointer( |
319 | &l->lock, p, NULL) != NULL) |
320 | CloseHandle(p); |
321 | } |
322 | return WaitForSingleObject(l->lock, 0) == WAIT_OBJECT_0; |
323 | } |
324 | |
325 | #define MT_lock_set(l) \ |
326 | do { \ |
327 | _DBG_LOCK_COUNT_0(l); \ |
328 | if (!MT_lock_try(l)) { \ |
329 | _DBG_LOCK_CONTENTION(l); \ |
330 | MT_thread_setlockwait(l); \ |
331 | do \ |
332 | _DBG_LOCK_SLEEP(l); \ |
333 | while (WaitForSingleObject( \ |
334 | (l)->lock, INFINITE) != WAIT_OBJECT_0); \ |
335 | MT_thread_setlockwait(NULL); \ |
336 | } \ |
337 | _DBG_LOCK_LOCKER(l); \ |
338 | _DBG_LOCK_COUNT_2(l); \ |
339 | } while (0) |
340 | |
341 | #define MT_lock_unset(l) \ |
342 | do { \ |
343 | assert((l)->lock); \ |
344 | _DBG_LOCK_UNLOCKER(l); \ |
345 | ReleaseMutex((l)->lock); \ |
346 | } while (0) |
347 | |
348 | #define MT_lock_destroy(l) \ |
349 | do { \ |
350 | assert((l)->lock); \ |
351 | _DBG_LOCK_DESTROY(l); \ |
352 | CloseHandle((l)->lock); \ |
353 | (l)->lock = NULL; \ |
354 | } while (0) |
355 | |
356 | #else |
357 | |
358 | typedef struct MT_Lock { |
359 | pthread_mutex_t lock; |
360 | char name[16]; |
361 | #ifdef LOCK_STATS |
362 | size_t count; |
363 | ATOMIC_TYPE contention; |
364 | ATOMIC_TYPE sleep; |
365 | struct MT_Lock * volatile next; |
366 | const char *locker; |
367 | const char *thread; |
368 | #endif |
369 | } MT_Lock; |
370 | |
371 | #ifdef LOCK_STATS |
372 | #define MT_LOCK_INITIALIZER(n) { .lock = PTHREAD_MUTEX_INITIALIZER, .name = n, .next = (struct MT_Lock *) -1, } |
373 | #else |
374 | #define MT_LOCK_INITIALIZER(n) { .lock = PTHREAD_MUTEX_INITIALIZER, .name = n, } |
375 | #endif |
376 | |
377 | #define MT_lock_init(l, n) \ |
378 | do { \ |
379 | pthread_mutex_init(&(l)->lock, 0); \ |
380 | strcpy_len((l)->name, (n), sizeof((l)->name)); \ |
381 | _DBG_LOCK_INIT(l); \ |
382 | } while (0) |
383 | |
384 | #define MT_lock_try(l) (pthread_mutex_trylock(&(l)->lock) == 0) |
385 | |
386 | #ifdef LOCK_STATS |
387 | #define MT_lock_set(l) \ |
388 | do { \ |
389 | _DBG_LOCK_COUNT_0(l); \ |
390 | if (!MT_lock_try(l)) { \ |
391 | _DBG_LOCK_CONTENTION(l); \ |
392 | MT_thread_setlockwait(l); \ |
393 | do \ |
394 | _DBG_LOCK_SLEEP(l); \ |
395 | while (pthread_mutex_lock(&(l)->lock) != 0); \ |
396 | MT_thread_setlockwait(NULL); \ |
397 | } \ |
398 | _DBG_LOCK_LOCKER(l); \ |
399 | _DBG_LOCK_COUNT_2(l); \ |
400 | } while (0) |
401 | #else |
402 | #define MT_lock_set(l) pthread_mutex_lock(&(l)->lock) |
403 | #endif |
404 | |
405 | #define MT_lock_unset(l) \ |
406 | do { \ |
407 | _DBG_LOCK_UNLOCKER(l); \ |
408 | pthread_mutex_unlock(&(l)->lock); \ |
409 | } while (0) |
410 | |
411 | #define MT_lock_destroy(l) \ |
412 | do { \ |
413 | _DBG_LOCK_DESTROY(l); \ |
414 | pthread_mutex_destroy(&(l)->lock); \ |
415 | } while (0) |
416 | |
417 | #endif |
418 | |
419 | #else |
420 | |
421 | /* if LOCK_STATS is set, we maintain a bunch of counters and maintain |
422 | * a linked list of active locks */ |
423 | typedef struct MT_Lock { |
424 | ATOMIC_FLAG lock; |
425 | char name[16]; |
426 | #ifdef LOCK_STATS |
427 | size_t count; |
428 | ATOMIC_TYPE contention; |
429 | ATOMIC_TYPE sleep; |
430 | struct MT_Lock * volatile next; |
431 | const char *locker; |
432 | const char *thread; |
433 | #endif |
434 | } MT_Lock; |
435 | |
436 | #ifdef LOCK_STATS |
437 | #define MT_LOCK_INITIALIZER(n) { .next = (struct MT_Lock *) -1, .name = n, } |
438 | #else |
439 | #define MT_LOCK_INITIALIZER(n) { .name = n, } |
440 | #endif |
441 | |
442 | #define MT_lock_try(l) (ATOMIC_TAS(&(l)->lock) == 0) |
443 | |
444 | #define MT_lock_set(l) \ |
445 | do { \ |
446 | _DBG_LOCK_COUNT_0(l); \ |
447 | if (!MT_lock_try(l)) { \ |
448 | /* we didn't get the lock */ \ |
449 | unsigned _spincnt = 0; \ |
450 | _DBG_LOCK_CONTENTION(l); \ |
451 | MT_thread_setlockwait(l); \ |
452 | do { \ |
453 | if ((++_spincnt & 2047) == 0) { \ |
454 | _DBG_LOCK_SLEEP(l); \ |
455 | MT_sleep_ms(1); \ |
456 | } \ |
457 | } while (!MT_lock_try(l)); \ |
458 | MT_thread_setlockwait(NULL); \ |
459 | } \ |
460 | _DBG_LOCK_LOCKER(l); \ |
461 | _DBG_LOCK_COUNT_2(l); \ |
462 | } while (0) |
463 | |
464 | #define MT_lock_init(l, n) \ |
465 | do { \ |
466 | size_t nlen; \ |
467 | ATOMIC_CLEAR(&(l)->lock); \ |
468 | nlen = strlen(n); \ |
469 | if (nlen >= sizeof((l)->name)) \ |
470 | nlen = sizeof((l)->name) - 1; \ |
471 | memcpy((l)->name, (n), nlen + 1); \ |
472 | (l)->name[sizeof((l)->name) - 1] = 0; \ |
473 | _DBG_LOCK_INIT(l); \ |
474 | } while (0) |
475 | |
476 | #define MT_lock_unset(l) \ |
477 | do { \ |
478 | /* lock should be locked */ \ |
479 | assert(ATOMIC_TAS(&(l)->lock) != 0); \ |
480 | _DBG_LOCK_UNLOCKER(l); \ |
481 | ATOMIC_CLEAR(&(l)->lock); \ |
482 | } while (0) |
483 | |
484 | #define MT_lock_destroy(l) _DBG_LOCK_DESTROY(l) |
485 | |
486 | #endif |
487 | |
488 | #ifdef LOCK_STATS |
489 | gdk_export void GDKlockstatistics(int); |
490 | gdk_export MT_Lock * volatile GDKlocklist; |
491 | gdk_export ATOMIC_FLAG GDKlocklistlock; |
492 | gdk_export ATOMIC_TYPE GDKlockcnt; |
493 | gdk_export ATOMIC_TYPE GDKlockcontentioncnt; |
494 | gdk_export ATOMIC_TYPE GDKlocksleepcnt; |
495 | #endif |
496 | |
497 | /* |
498 | * @- MT Semaphore API |
499 | */ |
500 | #if !defined(HAVE_PTHREAD_H) && defined(WIN32) |
501 | |
502 | typedef struct { |
503 | HANDLE sema; |
504 | char name[16]; |
505 | } MT_Sema; |
506 | |
507 | #define MT_sema_init(s, nr, n) \ |
508 | do { \ |
509 | assert((s)->sema == NULL); \ |
510 | strcpy_len((s)->name, (n), sizeof((s)->name)); \ |
511 | (s)->sema = CreateSemaphore(NULL, nr, 0x7fffffff, NULL); \ |
512 | } while (0) |
513 | |
514 | #define MT_sema_destroy(s) \ |
515 | do { \ |
516 | assert((s)->sema != NULL); \ |
517 | CloseHandle((s)->sema); \ |
518 | (s)->sema = NULL; \ |
519 | } while (0) |
520 | |
521 | #define MT_sema_up(s) ReleaseSemaphore((s)->sema, 1, NULL) |
522 | |
523 | #define MT_sema_down(s) \ |
524 | do { \ |
525 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s down...\n", \ |
526 | MT_thread_getname(), __func__, (s)->name); \ |
527 | if (WaitForSingleObject((s)->sema, 0) != WAIT_OBJECT_0) { \ |
528 | MT_thread_setsemawait(s); \ |
529 | while (WaitForSingleObject((s)->sema, INFINITE) != WAIT_OBJECT_0) \ |
530 | ; \ |
531 | MT_thread_setsemawait(NULL); \ |
532 | } \ |
533 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s down complete\n", \ |
534 | MT_thread_getname(), __func__, (s)->name); \ |
535 | } while (0) |
536 | |
537 | #elif defined(HAVE_DISPATCH_SEMAPHORE_CREATE) |
538 | |
539 | /* MacOS X */ |
540 | typedef struct { |
541 | dispatch_semaphore_t sema; |
542 | char name[16]; |
543 | } MT_Sema; |
544 | |
545 | #define MT_sema_init(s, nr, n) \ |
546 | do { \ |
547 | strcpy_len((s)->name, (n), sizeof((s)->name)); \ |
548 | (s)->sema = dispatch_semaphore_create((long) (nr)); \ |
549 | } while (0) |
550 | |
551 | #define MT_sema_destroy(s) dispatch_release((s)->sema) |
552 | #define MT_sema_up(s) dispatch_semaphore_signal((s)->sema) |
553 | #define MT_sema_down(s) dispatch_semaphore_wait((s)->sema, DISPATCH_TIME_FOREVER) |
554 | |
555 | #elif defined(_AIX) || defined(__MACH__) |
556 | |
557 | /* simulate semaphores using mutex and condition variable */ |
558 | |
559 | typedef struct { |
560 | int cnt; |
561 | pthread_mutex_t mutex; |
562 | pthread_cond_t cond; |
563 | char name[16]; |
564 | } MT_Sema; |
565 | |
566 | #define MT_sema_init(s, nr, n) \ |
567 | do { \ |
568 | strcpy_len((s)->name, (n), sizeof((s)->name)); \ |
569 | (s)->cnt = (nr); \ |
570 | pthread_mutex_init(&(s)->mutex, 0); \ |
571 | pthread_cond_init(&(s)->cond, 0); \ |
572 | } while (0) |
573 | |
574 | #define MT_sema_destroy(s) \ |
575 | do { \ |
576 | pthread_mutex_destroy(&(s)->mutex); \ |
577 | pthread_cond_destroy(&(s)->cond); \ |
578 | } while (0) |
579 | |
580 | #define MT_sema_up(s) \ |
581 | do { \ |
582 | pthread_mutex_lock(&(s)->mutex); \ |
583 | if ((s)->cnt++ < 0) { \ |
584 | pthread_cond_signal(&(s)->cond); \ |
585 | } \ |
586 | pthread_mutex_unlock(&(s)->mutex); \ |
587 | } while (0) |
588 | |
589 | #define MT_sema_down(s) \ |
590 | do { \ |
591 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s down...\n", \ |
592 | MT_thread_getname(), __func__, (s)->name); \ |
593 | pthread_mutex_lock(&(s)->mutex); \ |
594 | if (--(s)->cnt < 0) { \ |
595 | MT_thread_setsemawait(s); \ |
596 | do { \ |
597 | pthread_cond_wait(&(s)->cond, \ |
598 | &(s)->mutex); \ |
599 | } while ((s)->cnt < 0); \ |
600 | MT_thread_setsemawait(NULL); \ |
601 | pthread_mutex_unlock(&(s)->mutex); \ |
602 | } \ |
603 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s down complete\n", \ |
604 | MT_thread_getname(), __func__, (s)->name); \ |
605 | } while (0) |
606 | |
607 | #else |
608 | |
609 | typedef struct { |
610 | sem_t sema; |
611 | char name[16]; |
612 | } MT_Sema; |
613 | |
614 | #define MT_sema_init(s, nr, n) \ |
615 | do { \ |
616 | strcpy_len((s)->name, (n), sizeof((s)->name)); \ |
617 | sem_init(&(s)->sema, 0, nr); \ |
618 | } while (0) |
619 | |
620 | #define MT_sema_destroy(s) sem_destroy(&(s)->sema) |
621 | |
622 | #define MT_sema_up(s) \ |
623 | do { \ |
624 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s up\n", \ |
625 | MT_thread_getname(), __func__, (s)->name); \ |
626 | sem_post(&(s)->sema); \ |
627 | } while (0) |
628 | |
629 | #define MT_sema_down(s) \ |
630 | do { \ |
631 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s down...\n", \ |
632 | MT_thread_getname(), __func__, (s)->name); \ |
633 | if (sem_trywait(&(s)->sema) != 0) { \ |
634 | MT_thread_setsemawait(s); \ |
635 | while (sem_wait(&(s)->sema) != 0) \ |
636 | ; \ |
637 | MT_thread_setsemawait(NULL); \ |
638 | } \ |
639 | TEMDEBUG fprintf(stderr, "#%s: %s: sema %s down complete\n", \ |
640 | MT_thread_getname(), __func__, (s)->name); \ |
641 | } while (0) |
642 | |
643 | #endif |
644 | |
645 | gdk_export void MT_thread_setlockwait(MT_Lock *lock); |
646 | gdk_export void MT_thread_setsemawait(MT_Sema *sema); |
647 | gdk_export void MT_thread_setworking(const char *work); |
648 | |
649 | gdk_export int MT_check_nr_cores(void); |
650 | |
651 | #endif /*_GDK_SYSTEM_H_*/ |
652 | |