1 /* Threads compatibility routines for libgcc2 and libobjc.  */
2 /* Compile this one with gcc.  */
3 /* Copyright (C) 1997-2021 Free Software Foundation, Inc.
4 
5 This file is part of GCC.
6 
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11 
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16 
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20 
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
24 <http://www.gnu.org/licenses/>.  */
25 
26 #ifndef GCC_GTHR_DCE_H
27 #define GCC_GTHR_DCE_H
28 
29 /* If _DCE_THREADS is not defined, then we're building the single
30    threaded version of the libraries and do not want to reference
31    anything related to pthreads or dce.  */
32 #ifndef _DCE_THREADS
33 #include "gthr-single.h"
34 #else
35 /* DCE threads interface.
36    DCE threads are based on POSIX threads draft 4, and many things
37    have changed since then.  */
38 
39 /* Make sure CONST_CAST2 (original in system.h) is defined.  */
40 #ifndef CONST_CAST2
41 #ifdef __cplusplus
42 #define CONST_CAST2(TOTYPE,FROMTYPE,X) (const_cast<TOTYPE> (X))
43 #else
44 #define CONST_CAST2(TOTYPE,FROMTYPE,X) ((__extension__(union {FROMTYPE _q; TOTYPE _nq;})(X))._nq)
45 #endif
46 #endif
47 
48 #define __GTHREADS 1
49 
50 #include <pthread.h>
51 
52 typedef pthread_key_t __gthread_key_t;
53 typedef pthread_once_t __gthread_once_t;
54 typedef pthread_mutex_t __gthread_mutex_t;
55 typedef pthread_mutex_t __gthread_recursive_mutex_t;
56 
57 #define __GTHREAD_ONCE_INIT pthread_once_init
58 
59 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
60 #define __GTHREAD_RECURSIVE_MUTEX_INIT_FUNCTION __gthread_recursive_mutex_init_function
61 
62 #define __GTHREAD_MUTEX_INIT_DEFAULT pthread_once_init
63 
64 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
65 # define __gthrw(name) \
66   static __typeof(name) __gthrw_ ## name __attribute__ ((__weakref__(#name)));
67 # define __gthrw_(name) __gthrw_ ## name
68 #else
69 # define __gthrw(name)
70 # define __gthrw_(name) name
71 #endif
72 
73 __gthrw(pthread_once)
__gthrw(pthread_keycreate)74 __gthrw(pthread_keycreate)
75 __gthrw(pthread_getspecific)
76 __gthrw(pthread_setspecific)
77 __gthrw(pthread_create)
78 __gthrw(pthread_mutex_init)
79 __gthrw(pthread_mutex_destroy)
80 __gthrw(pthread_mutex_lock)
81 __gthrw(pthread_mutex_trylock)
82 __gthrw(pthread_mutex_unlock)
83 __gthrw(pthread_mutexattr_create)
84 __gthrw(pthread_mutexattr_setkind_np)
85 __gthrw(pthread_mutexattr_delete)
86 
87 #ifdef _LIBOBJC
88 /* Objective-C.  */
89 __gthrw(pthread_cond_broadcast)
90 __gthrw(pthread_cond_destroy)
91 __gthrw(pthread_cond_init)
92 __gthrw(pthread_cond_signal)
93 __gthrw(pthread_cond_wait)
94 __gthrw(pthread_exit)
95 
96 #ifdef pthread_getunique_np
97 # define __gthrw_pthread_getunique_np pthread_getunique_np
98 #else
99 __gthrw(pthread_getunique_np)
100 # define __gthrw_pthread_getunique_np __gthrw_(pthread_getunique_np)
101 #endif
102 
103 __gthrw(pthread_mutex_destroy)
104 __gthrw(pthread_self)
105 __gthrw(pthread_yield)
106 #endif
107 
108 #if SUPPORTS_WEAK && GTHREAD_USE_WEAK
109 
110 static inline int
111 __gthread_active_p (void)
112 {
113   static void *const __gthread_active_ptr = (void *) &__gthrw_(pthread_create);
114   return __gthread_active_ptr != 0;
115 }
116 
117 #else /* not SUPPORTS_WEAK */
118 
119 static inline int
120 __gthread_active_p (void)
121 {
122   return 1;
123 }
124 
125 #endif /* SUPPORTS_WEAK */
126 
127 #ifdef _LIBOBJC
128 
129 /* Key structure for maintaining thread specific storage */
130 static pthread_key_t _objc_thread_storage;
131 
132 /* Thread local storage for a single thread */
133 static void *thread_local_storage = NULL;
134 
135 /* Backend initialization functions */
136 
137 /* Initialize the threads subsystem.  */
138 static inline int
__gthread_objc_init_thread_system(void)139 __gthread_objc_init_thread_system (void)
140 {
141   if (__gthread_active_p ())
142     /* Initialize the thread storage key.  */
143     return __gthrw_(pthread_keycreate) (&_objc_thread_storage, NULL);
144   else
145     return -1;
146 }
147 
148 /* Close the threads subsystem.  */
149 static inline int
__gthread_objc_close_thread_system(void)150 __gthread_objc_close_thread_system (void)
151 {
152   if (__gthread_active_p ())
153     return 0;
154   else
155     return -1;
156 }
157 
158 /* Backend thread functions */
159 
160 /* Create a new thread of execution.  */
161 static inline objc_thread_t
__gthread_objc_thread_detach(void (* func)(void *),void * arg)162 __gthread_objc_thread_detach (void (*func)(void *), void *arg)
163 {
164   objc_thread_t thread_id;
165   pthread_t new_thread_handle;
166 
167   if (!__gthread_active_p ())
168     return NULL;
169 
170   if (!(__gthrw_(pthread_create) (&new_thread_handle, pthread_attr_default,
171 			(void *) func, arg)))
172     {
173       /* ??? May not work! (64bit) */
174       thread_id = *(objc_thread_t *) &new_thread_handle;
175       pthread_detach (&new_thread_handle); /* Fully detach thread.  */
176     }
177   else
178     thread_id = NULL;
179 
180   return thread_id;
181 }
182 
183 /* Set the current thread's priority.  */
184 static inline int
__gthread_objc_thread_set_priority(int priority)185 __gthread_objc_thread_set_priority (int priority)
186 {
187   int sys_priority = 0;
188 
189   if (!__gthread_active_p ())
190     return -1;
191 
192   switch (priority)
193     {
194     case OBJC_THREAD_INTERACTIVE_PRIORITY:
195       sys_priority = (PRI_FG_MIN_NP + PRI_FG_MAX_NP) / 2;
196       break;
197     default:
198     case OBJC_THREAD_BACKGROUND_PRIORITY:
199       sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
200       break;
201     case OBJC_THREAD_LOW_PRIORITY:
202       sys_priority = (PRI_BG_MIN_NP + PRI_BG_MAX_NP) / 2;
203       break;
204     }
205 
206   /* Change the priority.  */
207   if (pthread_setprio (__gthrw_(pthread_self) (), sys_priority) >= 0)
208     return 0;
209   else
210     /* Failed */
211     return -1;
212 }
213 
214 /* Return the current thread's priority.  */
215 static inline int
__gthread_objc_thread_get_priority(void)216 __gthread_objc_thread_get_priority (void)
217 {
218   int sys_priority;
219 
220   if (__gthread_active_p ())
221     {
222       if ((sys_priority = pthread_getprio (__gthrw_(pthread_self) ())) >= 0)
223 	{
224 	  if (sys_priority >= PRI_FG_MIN_NP
225 	      && sys_priority <= PRI_FG_MAX_NP)
226 	    return OBJC_THREAD_INTERACTIVE_PRIORITY;
227 	  if (sys_priority >= PRI_BG_MIN_NP
228 	      && sys_priority <= PRI_BG_MAX_NP)
229 	    return OBJC_THREAD_BACKGROUND_PRIORITY;
230 	  return OBJC_THREAD_LOW_PRIORITY;
231 	}
232 
233       /* Failed */
234       return -1;
235     }
236   else
237     return OBJC_THREAD_INTERACTIVE_PRIORITY;
238 }
239 
240 /* Yield our process time to another thread.  */
241 static inline void
__gthread_objc_thread_yield(void)242 __gthread_objc_thread_yield (void)
243 {
244   if (__gthread_active_p ())
245     __gthrw_(pthread_yield) ();
246 }
247 
248 /* Terminate the current thread.  */
249 static inline int
__gthread_objc_thread_exit(void)250 __gthread_objc_thread_exit (void)
251 {
252   if (__gthread_active_p ())
253     /* exit the thread */
254     __gthrw_(pthread_exit) (&__objc_thread_exit_status);
255 
256   /* Failed if we reached here */
257   return -1;
258 }
259 
260 /* Returns an integer value which uniquely describes a thread.  */
261 static inline objc_thread_t
__gthread_objc_thread_id(void)262 __gthread_objc_thread_id (void)
263 {
264   if (__gthread_active_p ())
265     {
266       pthread_t self = __gthrw_(pthread_self) ();
267 
268       return (objc_thread_t) __gthrw_pthread_getunique_np (&self);
269     }
270   else
271     return (objc_thread_t) 1;
272 }
273 
274 /* Sets the thread's local storage pointer.  */
275 static inline int
__gthread_objc_thread_set_data(void * value)276 __gthread_objc_thread_set_data (void *value)
277 {
278   if (__gthread_active_p ())
279     return __gthrw_(pthread_setspecific) (_objc_thread_storage, value);
280   else
281     {
282       thread_local_storage = value;
283       return 0;
284     }
285 }
286 
287 /* Returns the thread's local storage pointer.  */
288 static inline void *
__gthread_objc_thread_get_data(void)289 __gthread_objc_thread_get_data (void)
290 {
291   void *value = NULL;
292 
293   if (__gthread_active_p ())
294     {
295       if (!(__gthrw_(pthread_getspecific) (_objc_thread_storage, &value)))
296 	return value;
297 
298       return NULL;
299     }
300   else
301     return thread_local_storage;
302 }
303 
304 /* Backend mutex functions */
305 
306 /* Allocate a mutex.  */
307 static inline int
__gthread_objc_mutex_allocate(objc_mutex_t mutex)308 __gthread_objc_mutex_allocate (objc_mutex_t mutex)
309 {
310   if (__gthread_active_p ())
311     {
312       mutex->backend = objc_malloc (sizeof (pthread_mutex_t));
313 
314       if (__gthrw_(pthread_mutex_init) ((pthread_mutex_t *) mutex->backend,
315 			      pthread_mutexattr_default))
316 	{
317 	  objc_free (mutex->backend);
318 	  mutex->backend = NULL;
319 	  return -1;
320 	}
321     }
322 
323   return 0;
324 }
325 
326 /* Deallocate a mutex.  */
327 static inline int
__gthread_objc_mutex_deallocate(objc_mutex_t mutex)328 __gthread_objc_mutex_deallocate (objc_mutex_t mutex)
329 {
330   if (__gthread_active_p ())
331     {
332       if (__gthrw_(pthread_mutex_destroy) ((pthread_mutex_t *) mutex->backend))
333 	return -1;
334 
335       objc_free (mutex->backend);
336       mutex->backend = NULL;
337     }
338 
339   return 0;
340 }
341 
342 /* Grab a lock on a mutex.  */
343 static inline int
__gthread_objc_mutex_lock(objc_mutex_t mutex)344 __gthread_objc_mutex_lock (objc_mutex_t mutex)
345 {
346   if (__gthread_active_p ())
347     return __gthrw_(pthread_mutex_lock) ((pthread_mutex_t *) mutex->backend);
348   else
349     return 0;
350 }
351 
352 /* Try to grab a lock on a mutex.  */
353 static inline int
__gthread_objc_mutex_trylock(objc_mutex_t mutex)354 __gthread_objc_mutex_trylock (objc_mutex_t mutex)
355 {
356   if (__gthread_active_p ()
357       && __gthrw_(pthread_mutex_trylock) ((pthread_mutex_t *) mutex->backend) != 1)
358     return -1;
359 
360   return 0;
361 }
362 
363 /* Unlock the mutex */
364 static inline int
__gthread_objc_mutex_unlock(objc_mutex_t mutex)365 __gthread_objc_mutex_unlock (objc_mutex_t mutex)
366 {
367   if (__gthread_active_p ())
368     return __gthrw_(pthread_mutex_unlock) ((pthread_mutex_t *) mutex->backend);
369   else
370     return 0;
371 }
372 
373 /* Backend condition mutex functions */
374 
375 /* Allocate a condition.  */
376 static inline int
__gthread_objc_condition_allocate(objc_condition_t condition)377 __gthread_objc_condition_allocate (objc_condition_t condition
378 				   __attribute__ ((__unused__)))
379 {
380   if (__gthread_active_p ())
381     /* Unimplemented.  */
382     return -1;
383   else
384     return 0;
385 }
386 
387 /* Deallocate a condition.  */
388 static inline int
__gthread_objc_condition_deallocate(objc_condition_t condition)389 __gthread_objc_condition_deallocate (objc_condition_t condition
390 				     __attribute__ ((__unused__)))
391 {
392   if (__gthread_active_p ())
393     /* Unimplemented.  */
394     return -1;
395   else
396     return 0;
397 }
398 
399 /* Wait on the condition */
400 static inline int
__gthread_objc_condition_wait(objc_condition_t condition,objc_mutex_t mutex)401 __gthread_objc_condition_wait (objc_condition_t condition
402 			       __attribute__ ((__unused__)),
403 			       objc_mutex_t mutex __attribute__ ((__unused__)))
404 {
405   if (__gthread_active_p ())
406     /* Unimplemented.  */
407     return -1;
408   else
409     return 0;
410 }
411 
412 /* Wake up all threads waiting on this condition.  */
413 static inline int
__gthread_objc_condition_broadcast(objc_condition_t condition)414 __gthread_objc_condition_broadcast (objc_condition_t condition
415 				    __attribute__ ((__unused__)))
416 {
417   if (__gthread_active_p ())
418     /* Unimplemented.  */
419     return -1;
420   else
421     return 0;
422 }
423 
424 /* Wake up one thread waiting on this condition.  */
425 static inline int
__gthread_objc_condition_signal(objc_condition_t condition)426 __gthread_objc_condition_signal (objc_condition_t condition
427 				 __attribute__ ((__unused__)))
428 {
429   if (__gthread_active_p ())
430     /* Unimplemented.  */
431     return -1;
432   else
433     return 0;
434 }
435 
436 #else /* _LIBOBJC */
437 
438 static inline int
__gthread_once(__gthread_once_t * __once,void (* __func)(void))439 __gthread_once (__gthread_once_t *__once, void (*__func) (void))
440 {
441   if (__gthread_active_p ())
442     return __gthrw_(pthread_once) (__once, __func);
443   else
444     return -1;
445 }
446 
447 static inline int
__gthread_key_create(__gthread_key_t * __key,void (* __dtor)(void *))448 __gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
449 {
450   return __gthrw_(pthread_keycreate) (__key, __dtor);
451 }
452 
453 static inline int
__gthread_key_delete(__gthread_key_t __key)454 __gthread_key_delete (__gthread_key_t __key __attribute__ ((__unused__)))
455 {
456   /* Operation is not supported.  */
457   return -1;
458 }
459 
460 static inline void *
__gthread_getspecific(__gthread_key_t __key)461 __gthread_getspecific (__gthread_key_t __key)
462 {
463   void *__ptr;
464   if (__gthrw_(pthread_getspecific) (__key, &__ptr) == 0)
465     return __ptr;
466   else
467     return 0;
468 }
469 
470 static inline int
__gthread_setspecific(__gthread_key_t __key,const void * __ptr)471 __gthread_setspecific (__gthread_key_t __key, const void *__ptr)
472 {
473   return __gthrw_(pthread_setspecific)
474     (__key, CONST_CAST2(void *, const void *, __ptr));
475 }
476 
477 static inline void
__gthread_mutex_init_function(__gthread_mutex_t * __mutex)478 __gthread_mutex_init_function (__gthread_mutex_t *__mutex)
479 {
480   if (__gthread_active_p ())
481     __gthrw_(pthread_mutex_init) (__mutex, pthread_mutexattr_default);
482 }
483 
484 static inline int
__gthread_mutex_destroy(__gthread_mutex_t * __mutex)485 __gthread_mutex_destroy (__gthread_mutex_t *__mutex)
486 {
487   if (__gthread_active_p ())
488     return __gthrw_(pthread_mutex_destroy) (__mutex);
489   else
490     return 0;
491 }
492 
493 static inline int
__gthread_mutex_lock(__gthread_mutex_t * __mutex)494 __gthread_mutex_lock (__gthread_mutex_t *__mutex)
495 {
496   if (__gthread_active_p ())
497     return __gthrw_(pthread_mutex_lock) (__mutex);
498   else
499     return 0;
500 }
501 
502 static inline int
__gthread_mutex_trylock(__gthread_mutex_t * __mutex)503 __gthread_mutex_trylock (__gthread_mutex_t *__mutex)
504 {
505   if (__gthread_active_p ())
506     return __gthrw_(pthread_mutex_trylock) (__mutex);
507   else
508     return 0;
509 }
510 
511 static inline int
__gthread_mutex_unlock(__gthread_mutex_t * __mutex)512 __gthread_mutex_unlock (__gthread_mutex_t *__mutex)
513 {
514   if (__gthread_active_p ())
515     return __gthrw_(pthread_mutex_unlock) (__mutex);
516   else
517     return 0;
518 }
519 
520 static inline int
__gthread_recursive_mutex_init_function(__gthread_recursive_mutex_t * __mutex)521 __gthread_recursive_mutex_init_function (__gthread_recursive_mutex_t *__mutex)
522 {
523   if (__gthread_active_p ())
524     {
525       pthread_mutexattr_t __attr;
526       int __r;
527 
528       __r = __gthrw_(pthread_mutexattr_create) (&__attr);
529       if (!__r)
530 	__r = __gthrw_(pthread_mutexattr_setkind_np) (&__attr,
531 						      MUTEX_RECURSIVE_NP);
532       if (!__r)
533 	__r = __gthrw_(pthread_mutex_init) (__mutex, __attr);
534       if (!__r)
535 	__r = __gthrw_(pthread_mutexattr_delete) (&__attr);
536       return __r;
537     }
538   return 0;
539 }
540 
541 static inline int
__gthread_recursive_mutex_lock(__gthread_recursive_mutex_t * __mutex)542 __gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
543 {
544   return __gthread_mutex_lock (__mutex);
545 }
546 
547 static inline int
__gthread_recursive_mutex_trylock(__gthread_recursive_mutex_t * __mutex)548 __gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
549 {
550   return __gthread_mutex_trylock (__mutex);
551 }
552 
553 static inline int
__gthread_recursive_mutex_unlock(__gthread_recursive_mutex_t * __mutex)554 __gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
555 {
556   return __gthread_mutex_unlock (__mutex);
557 }
558 
559 static inline int
__gthread_recursive_mutex_destroy(__gthread_recursive_mutex_t * __mutex)560 __gthread_recursive_mutex_destroy (__gthread_recursive_mutex_t *__mutex)
561 {
562   return __gthread_mutex_destroy (__mutex);
563 }
564 
565 #endif /* _LIBOBJC */
566 
567 #endif
568 #endif /* ! GCC_GTHR_DCE_H */
569