1 /* Threads compatibility routines for libgcc2 and libobjc for VxWorks. */
2 /* Compile this one with gcc. */
3 /* Copyright (C) 1997-2021 Free Software Foundation, Inc.
4 Contributed by Mike Stump <mrs@wrs.com>.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 Under Section 7 of GPL version 3, you are granted additional
19 permissions described in the GCC Runtime Library Exception, version
20 3.1, as published by the Free Software Foundation.
21
22 You should have received a copy of the GNU General Public License and
23 a copy of the GCC Runtime Library Exception along with this program;
24 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
25 <http://www.gnu.org/licenses/>. */
26
27 #ifndef GCC_GTHR_VXWORKS_H
28 #define GCC_GTHR_VXWORKS_H
29
30 #ifdef _LIBOBJC
31
32 /* libobjc requires the optional pthreads component. */
33 #include "gthr-posix.h"
34
35 #else
36
37 #include <vxWorks.h>
38 #include <_vxworks-versions.h>
39
40 /* Some VxWorks headers profusely use typedefs of a pointer to a function with
41 undefined number of arguments. */
42 #pragma GCC diagnostic push
43 #pragma GCC diagnostic ignored "-Wstrict-prototypes"
44 #include <semLib.h>
45 #pragma GCC diagnostic pop
46
47 #include <errnoLib.h>
48
49
50 /* --------------------- Test & Set/Swap internal API --------------------- */
51
52 /* We use a bare atomic primitive with busy loops to handle mutual exclusion.
53 Inefficient, but reliable. The actual primitive used depends on the mode
54 (RTP vs Kernel) and the version of VxWorks. We define a macro and a type
55 here, for reuse without conditionals cluttering in the code afterwards. */
56
57 /* RTP, pre 6.9. */
58
59 #if defined(__RTP__) && _VXWORKS_PRE(6,9)
60
61 #define __TAS(x) vxCas ((x), 0, 1)
62 typedef volatile unsigned char __vx_tas_t;
63
64 #endif
65
66 /* RTP, 6.9 and beyond. */
67
68 #if defined(__RTP__) && !_VXWORKS_PRE(6,9)
69
70 #define __TAS(x) vxAtomicCas ((x), 0, 1)
71 typedef atomic_t __vx_tas_t;
72
73 /* Our implementation will need the system headers to use the vxAtomic
74 primitives. Other includers won't and could actually be incompatible
75 with this inclusion, for instance libstdc++ sources compiled in C++
76 98 mode while AtomicLib for C++ requires C++ 11 at least. */
77
78 #if defined(IN_LIBGCC2)
79 #include <vxAtomicLib.h>
80 #endif
81
82 #endif
83
84 /* Kernel */
85
86 #if !defined(__RTP__)
87
88 #define __TAS(x) vxTas (x)
89 typedef volatile unsigned char __vx_tas_t;
90
91 #endif
92
93 #ifdef __cplusplus
94 extern "C" {
95 #endif
96
97 /* ------------------------ Base __GTHREADS support ----------------------- */
98
99 #define __GTHREADS 1
100 #define __gthread_active_p() 1
101
102 /* Mutexes are easy, except that they need to be initialized at runtime. */
103
104 /* All VxWorks mutexes are recursive. */
105 typedef SEM_ID __gthread_mutex_t;
106 typedef SEM_ID __gthread_recursive_mutex_t;
107 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init
108 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init
109
110 #define __CHECK_RESULT(result) (((result) == OK) ? OK : errnoGet())
111
112 /* If a call to the VxWorks API fails, we must propagate the errno value. */
113 #define __RETURN_ERRNO_IF_NOT_OK(exp) if ((exp) != OK) return errnoGet()
114
115 /* Non re-entrant mutex implementation. Libstdc++ expects the default
116 gthread mutex to be non reentrant. */
117
118 static inline void
__gthread_mutex_init(__gthread_mutex_t * __mutex)119 __gthread_mutex_init (__gthread_mutex_t * __mutex)
120 {
121 if (!__mutex)
122 return;
123 *__mutex = semBCreate (SEM_Q_PRIORITY, SEM_FULL);
124 }
125
126 static inline int
__gthread_mutex_destroy(__gthread_mutex_t * __mutex)127 __gthread_mutex_destroy (__gthread_mutex_t * __mutex)
128 {
129 if (!__mutex)
130 return ERROR;
131 return __CHECK_RESULT (semDelete (*__mutex));
132 }
133
134 static inline int
__gthread_mutex_lock(__gthread_mutex_t * __mutex)135 __gthread_mutex_lock (__gthread_mutex_t * __mutex)
136 {
137 if (!__mutex)
138 return ERROR;
139 return __CHECK_RESULT (semTake(*__mutex, WAIT_FOREVER));
140 }
141
142 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * __mutex)143 __gthread_mutex_trylock (__gthread_mutex_t * __mutex)
144 {
145 if (!__mutex)
146 return ERROR;
147 return __CHECK_RESULT (semTake (*__mutex, NO_WAIT));
148 }
149
150 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * __mutex)151 __gthread_mutex_unlock (__gthread_mutex_t * __mutex)
152 {
153 if (!__mutex)
154 return ERROR;
155 return __CHECK_RESULT (semGive (*__mutex));
156 }
157
158 /* Recursive mutex implementation. The only change is that we use semMCreate()
159 instead of semBCreate(). */
160
161 static inline void
__gthread_recursive_mutex_init(__gthread_recursive_mutex_t * __mutex)162 __gthread_recursive_mutex_init (__gthread_recursive_mutex_t * __mutex)
163 {
164 if (!__mutex)
165 return;
166 *__mutex =
167 semMCreate (SEM_Q_PRIORITY | SEM_INVERSION_SAFE | SEM_DELETE_SAFE);
168 }
169
170 static inline int
__gthread_recursive_mutex_destroy(__gthread_recursive_mutex_t * __mutex)171 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t * __mutex)
172 {
173 return __gthread_mutex_destroy (__mutex);
174 }
175
176 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * __mutex)177 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t * __mutex)
178 {
179 return __gthread_mutex_lock (__mutex);
180 }
181
182 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * __mutex)183 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t * __mutex)
184 {
185 return __gthread_mutex_trylock (__mutex);
186 }
187
188 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * __mutex)189 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t * __mutex)
190 {
191 return __gthread_mutex_unlock (__mutex);
192 }
193
194 typedef struct
195 {
196 /* PPC's test-and-set kernel mode implementation requires a pointer aligned
197 object, of which it only sets the first byte. We use padding in addition
198 to an alignment request here to maxmise the factors leading to the
199 desired actual alignment choice by the compiler. */
200 #if defined(__PPC__)
201 __attribute ((aligned (__alignof__ (void *))))
202 #endif
203
204 __vx_tas_t busy;
205 volatile unsigned char done;
206
207 #if !defined(__RTP__) && defined(__PPC__)
208 unsigned char pad1;
209 unsigned char pad2;
210 #endif
211 #if !defined(__RTP__) && defined(__PPC64__)
212 unsigned char pad3;
213 unsigned char pad4;
214 unsigned char pad5;
215 unsigned char pad6;
216 #endif
217 } __gthread_once_t;
218
219 #define __GTHREAD_ONCE_INIT {}
220
221 extern int __gthread_once (__gthread_once_t *__once, void (*__func)(void));
222
223 /* All the TSD routines are sufficiently complex that they
224 need to be implemented out of line. */
225
226 typedef unsigned int __gthread_key_t;
227
228 extern int __gthread_key_create (__gthread_key_t *__keyp,
229 void (*__dtor)(void *));
230 extern int __gthread_key_delete (__gthread_key_t __key);
231
232 extern void *__gthread_getspecific (__gthread_key_t __key);
233 extern int __gthread_setspecific (__gthread_key_t __key, void *__ptr);
234
235 /* ------------------ Base condition variables support ------------------- */
236
237 /* VxWorks prio to 6 misses a few services key to a correct
238 implementation of condition variables with reasonable complexity.
239 semExchange in particular. */
240
241 #if _VXWORKS_MAJOR_GE(6)
242
243 #define __GTHREAD_HAS_COND 1
244
245 typedef SEM_ID __gthread_cond_t;
246
247 #define __GTHREAD_COND_INIT_FUNCTION __gthread_cond_init
248
249 /* Condition variable declarations. */
250
251 extern void __gthread_cond_init (__gthread_cond_t *cond);
252
253 extern int __gthread_cond_destroy (__gthread_cond_t *cond);
254
255 extern int __gthread_cond_broadcast (__gthread_cond_t *cond);
256
257 extern int __gthread_cond_wait (__gthread_cond_t *cond,
258 __gthread_mutex_t *mutex);
259
260 extern int __gthread_cond_wait_recursive (__gthread_cond_t *cond,
261 __gthread_recursive_mutex_t *mutex);
262
263 #endif
264
265 /* ----------------------- C++0x thread support ------------------------- */
266
267 /* We do not support C++0x threads on that VxWorks 653, which we can
268 recognize by VTHREADS being defined. */
269
270 #if _VXWORKS_MAJOR_GE(6) && !defined(VTHREADS)
271
272 #define __GTHREADS_CXX0X 1
273
274 #include <limits.h>
275 #include <time.h>
276 #include <tickLib.h>
277 #include <sysLib.h>
278 #include <version.h>
279
280 typedef struct
281 {
282 TASK_ID task_id;
283 void *return_value;
284
285 /* This mutex is used to block in join() while the return value is
286 unavailable. */
287 __gthread_mutex_t return_value_available;
288
289 /* Before freeing the structure in the task wrapper, we need to wait until
290 join() or detach() are called on that thread. */
291 __gthread_mutex_t delete_ok;
292 } __gthread_tcb;
293
294 typedef __gthread_tcb *__gthread_t;
295
296 /* Typedefs specific to different vxworks versions. */
297 #if _VXWORKS_PRE(6,9)
298 typedef int _Vx_usr_arg_t;
299 #define TASK_ID_NULL ((TASK_ID)NULL)
300 #define SEM_ID_NULL ((SEM_ID)NULL)
301 #endif
302
303 typedef struct timespec __gthread_time_t;
304
305 /* Timed mutex lock declarations. */
306
307 extern int __gthread_mutex_timedlock (__gthread_mutex_t *m,
308 const __gthread_time_t *abs_time);
309
310 extern int __gthread_recursive_mutex_timedlock
311 (__gthread_recursive_mutex_t *mutex,
312 const __gthread_time_t *abs_timeout);
313
314 /* Timed condition variable declarations. */
315
316 extern int __gthread_cond_signal (__gthread_cond_t *cond);
317 extern int __gthread_cond_timedwait (__gthread_cond_t *cond,
318 __gthread_mutex_t *mutex,
319 const __gthread_time_t *abs_timeout);
320
321 /* gthreads declarations. */
322
323 extern int __gthread_equal (__gthread_t t1, __gthread_t t2);
324 extern int __gthread_yield (void);
325 extern int __gthread_create (__gthread_t *__threadid,
326 void *(*__func) (void*),
327 void *__args);
328 extern int __gthread_join (__gthread_t thread, void **value_ptr);
329 extern int __gthread_detach (__gthread_t thread);
330
331 extern __gthread_t __gthread_self (void);
332
333 #endif /* _VXWORKS_MAJOR_GE(6) && !defined(VTHREADS) */
334
335 #ifdef __cplusplus
336 }
337 #endif
338
339 #endif /* not _LIBOBJC */
340
341 #endif /* gthr-vxworks.h */
342