JasPer  4.2.4
jas_thread.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 1999-2000 Image Power, Inc. and the University of
3  * British Columbia.
4  * Copyright (c) 2001-2003 Michael David Adams.
5  * All rights reserved.
6  */
7 
8 /* __START_OF_JASPER_LICENSE__
9  *
10  * JasPer License Version 2.0
11  *
12  * Copyright (c) 2001-2006 Michael David Adams
13  * Copyright (c) 1999-2000 Image Power, Inc.
14  * Copyright (c) 1999-2000 The University of British Columbia
15  *
16  * All rights reserved.
17  *
18  * Permission is hereby granted, free of charge, to any person (the
19  * "User") obtaining a copy of this software and associated documentation
20  * files (the "Software"), to deal in the Software without restriction,
21  * including without limitation the rights to use, copy, modify, merge,
22  * publish, distribute, and/or sell copies of the Software, and to permit
23  * persons to whom the Software is furnished to do so, subject to the
24  * following conditions:
25  *
26  * 1. The above copyright notices and this permission notice (which
27  * includes the disclaimer below) shall be included in all copies or
28  * substantial portions of the Software.
29  *
30  * 2. The name of a copyright holder shall not be used to endorse or
31  * promote products derived from the Software without specific prior
32  * written permission.
33  *
34  * THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS
35  * LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER
36  * THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
37  * "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
38  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
39  * PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO
40  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL
41  * INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING
42  * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
43  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
44  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE
45  * PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE
46  * THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY.
47  * EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS
48  * BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL
49  * PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS
50  * GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE
51  * ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE
52  * IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL
53  * SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES,
54  * AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL
55  * SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH
56  * THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH,
57  * PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH
58  * RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY
59  * EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES.
60  *
61  * __END_OF_JASPER_LICENSE__
62  */
63 
69 #ifndef JAS_THREAD_H
70 #define JAS_THREAD_H
71 
72 /******************************************************************************\
73 * Includes
74 \******************************************************************************/
75 
76 /* The configuration header file should be included first. */
77 #include <jasper/jas_config.h>
78 
79 #include "jasper/jas_compiler.h"
80 #include "jasper/jas_types.h"
81 
82 #if defined(JAS_THREADS)
83 
84 #include <stdlib.h>
85 #include <assert.h>
86 
87 #if defined(JAS_THREADS_C11)
88 #include <threads.h>
89 #include <stdatomic.h>
90 #elif defined(JAS_THREADS_PTHREAD)
91 #include <pthread.h>
92 #include <sched.h>
93 #elif defined(JAS_THREADS_WIN32)
94 #include <process.h>
95 #include <windows.h>
96 #include <processthreadsapi.h>
97 #endif
98 
99 #endif
100 
101 /******************************************************************************\
102 \******************************************************************************/
103 
104 #ifdef __cplusplus
105 extern "C" {
106 #endif
107 
114 #if defined(JAS_THREADS)
115 #if defined(JAS_FOR_INTERNAL_USE_ONLY) || defined(JAS_FOR_JASPER_APP_USE_ONLY)
116 
117 /******************************************************************************\
118 * Types
119 \******************************************************************************/
120 
121 #if defined(JAS_THREADS_C11)
122 # define JAS_THREADS_IMPL "C11"
123 # define JAS_USE_SPINLOCK
124 #elif defined(JAS_THREADS_PTHREAD)
125 # define JAS_THREADS_IMPL "PTHREAD"
126 # undef JAS_USE_SPINLOCK
127 #elif defined(JAS_THREADS_WIN32)
128 # define JAS_THREADS_IMPL "WIN32"
129 # define JAS_USE_SPINLOCK
130 #endif
131 
132 /**************************************\
133 * Spinlock
134 \**************************************/
135 
137 #if defined(JAS_THREADS_C11)
138 # define JAS_USE_SPINLOCK
139 typedef struct {
140  atomic_flag flag;
141 } jas_spinlock_t;
142 #elif defined(JAS_THREADS_PTHREAD)
143 /* There is no pthread_spinlock_t type on MacOS. */
144 # undef JAS_USE_SPINLOCK
145 #elif defined(JAS_THREADS_WIN32)
146 # define JAS_USE_SPINLOCK
147 typedef struct {
148  LONG flag;
149 } jas_spinlock_t;
150 #endif
151 
153 #if defined(JAS_THREADS_C11)
154 #define JAS_SPINLOCK_INITIALIZER {ATOMIC_FLAG_INIT}
155 #elif defined(JAS_THREADS_PTHREAD)
156 /* There is no pthread_spinlock_t type on MacOS. */
157 #elif defined(JAS_THREADS_WIN32)
158 #define JAS_SPINLOCK_INITIALIZER {0}
159 #endif
160 
161 /**************************************\
162 * Basic Mutex
163 \**************************************/
164 
166 #if defined(JAS_THREADS_C11)
167 typedef mtx_t jas_basicmutex_t;
168 #elif defined(JAS_THREADS_PTHREAD)
169 typedef pthread_mutex_t jas_basicmutex_t;
170 #elif defined(JAS_THREADS_WIN32)
171 typedef CRITICAL_SECTION jas_basicmutex_t;
172 #endif
173 
175 #if defined(JAS_THREADS_C11)
176 #undef JAS_BASICMUTEX_INITIALIZER
177 #elif defined(JAS_THREADS_PTHREAD)
178 #define JAS_BASICMUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
179 #elif defined(JAS_THREADS_WIN32)
180 #define JAS_BASICMUTEX_INITIALIZER
181 #endif
182 
183 /**************************************\
184 * Mutex (Allowing Static Initialization)
185 \**************************************/
186 
187 #if defined(JAS_USE_SPINLOCK)
188 # define jas_mutex_t jas_spinlock_t
189 # define JAS_MUTEX_INITIALIZER JAS_SPINLOCK_INITIALIZER
190 # define jas_mutex_init jas_spinlock_init
191 # define jas_mutex_cleanup jas_spinlock_cleanup
192 # define jas_mutex_lock jas_spinlock_lock
193 # define jas_mutex_unlock jas_spinlock_unlock
194 #else
195 # define jas_mutex_t jas_basicmutex_t
196 # define JAS_MUTEX_INITIALIZER JAS_BASICMUTEX_INITIALIZER
197 # define jas_mutex_init jas_basicmutex_init
198 # define jas_mutex_cleanup jas_basicmutex_cleanup
199 # define jas_mutex_lock jas_basicmutex_lock
200 # define jas_mutex_unlock jas_basicmutex_unlock
201 #endif
202 
203 /**************************************\
204 * Once Flag
205 \**************************************/
206 
208 #if defined(JAS_THREADS_C11)
209 typedef once_flag jas_once_flag_t;
210 #elif defined(JAS_THREADS_PTHREAD)
211 typedef pthread_once_t jas_once_flag_t;
212 #elif defined(JAS_THREADS_WIN32)
213 typedef struct {
214  volatile LONG status;
215 } jas_once_flag_t;
216 #endif
217 
219 #if defined(JAS_THREADS_C11)
220 # define JAS_ONCE_FLAG_INIT ONCE_FLAG_INIT
221 #elif defined(JAS_THREADS_PTHREAD)
222 # define JAS_ONCE_FLAG_INIT PTHREAD_ONCE_INIT
223 #elif defined(JAS_THREADS_WIN32)
224 # define JAS_ONCE_FLAG_INIT {0}
225 #endif
226 
227 /**************************************\
228 * Threads
229 \**************************************/
230 
231 #if defined(JAS_FOR_INTERNAL_USE_ONLY) || defined(JAS_FOR_JASPER_APP_USE_ONLY)
232 
234 #if defined(JAS_THREADS_C11)
235 typedef thrd_t jas_thread_id_t;
236 #elif defined(JAS_THREADS_PTHREAD)
237 typedef pthread_t jas_thread_id_t;
238 #elif defined(JAS_THREADS_WIN32)
239 typedef HANDLE jas_thread_id_t;
240 #endif
241 
243 #if defined(JAS_THREADS_C11)
244 typedef thrd_t jas_thread_t;
245 #elif defined(JAS_THREADS_PTHREAD)
246 typedef struct {
247  pthread_t id;
248  int (*func)(void *);
249  void *arg;
250  int result;
251 } jas_thread_t;
252 #elif defined(JAS_THREADS_WIN32)
253 typedef struct {
254  jas_thread_id_t id;
255  int (*func)(void *);
256  void *arg;
257 } jas_thread_t;
258 #endif
259 
260 static inline void jas_thread_yield(void);
261 
262 #endif
263 
264 /**************************************\
265 * Thread-Specific Storage (TSS)
266 \**************************************/
267 
269 #if defined(JAS_THREADS_C11)
270 typedef tss_t jas_tss_t;
271 #elif defined(JAS_THREADS_PTHREAD)
272 typedef pthread_key_t jas_tss_t;
273 #elif defined(JAS_THREADS_WIN32)
274 typedef DWORD jas_tss_t;
275 #endif
276 
277 
278 /******************************************************************************\
279 * Spinlock
280 \******************************************************************************/
281 
282 #if defined(JAS_USE_SPINLOCK)
283 
295 static inline int jas_spinlock_init(jas_spinlock_t *mtx)
296 {
297  assert(mtx);
298 #if defined(JAS_THREADS_C11)
299  atomic_flag_clear(&mtx->flag);
300  return 0;
301 #elif defined(JAS_THREADS_PTHREAD)
302  JAS_UNUSED(mtx);
303  abort();
304  return -1;
305 #elif defined(JAS_THREADS_WIN32)
306  InterlockedExchange(&mtx->flag, 0);
307  return 0;
308 #endif
309 }
310 
322 static inline int jas_spinlock_cleanup(jas_spinlock_t *mtx)
323 {
324  assert(mtx);
325 #if defined(JAS_THREADS_C11)
326  JAS_UNUSED(mtx);
327  return 0;
328 #elif defined(JAS_THREADS_PTHREAD)
329  JAS_UNUSED(mtx);
330  abort();
331  return -1;
332 #elif defined(JAS_THREADS_WIN32)
333  JAS_UNUSED(mtx);
334  return 0;
335 #endif
336 }
337 
349 static inline int jas_spinlock_lock(jas_spinlock_t *mtx)
350 {
351  assert(mtx);
352 #if defined(JAS_THREADS_C11)
353  while (atomic_flag_test_and_set(&mtx->flag)) {}
354  return 0;
355 #elif defined(JAS_THREADS_PTHREAD)
356  JAS_UNUSED(mtx);
357  abort();
358  return -1;
359 #elif defined(JAS_THREADS_WIN32)
360  while (InterlockedCompareExchange(&mtx->flag, 1, 0)) {}
361  return 0;
362 #endif
363 }
364 
376 static inline int jas_spinlock_unlock(jas_spinlock_t *mtx)
377 {
378  assert(mtx);
379 #if defined(JAS_THREADS_C11)
380  atomic_flag_clear(&mtx->flag);
381  return 0;
382 #elif defined(JAS_THREADS_PTHREAD)
383  JAS_UNUSED(mtx);
384  abort();
385  return -1;
386 #elif defined(JAS_THREADS_WIN32)
387  InterlockedExchange(&mtx->flag, 0);
388  return 0;
389 #endif
390 }
391 
392 #endif
393 
394 /******************************************************************************\
395 * Basic Mutex
396 \******************************************************************************/
397 
398 /* For internal use only. */
399 static inline int jas_basicmutex_init(jas_basicmutex_t *mtx)
400 {
401  assert(mtx);
402 #if defined(JAS_THREADS_C11)
403  return mtx_init(mtx, mtx_plain) == thrd_success ? 0 : -1;
404 #elif defined(JAS_THREADS_PTHREAD)
405  return pthread_mutex_init(mtx, 0);
406 #elif defined(JAS_THREADS_WIN32)
407  InitializeCriticalSection(mtx);
408  return 0;
409 #endif
410 }
411 
412 /* For internal use only. */
413 static inline int jas_basicmutex_cleanup(jas_basicmutex_t *mtx)
414 {
415  assert(mtx);
416 #if defined(JAS_THREADS_C11)
417  mtx_destroy(mtx);
418  return 0;
419 #elif defined(JAS_THREADS_PTHREAD)
420  return pthread_mutex_destroy(mtx);
421 #elif defined(JAS_THREADS_WIN32)
422  DeleteCriticalSection(mtx);
423  return 0;
424 #endif
425 }
426 
427 /* For internal use only. */
428 static inline int jas_basicmutex_lock(jas_basicmutex_t *mtx)
429 {
430  assert(mtx);
431 #if defined(JAS_THREADS_C11)
432  return mtx_lock(mtx);
433 #elif defined(JAS_THREADS_PTHREAD)
434  return pthread_mutex_lock(mtx);
435 #elif defined(JAS_THREADS_WIN32)
436  EnterCriticalSection(mtx);
437  return 0;
438 #endif
439 }
440 
441 /* For internal use only. */
442 static inline int jas_basicmutex_unlock(jas_basicmutex_t *mtx)
443 {
444  assert(mtx);
445 #if defined(JAS_THREADS_C11)
446  return mtx_unlock(mtx);
447 #elif defined(JAS_THREADS_PTHREAD)
448  return pthread_mutex_unlock(mtx);
449 #elif defined(JAS_THREADS_WIN32)
450  LeaveCriticalSection(mtx);
451  return 0;
452 #endif
453 }
454 
455 /******************************************************************************\
456 * Thread-Specific Storage (TSS)
457 \******************************************************************************/
458 
472 static inline
473 int jas_tss_create(jas_tss_t *tss, void (*destructor)(void *))
474 {
475  assert(tss);
476 #if defined(JAS_THREADS_C11)
477  return tss_create(tss, destructor) == thrd_success ? 0 : -1;
478 #elif defined(JAS_THREADS_PTHREAD)
479  return pthread_key_create(tss, destructor);
480 #elif defined(JAS_THREADS_WIN32)
481  if (destructor) {
482  return -1;
483  }
484  DWORD id;
485  if ((id = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
486  return -2;
487  }
488  *tss = id;
489  return 0;
490 #endif
491 }
492 
503 static inline
504 void jas_tss_delete(jas_tss_t tss)
505 {
506 #if defined(JAS_THREADS_C11)
507  tss_delete(tss);
508 #elif defined(JAS_THREADS_PTHREAD)
509  pthread_key_delete(tss);
510 #elif defined(JAS_THREADS_WIN32)
511  TlsFree(tss);
512 #endif
513 }
514 
524 static inline
525 void *jas_tss_get(jas_tss_t tss)
526 {
527 #if defined(JAS_THREADS_C11)
528  return tss_get(tss);
529 #elif defined(JAS_THREADS_PTHREAD)
530  return pthread_getspecific(tss);
531 #elif defined(JAS_THREADS_WIN32)
532  return TlsGetValue(tss);
533 #endif
534 }
535 
546 static inline
547 int jas_tss_set(jas_tss_t tss, void *value)
548 {
549 #if defined(JAS_THREADS_C11)
550  return tss_set(tss, value) == thrd_success ? 0 : -1;
551 #elif defined(JAS_THREADS_PTHREAD)
552  return pthread_setspecific(tss, value);
553 #elif defined(JAS_THREADS_WIN32)
554  return TlsSetValue(tss, value) ? 0 : -1;
555 #endif
556 }
557 
558 /******************************************************************************\
559 * Once Flag
560 \******************************************************************************/
561 
572 static inline int jas_call_once(jas_once_flag_t *flag, void (*func)(void))
573 {
574  assert(flag);
575  assert(func);
576 #if defined(JAS_THREADS_C11)
577  call_once(flag, func);
578  return 0;
579 #elif defined(JAS_THREADS_PTHREAD)
580  return pthread_once(flag, func);
581 #elif defined(JAS_THREADS_WIN32)
582  if (InterlockedCompareExchange(&flag->status, 1, 0) == 0) {
583  (func)();
584  InterlockedExchange(&flag->status, 2);
585  } else {
586  while (flag->status == 1) {
587  /* Perform a busy wait. This is ugly. */
588  /* Yield processor. */
589  SwitchToThread();
590  }
591  }
592  return 0;
593 #endif
594 }
595 
596 /******************************************************************************\
597 * Threads
598 \******************************************************************************/
599 
600 #if defined(JAS_FOR_INTERNAL_USE_ONLY) || defined(JAS_FOR_JASPER_APP_USE_ONLY)
601 
602 #if defined(JAS_THREADS_PTHREAD)
603 static void *thread_func_wrapper(void *thread_ptr)
604 {
605  jas_thread_t *thread = JAS_CAST(jas_thread_t *, thread_ptr);
606  int result = (thread->func)(thread->arg);
607  thread->result = result;
608  return thread;
609 }
610 #elif defined(JAS_THREADS_WIN32)
611 static unsigned __stdcall thread_func_wrapper(void *thread_ptr)
612 {
613  jas_thread_t *thread = JAS_CAST(jas_thread_t *, thread_ptr);
614  int result = (thread->func)(thread->arg);
615  return JAS_CAST(unsigned, result);
616 }
617 #endif
618 
627 static inline
628 int jas_thread_compare(jas_thread_id_t x, jas_thread_id_t y)
629 {
630 #if defined(JAS_THREADS_C11)
631  return thrd_equal(x, y);
632 #elif defined(JAS_THREADS_PTHREAD)
633  return pthread_equal(x, y);
634 #elif defined(JAS_THREADS_WIN32)
635  return GetThreadId(x) == GetThreadId(y);
636 #endif
637 }
638 
647 static inline
648 int jas_thread_create(jas_thread_t *thread, int (*func)(void *), void *arg)
649 {
650  assert(thread);
651  assert(func);
652 #if defined(JAS_THREADS_C11)
653  return thrd_create(thread, func, arg) == thrd_success ? 0 : -1;
654 #elif defined(JAS_THREADS_PTHREAD)
655  thread->func = func;
656  thread->arg = arg;
657  thread->result = 0;
658  return pthread_create(&thread->id, 0, thread_func_wrapper, thread);
659 #elif defined(JAS_THREADS_WIN32)
660  uintptr_t handle;
661  thread->func = func;
662  thread->arg = arg;
663  if (!(handle = _beginthreadex(0, 0, thread_func_wrapper, thread, 0, 0))) {
664  return -1;
665  }
666  thread->id = JAS_CAST(jas_thread_id_t, handle);
667  return 0;
668 #endif
669 }
670 
679 static inline
680 int jas_thread_join(jas_thread_t *thread, int *result)
681 {
682  assert(thread);
683 #if defined(JAS_THREADS_C11)
684  return thrd_join(*thread, result) == thrd_success ? 0 : -1;
685 #elif defined(JAS_THREADS_PTHREAD)
686  void *result_buf;
687  int ret = pthread_join(thread->id, &result_buf);
688  if (!ret) {
689  jas_thread_t *other_thread = JAS_CAST(jas_thread_t *, result_buf);
690  if (result) {
691  /* A null pointer is probably a bug. */
692  assert(other_thread);
693  *result = other_thread ? other_thread->result : 0;
694  }
695  }
696  return ret;
697 #elif defined(JAS_THREADS_WIN32)
698  DWORD w;
699  DWORD code;
700  if ((w = WaitForSingleObject(thread->id, INFINITE)) != WAIT_OBJECT_0) {
701  return -1;
702  }
703  if (result) {
704  if (!GetExitCodeThread(thread->id, &code)) {
705  CloseHandle(thread->id);
706  return -1;
707  }
708  *result = JAS_CAST(int, code);
709  }
710  CloseHandle(thread->id);
711  return 0;
712 #endif
713 }
714 
725 static inline void jas_thread_yield(void)
726 {
727 #if defined(JAS_THREADS_C11)
728  thrd_yield();
729 #elif defined(JAS_THREADS_PTHREAD)
730  sched_yield();
731 #elif defined(JAS_THREADS_WIN32)
732  SwitchToThread();
733 #endif
734 }
735 
736 #if 0
737 /* This functionality is not available for all threading support libraries. */
738 static inline
739 void jas_thread_exit(int result)
740 {
741 #if defined(JAS_THREADS_C11)
742  thrd_exit(result);
743 #elif defined(JAS_THREADS_PTHREAD)
744  /* This does not have a trivial implementation, as far as I can see. */
745  /* There is no jas_thread_find function. */
746  jas_thread_t *thread = jas_thread_find(pthread_self());
747  thread->result = result;
748  pthread_exit(JAS_CAST(void *, thread));
749 #endif
750 }
751 #endif
752 
753 #if 0
757 static inline
758 jas_thread_id_t jas_thread_current(void)
759 {
760 #if defined(JAS_THREADS_C11)
761  return thrd_current();
762 #elif defined(JAS_THREADS_PTHREAD)
763  return pthread_self();
764 #elif defined(JAS_THREADS_WIN32)
765  /* FIXME - NOT YET IMPLEMENTED. */
766  abort();
767 #endif
768 }
769 #endif
770 
771 #endif
772 
773 /******************************************************************************\
774 *
775 \******************************************************************************/
776 
777 #endif
778 #else
779 
780 /******************************************************************************\
781 * No Threading Support.
782 \******************************************************************************/
783 
784 #endif
785 
791 #ifdef __cplusplus
792 }
793 #endif
794 
795 #endif
Compiler-related macros.
#define JAS_UNUSED(x)
Indicate that a variable may be unused (in order to avoid a compiler warning).
Definition: jas_compiler.h:145
Primitive Types.