• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * C11 <threads.h> emulation library
3  *
4  * (C) Copyright yohhoy 2012.
5  * Copyright 2022 Yonggang Luo
6  * Distributed under the Boost Software License, Version 1.0.
7  *
8  * Permission is hereby granted, free of charge, to any person or organization
9  * obtaining a copy of the software and accompanying documentation covered by
10  * this license (the "Software") to use, reproduce, display, distribute,
11  * execute, and transmit the Software, and to prepare [[derivative work]]s of the
12  * Software, and to permit third-parties to whom the Software is furnished to
13  * do so, all subject to the following:
14  *
15  * The copyright notices in the Software and this entire statement, including
16  * the above license grant, this restriction and the following disclaimer,
17  * must be included in all copies of the Software, in whole or in part, and
18  * all derivative works of the Software, unless such copies or derivative
19  * works are solely in the form of machine-executable object code generated by
20  * a source language processor.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25  * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26  * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  */
30 
31 #ifndef C11_THREADS_H_INCLUDED_
32 #define C11_THREADS_H_INCLUDED_
33 
34 #include "c11/time.h"
35 
36 #include <errno.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 
40 #if defined(_WIN32) && !defined(__CYGWIN__)
41 #  include <io.h> /* close */
42 #  include <process.h> /* _exit */
43 #elif defined(HAVE_PTHREAD)
44 #  include <pthread.h>
45 #  include <unistd.h> /* close, _exit */
46 #else
47 #  error Not supported on this platform.
48 #endif
49 
50 #if defined(HAVE_THRD_CREATE)
51 #include <threads.h>
52 
53 #if defined(ANDROID)
54 /* Currently, only Android are verified that it's thrd_t are typedef of pthread_t
55  * So we can define _MTX_INITIALIZER_NP to PTHREAD_MUTEX_INITIALIZER
56  * FIXME: temporary non-standard hack to ease transition
57  */
58 #  define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
59 #else
60 #error Can not define _MTX_INITIALIZER_NP properly for this platform
61 #endif
62 #else
63 
64 /*---------------------------- macros ---------------------------*/
65 
66 #ifndef _Thread_local
67 #  if defined(__cplusplus)
68      /* C++11 doesn't need `_Thread_local` keyword or macro */
69 #  elif !defined(__STDC_NO_THREADS__)
70      /* threads are optional in C11, _Thread_local present in this condition */
71 #  elif defined(_MSC_VER)
72 #    define _Thread_local __declspec(thread)
73 #  elif defined(__GNUC__)
74 #    define _Thread_local __thread
75 #  else
76      /* Leave _Thread_local undefined so that use of _Thread_local would not promote
77       * to a non-thread-local global variable
78       */
79 #  endif
80 #endif
81 
82 #if !defined(__cplusplus)
83    /*
84     * C11 thread_local() macro
85     * C++11 and above already have thread_local keyword
86     */
87 #  ifndef thread_local
88 #    define thread_local _Thread_local
89 #  endif
90 #endif
91 
92 #ifdef __cplusplus
93 extern "C" {
94 #endif
95 
96 /*---------------------------- types ----------------------------*/
97 typedef void (*tss_dtor_t)(void *);
98 typedef int (*thrd_start_t)(void *);
99 
100 #if defined(_WIN32) && !defined(__CYGWIN__)
101 typedef struct
102 {
103    void *Ptr;
104 } cnd_t;
105 typedef void *thrd_t;
106 typedef unsigned long tss_t;
107 typedef struct
108 {
109    void *DebugInfo;
110    long LockCount;
111    long RecursionCount;
112    void *OwningThread;
113    void *LockSemaphore;
114    uintptr_t SpinCount;
115 } mtx_t; /* Mock of CRITICAL_SECTION */
116 typedef struct
117 {
118    volatile uintptr_t status;
119 } once_flag;
120 // FIXME: temporary non-standard hack to ease transition
121 #  define _MTX_INITIALIZER_NP {(void*)-1, -1, 0, 0, 0, 0}
122 #  define ONCE_FLAG_INIT {0}
123 #  define TSS_DTOR_ITERATIONS 1
124 #elif defined(HAVE_PTHREAD)
125 typedef pthread_cond_t  cnd_t;
126 typedef pthread_t       thrd_t;
127 typedef pthread_key_t   tss_t;
128 typedef pthread_mutex_t mtx_t;
129 typedef pthread_once_t  once_flag;
130 // FIXME: temporary non-standard hack to ease transition
131 #  define _MTX_INITIALIZER_NP PTHREAD_MUTEX_INITIALIZER
132 #  define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
133 #  ifdef INIT_ONCE_STATIC_INIT
134 #    define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
135 #  else
136 #    define TSS_DTOR_ITERATIONS 1  // assume TSS dtor MAY be called at least once.
137 #  endif
138 #else
139 #  error Not supported on this platform.
140 #endif
141 
142 /*-------------------- enumeration constants --------------------*/
143 enum
144 {
145    mtx_plain = 0,
146    mtx_try = 1,
147    mtx_timed = 2,
148    mtx_recursive = 4
149 };
150 
151 enum
152 {
153    thrd_success = 0, // succeeded
154    thrd_timedout,    // timed out
155    thrd_error,       // failed
156    thrd_busy,        // resource busy
157    thrd_nomem        // out of memory
158 };
159 
160 /*-------------------------- functions --------------------------*/
161 
162 void call_once(once_flag *, void (*)(void));
163 int cnd_broadcast(cnd_t *);
164 void cnd_destroy(cnd_t *);
165 int cnd_init(cnd_t *);
166 int cnd_signal(cnd_t *);
167 int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx,
168                   const struct timespec *__restrict);
169 int cnd_wait(cnd_t *, mtx_t *__mtx);
170 void mtx_destroy(mtx_t *__mtx);
171 int mtx_init(mtx_t *__mtx, int);
172 int mtx_lock(mtx_t *__mtx);
173 int mtx_timedlock(mtx_t *__restrict __mtx,
174                   const struct timespec *__restrict);
175 int mtx_trylock(mtx_t *__mtx);
176 int mtx_unlock(mtx_t *__mtx);
177 int thrd_create(thrd_t *, thrd_start_t, void *);
178 thrd_t thrd_current(void);
179 int thrd_detach(thrd_t);
180 int thrd_equal(thrd_t, thrd_t);
181 #if defined(__cplusplus)
182 [[ noreturn ]]
183 #else
184 _Noreturn
185 #endif
186 void thrd_exit(int);
187 int thrd_join(thrd_t, int *);
188 int thrd_sleep(const struct timespec *, struct timespec *);
189 void thrd_yield(void);
190 int tss_create(tss_t *, tss_dtor_t);
191 void tss_delete(tss_t);
192 void *tss_get(tss_t);
193 int tss_set(tss_t, void *);
194 
195 #ifdef __cplusplus
196 }
197 #endif
198 
199 #endif /* HAVE_THRD_CREATE */
200 
201 #endif /* C11_THREADS_H_INCLUDED_ */
202