1  /* libc-internal interface for mutex locks.  Mach cthreads version.
       2     Copyright (C) 1996-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #ifndef _LIBC_LOCK_H
      20  #define _LIBC_LOCK_H 1
      21  
      22  #ifdef _LIBC
      23  
      24  #include <tls.h>
      25  #include <lowlevellock.h>
      26  
      27  typedef unsigned int __libc_lock_t;
      28  typedef struct
      29  {
      30    __libc_lock_t lock;
      31    int cnt;
      32    void *owner;
      33  } __libc_lock_recursive_t;
      34  
      35  typedef __libc_lock_recursive_t __rtld_lock_recursive_t;
      36  
      37  #define __libc_lock_owner_self()   \
      38    (__LIBC_NO_TLS () ? (void *) 1 : THREAD_SELF)
      39  
      40  #else
      41  typedef struct __libc_lock_opaque__ __libc_lock_t;
      42  typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t;
      43  #endif
      44  
      45  /* Define a lock variable NAME with storage class CLASS.  The lock must be
      46     initialized with __libc_lock_init before it can be used (or define it
      47     with __libc_lock_define_initialized, below).  Use `extern' for CLASS to
      48     declare a lock defined in another module.  In public structure
      49     definitions you must use a pointer to the lock structure (i.e., NAME
      50     begins with a `*'), because its storage size will not be known outside
      51     of libc.  */
      52  #define __libc_lock_define(CLASS,NAME) \
      53    CLASS __libc_lock_t NAME;
      54  
      55  /* Define an initialized lock variable NAME with storage class CLASS.  */
      56  #define _LIBC_LOCK_INITIALIZER LLL_LOCK_INITIALIZER
      57  #define __libc_lock_define_initialized(CLASS,NAME) \
      58    CLASS __libc_lock_t NAME = LLL_LOCK_INITIALIZER;
      59  
      60  /* Initialize the named lock variable, leaving it in a consistent, unlocked
      61     state.  */
      62  #define __libc_lock_init(NAME) (NAME) = LLL_LOCK_INITIALIZER
      63  
      64  /* Finalize the named lock variable, which must be locked.  It cannot be
      65     used again until __libc_lock_init is called again on it.  This must be
      66     called on a lock variable before the containing storage is reused.  */
      67  #define __libc_lock_fini             __libc_lock_unlock
      68  #define __libc_lock_fini_recursive   __libc_lock_unlock_recursive
      69  #define __rtld_lock_fini_recursive   __rtld_lock_unlock_recursive
      70  
      71  /* Lock the named lock variable.  */
      72  #define __libc_lock_lock(NAME)   \
      73    ({ lll_lock ((NAME), LLL_PRIVATE); 0; })
      74  
      75  /* Lock the named lock variable.  */
      76  #define __libc_lock_trylock(NAME) lll_trylock (NAME)
      77  
      78  /* Unlock the named lock variable.  */
      79  #define __libc_lock_unlock(NAME)   \
      80    ({ lll_unlock ((NAME), LLL_PRIVATE); 0; })
      81  
      82  #define __libc_lock_define_recursive(CLASS,NAME) \
      83    CLASS __libc_lock_recursive_t NAME;
      84  
      85  #define _LIBC_LOCK_RECURSIVE_INITIALIZER { LLL_LOCK_INITIALIZER, 0, 0 }
      86  
      87  #define __libc_lock_define_initialized_recursive(CLASS,NAME) \
      88    CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER;
      89  
      90  #define __rtld_lock_define_recursive(CLASS,NAME) \
      91    __libc_lock_define_recursive (CLASS, NAME)
      92  #define _RTLD_LOCK_RECURSIVE_INITIALIZER \
      93    _LIBC_LOCK_RECURSIVE_INITIALIZER
      94  #define __rtld_lock_define_initialized_recursive(CLASS,NAME) \
      95    __libc_lock_define_initialized_recursive (CLASS, NAME)
      96  
      97  #define __libc_lock_init_recursive(NAME)   \
      98    ({   \
      99       (NAME) = (__libc_lock_recursive_t)_LIBC_LOCK_RECURSIVE_INITIALIZER;   \
     100       0;   \
     101    })
     102  
     103  #define __libc_lock_trylock_recursive(NAME)   \
     104    ({   \
     105       __libc_lock_recursive_t *const __lock = &(NAME);   \
     106       void *__self = __libc_lock_owner_self ();   \
     107       int __r = 0;   \
     108       if (__self == __lock->owner)   \
     109         ++__lock->cnt;   \
     110       else if ((__r = lll_trylock (__lock->lock)) == 0)   \
     111         __lock->owner = __self, __lock->cnt = 1;   \
     112       __r;   \
     113     })
     114  
     115  #define __libc_lock_lock_recursive(NAME)   \
     116    ({   \
     117       __libc_lock_recursive_t *const __lock = &(NAME);   \
     118       void *__self = __libc_lock_owner_self ();   \
     119       if (__self != __lock->owner)   \
     120         {   \
     121           lll_lock (__lock->lock, 0);   \
     122           __lock->owner = __self;   \
     123         }   \
     124       ++__lock->cnt;   \
     125       (void)0;   \
     126     })
     127  
     128  #define __libc_lock_unlock_recursive(NAME)   \
     129    ({   \
     130       __libc_lock_recursive_t *const __lock = &(NAME);   \
     131       if (--__lock->cnt == 0)   \
     132         {   \
     133           __lock->owner = 0;   \
     134           lll_unlock (__lock->lock, 0);   \
     135         }   \
     136     })
     137  
     138  
     139  #define __rtld_lock_initialize(NAME) \
     140    (void) ((NAME) = (__rtld_lock_recursive_t) _RTLD_LOCK_RECURSIVE_INITIALIZER)
     141  #define __rtld_lock_trylock_recursive(NAME) \
     142    __libc_lock_trylock_recursive (NAME)
     143  #define __rtld_lock_lock_recursive(NAME) \
     144    __libc_lock_lock_recursive(NAME)
     145  #define __rtld_lock_unlock_recursive(NAME) \
     146    __libc_lock_unlock_recursive (NAME)
     147  
     148  /* XXX for now */
     149  #define __libc_rwlock_define		__libc_lock_define
     150  #define __libc_rwlock_define_initialized __libc_lock_define_initialized
     151  #define __libc_rwlock_init		__libc_lock_init
     152  #define __libc_rwlock_fini		__libc_lock_fini
     153  #define __libc_rwlock_rdlock		__libc_lock_lock
     154  #define __libc_rwlock_wrlock		__libc_lock_lock
     155  #define __libc_rwlock_tryrdlock		__libc_lock_trylock
     156  #define __libc_rwlock_trywrlock		__libc_lock_trylock
     157  #define __libc_rwlock_unlock		__libc_lock_unlock
     158  
     159  struct __libc_cleanup_frame
     160  {
     161    void (*__fct) (void *);
     162    void *__argp;
     163    int __doit;
     164  };
     165  
     166  __extern_inline void
     167  __libc_cleanup_fct (struct __libc_cleanup_frame *framep)
     168  {
     169    if (framep->__doit)
     170      framep->__fct (framep->__argp);
     171  }
     172  
     173  /* Start a critical region with a cleanup function */
     174  #define __libc_cleanup_region_start(DOIT, FCT, ARG)   \
     175    do   \
     176      {   \
     177        struct __libc_cleanup_frame __cleanup   \
     178          __attribute__ ((__cleanup__ (__libc_cleanup_fct))) =   \
     179          { .__fct = (FCT), .__argp = (ARG), .__doit = (DOIT) };
     180  
     181  /* This one closes the brace above.  */
     182  #define __libc_cleanup_region_end(DOIT)   \
     183        __cleanup.__doit = (DOIT);   \
     184      }   \
     185    while (0)
     186  
     187  #define __libc_cleanup_end(DOIT)   __cleanup.__doit = (DOIT);
     188  
     189  #define __libc_cleanup_push(fct, arg) __libc_cleanup_region_start (1, fct, arg)
     190  #define __libc_cleanup_pop(execute) __libc_cleanup_region_end (execute)
     191  
     192  /* Use mutexes as once control variables.  */
     193  
     194  struct __libc_once
     195    {
     196      __libc_lock_t lock;
     197      int done;
     198    };
     199  
     200  #define __libc_once_define(CLASS,NAME) \
     201    CLASS struct __libc_once NAME = { _LIBC_LOCK_INITIALIZER, 0 }
     202  
     203  /* Call handler iff the first call.  */
     204  #define __libc_once(ONCE_CONTROL, INIT_FUNCTION) \
     205    do {									      \
     206      __libc_lock_lock (ONCE_CONTROL.lock);				      \
     207      if (!ONCE_CONTROL.done)						      \
     208        (INIT_FUNCTION) ();						      \
     209      ONCE_CONTROL.done = 1;						      \
     210      __libc_lock_unlock (ONCE_CONTROL.lock);				      \
     211    } while (0)
     212  
     213  /* Get once control variable.  */
     214  #define __libc_once_get(ONCE_CONTROL)	((ONCE_CONTROL).done != 0)
     215  
     216  #ifdef _LIBC
     217  /* We need portable names for some functions.  E.g., when they are
     218     used as argument to __libc_cleanup_region_start.  */
     219  #define __libc_mutex_unlock __libc_lock_unlock
     220  
     221  /* Hide the definitions which are only supposed to be used inside libc in
     222     a separate file.  This file is not present in the installation!  */
     223  # include <libc-lockP.h>
     224  #endif
     225  
     226  #endif	/* libc-lock.h */