• 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(HAVE_PTHREAD)
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 #else
53 
54 /*---------------------------- macros ---------------------------*/
55 
56 #ifndef _Thread_local
57 #  if defined(__cplusplus)
58      /* C++11 doesn't need `_Thread_local` keyword or macro */
59 #  elif !defined(__STDC_NO_THREADS__)
60      /* threads are optional in C11, _Thread_local present in this condition */
61 #  elif defined(_MSC_VER)
62 #    define _Thread_local __declspec(thread)
63 #  elif defined(__GNUC__)
64 #    define _Thread_local __thread
65 #  else
66      /* Leave _Thread_local undefined so that use of _Thread_local would not promote
67       * to a non-thread-local global variable
68       */
69 #  endif
70 #endif
71 
72 #if !defined(__cplusplus)
73    /*
74     * C11 thread_local() macro
75     * C++11 and above already have thread_local keyword
76     */
77 #  ifndef thread_local
78 #    define thread_local _Thread_local
79 #  endif
80 #endif
81 
82 #ifdef __cplusplus
83 extern "C" {
84 #endif
85 
86 /*---------------------------- types ----------------------------*/
87 typedef void (*tss_dtor_t)(void *);
88 typedef int (*thrd_start_t)(void *);
89 
90 #if defined(_WIN32) && !defined(HAVE_PTHREAD)
91 typedef struct
92 {
93    void *Ptr;
94 } cnd_t;
95 /* Define thrd_t as struct type intentionally for avoid use of thrd_t as pointer type */
96 typedef struct
97 {
98    void *handle;
99 } thrd_t;
100 typedef unsigned long tss_t;
101 typedef struct
102 {
103    void *DebugInfo;
104    long LockCount;
105    long RecursionCount;
106    void *OwningThread;
107    void *LockSemaphore;
108    uintptr_t SpinCount;
109 } mtx_t; /* Mock of CRITICAL_SECTION */
110 typedef struct
111 {
112    volatile uintptr_t status;
113 } once_flag;
114 #  define ONCE_FLAG_INIT {0}
115 #  define TSS_DTOR_ITERATIONS 1
116 #elif defined(HAVE_PTHREAD)
117 typedef pthread_cond_t  cnd_t;
118 typedef pthread_t       thrd_t;
119 typedef pthread_key_t   tss_t;
120 typedef pthread_mutex_t mtx_t;
121 typedef pthread_once_t  once_flag;
122 #  define ONCE_FLAG_INIT PTHREAD_ONCE_INIT
123 #  ifdef PTHREAD_DESTRUCTOR_ITERATIONS
124 #    define TSS_DTOR_ITERATIONS PTHREAD_DESTRUCTOR_ITERATIONS
125 #  else
126 #    define TSS_DTOR_ITERATIONS 1  // assume TSS dtor MAY be called at least once.
127 #  endif
128 #else
129 #  error Not supported on this platform.
130 #endif
131 
132 /*-------------------- enumeration constants --------------------*/
133 enum
134 {
135    mtx_plain = 0x1,
136    mtx_recursive = 0x2,
137    mtx_timed = 0x4,
138 };
139 
140 enum
141 {
142    thrd_success = 0, // succeeded
143    thrd_timedout,    // timed out
144    thrd_error,       // failed
145    thrd_busy,        // resource busy
146    thrd_nomem        // out of memory
147 };
148 
149 /*-------------------------- functions --------------------------*/
150 
151 void call_once(once_flag *, void (*)(void));
152 int cnd_broadcast(cnd_t *);
153 void cnd_destroy(cnd_t *);
154 int cnd_init(cnd_t *);
155 int cnd_signal(cnd_t *);
156 int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx,
157                   const struct timespec *__restrict);
158 int cnd_wait(cnd_t *, mtx_t *__mtx);
159 void mtx_destroy(mtx_t *__mtx);
160 int mtx_init(mtx_t *__mtx, int);
161 int mtx_lock(mtx_t *__mtx);
162 int mtx_timedlock(mtx_t *__restrict __mtx,
163                   const struct timespec *__restrict);
164 int mtx_trylock(mtx_t *__mtx);
165 int mtx_unlock(mtx_t *__mtx);
166 int thrd_create(thrd_t *, thrd_start_t, void *);
167 thrd_t thrd_current(void);
168 int thrd_detach(thrd_t);
169 int thrd_equal(thrd_t, thrd_t);
170 #if defined(__cplusplus)
171 [[ noreturn ]]
172 #else
173 _Noreturn
174 #endif
175 void thrd_exit(int);
176 int thrd_join(thrd_t, int *);
177 int thrd_sleep(const struct timespec *, struct timespec *);
178 void thrd_yield(void);
179 int tss_create(tss_t *, tss_dtor_t);
180 void tss_delete(tss_t);
181 void *tss_get(tss_t);
182 int tss_set(tss_t, void *);
183 
184 #ifdef __cplusplus
185 }
186 #endif
187 
188 #endif /* HAVE_THRD_CREATE */
189 
190 #endif /* C11_THREADS_H_INCLUDED_ */
191