JasPer: jas_thread.h Source File

JasPer 4.2.1 |

Loading...
Searching...
No Matches
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
105extern "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
139typedef 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
147typedef 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)
167typedef mtx_t jas_basicmutex_t;
168#elif defined(JAS_THREADS_PTHREAD)
169typedef pthread_mutex_t jas_basicmutex_t;
170#elif defined(JAS_THREADS_WIN32)
171typedef 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)
209typedef once_flag jas_once_flag_t;
210#elif defined(JAS_THREADS_PTHREAD)
211typedef pthread_once_t jas_once_flag_t;
212#elif defined(JAS_THREADS_WIN32)
213typedef 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)
235typedef thrd_t jas_thread_id_t;
236#elif defined(JAS_THREADS_PTHREAD)
237typedef pthread_t jas_thread_id_t;
238#elif defined(JAS_THREADS_WIN32)
239typedef HANDLE jas_thread_id_t;
240#endif
241
243#if defined(JAS_THREADS_C11)
244typedef thrd_t jas_thread_t;
245#elif defined(JAS_THREADS_PTHREAD)
246typedef 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)
253typedef struct {
254 jas_thread_id_t id;
255 int (*func)(void *);
256 void *arg;
257} jas_thread_t;
258#endif
259
260static inline void jas_thread_yield(void);
261
262#endif
263
264/**************************************\
265* Thread-Specific Storage (TSS)
266\**************************************/
267
269#if defined(JAS_THREADS_C11)
270typedef tss_t jas_tss_t;
271#elif defined(JAS_THREADS_PTHREAD)
272typedef pthread_key_t jas_tss_t;
273#elif defined(JAS_THREADS_WIN32)
274typedef DWORD jas_tss_t;
275#endif
276
277
278/******************************************************************************\
279* Spinlock
280\******************************************************************************/
281
282#if defined(JAS_USE_SPINLOCK)
283
295static 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
322static 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
349static 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
376static 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. */
399static 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. */
413static 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. */
428static 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. */
442static 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
472static inline
473int 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
503static inline
504void 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
524static inline
525void *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
546static inline
547int 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
572static 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)
603static 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)
611static 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
627static inline
628int 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
647static inline
648int 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
679static inline
680int 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
725static 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. */
738static inline
739void 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
757static inline
758jas_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
jas_compiler.h
Compiler-related macros.
JAS_UNUSED
#define JAS_UNUSED(x)
Indicate that a variable may be unused (in order to avoid a compiler warning).
Definition jas_compiler.h:145
jas_types.h
Primitive Types.