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