1/* Threads compatibility routines for libgcc2 and libobjc.  */
2/* Compile this one with gcc.  */
3/* Copyright (C) 1997-2020 Free Software Foundation, Inc.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see 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
52typedef pthread_key_t __gthread_key_t;
53typedef pthread_once_t __gthread_once_t;
54typedef pthread_mutex_t __gthread_mutex_t;
55typedef 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)
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
110static 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
119static 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 */
130static pthread_key_t _objc_thread_storage;
131
132/* Thread local storage for a single thread */
133static void *thread_local_storage = NULL;
134
135/* Backend initialization functions */
136
137/* Initialize the threads subsystem.  */
138static inline int
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.  */
149static inline int
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.  */
161static inline objc_thread_t
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.  */
184static inline int
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.  */
215static inline int
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.  */
241static inline void
242__gthread_objc_thread_yield (void)
243{
244  if (__gthread_active_p ())
245    __gthrw_(pthread_yield) ();
246}
247
248/* Terminate the current thread.  */
249static inline int
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.  */
261static inline objc_thread_t
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.  */
275static inline int
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.  */
288static inline 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.  */
307static inline int
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.  */
327static inline int
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.  */
343static inline int
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.  */
353static inline int
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 */
364static inline int
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.  */
376static inline int
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.  */
388static inline int
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 */
400static inline int
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.  */
413static inline int
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.  */
425static inline int
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
438static inline int
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
447static inline int
448__gthread_key_create (__gthread_key_t *__key, void (*__dtor) (void *))
449{
450  return __gthrw_(pthread_keycreate) (__key, __dtor);
451}
452
453static inline int
454__gthread_key_delete (__gthread_key_t __key __attribute__ ((__unused__)))
455{
456  /* Operation is not supported.  */
457  return -1;
458}
459
460static inline void *
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
470static inline int
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
477static inline void
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
484static inline int
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
493static inline int
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
502static inline int
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
511static inline int
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
520static inline int
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
541static inline int
542__gthread_recursive_mutex_lock (__gthread_recursive_mutex_t *__mutex)
543{
544  return __gthread_mutex_lock (__mutex);
545}
546
547static inline int
548__gthread_recursive_mutex_trylock (__gthread_recursive_mutex_t *__mutex)
549{
550  return __gthread_mutex_trylock (__mutex);
551}
552
553static inline int
554__gthread_recursive_mutex_unlock (__gthread_recursive_mutex_t *__mutex)
555{
556  return __gthread_mutex_unlock (__mutex);
557}
558
559static inline int
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