1 /* libc-internal interface for mutex locks. NPTL version. 2 Copyright (C) 1996-2022 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 License as 7 published by the Free Software Foundation; either version 2.1 of the 8 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; see the file COPYING.LIB. If 17 not, see <https://www.gnu.org/licenses/>. */ 18 19 #ifndef _LIBC_LOCK_H 20 #define _LIBC_LOCK_H 1 21 22 #include <pthread.h> 23 #define __need_NULL 24 #include <stddef.h> 25 26 27 /* Mutex type. */ 28 #if defined _LIBC || defined _IO_MTSAFE_IO 29 # if (!IS_IN (libc) && !IS_IN (libpthread)) || !defined _LIBC 30 typedef struct { pthread_mutex_t mutex; } __libc_lock_recursive_t; 31 # else 32 typedef struct { int lock; int cnt; void *owner; } __libc_lock_recursive_t; 33 # endif 34 #else 35 typedef struct __libc_lock_recursive_opaque__ __libc_lock_recursive_t; 36 #endif 37 38 /* Define a lock variable NAME with storage class CLASS. The lock must be 39 initialized with __libc_lock_init before it can be used (or define it 40 with __libc_lock_define_initialized, below). Use `extern' for CLASS to 41 declare a lock defined in another module. In public structure 42 definitions you must use a pointer to the lock structure (i.e., NAME 43 begins with a `*'), because its storage size will not be known outside 44 of libc. */ 45 #define __libc_lock_define_recursive(CLASS,NAME) \ 46 CLASS __libc_lock_recursive_t NAME; 47 48 /* Define an initialized recursive lock variable NAME with storage 49 class CLASS. */ 50 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) 51 # define __libc_lock_define_initialized_recursive(CLASS, NAME) \ 52 CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; 53 # define _LIBC_LOCK_RECURSIVE_INITIALIZER \ 54 { LLL_LOCK_INITIALIZER, 0, NULL } 55 #else 56 # define __libc_lock_define_initialized_recursive(CLASS,NAME) \ 57 CLASS __libc_lock_recursive_t NAME = _LIBC_LOCK_RECURSIVE_INITIALIZER; 58 # define _LIBC_LOCK_RECURSIVE_INITIALIZER \ 59 {PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP} 60 #endif 61 62 /* Initialize a recursive mutex. */ 63 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) 64 # define __libc_lock_init_recursive(NAME) \ 65 ((void) ((NAME) = (__libc_lock_recursive_t) _LIBC_LOCK_RECURSIVE_INITIALIZER)) 66 #else 67 # define __libc_lock_init_recursive(NAME) \ 68 do { \ 69 if (__pthread_mutex_init != NULL) \ 70 { \ 71 pthread_mutexattr_t __attr; \ 72 __pthread_mutexattr_init (&__attr); \ 73 __pthread_mutexattr_settype (&__attr, PTHREAD_MUTEX_RECURSIVE_NP); \ 74 __pthread_mutex_init (&(NAME).mutex, &__attr); \ 75 __pthread_mutexattr_destroy (&__attr); \ 76 } \ 77 } while (0) 78 #endif 79 80 /* Finalize recursive named lock. */ 81 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) 82 # define __libc_lock_fini_recursive(NAME) ((void) 0) 83 #else 84 # define __libc_lock_fini_recursive(NAME) \ 85 __libc_maybe_call (__pthread_mutex_destroy, (&(NAME).mutex), 0) 86 #endif 87 88 /* Lock the recursive named lock variable. */ 89 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) 90 # define __libc_lock_lock_recursive(NAME) \ 91 do { \ 92 void *self = THREAD_SELF; \ 93 if ((NAME).owner != self) \ 94 { \ 95 lll_lock ((NAME).lock, LLL_PRIVATE); \ 96 (NAME).owner = self; \ 97 } \ 98 ++(NAME).cnt; \ 99 } while (0) 100 #else 101 # define __libc_lock_lock_recursive(NAME) \ 102 __libc_maybe_call (__pthread_mutex_lock, (&(NAME).mutex), 0) 103 #endif 104 105 /* Try to lock the recursive named lock variable. */ 106 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) 107 # define __libc_lock_trylock_recursive(NAME) \ 108 ({ \ 109 int result = 0; \ 110 void *self = THREAD_SELF; \ 111 if ((NAME).owner != self) \ 112 { \ 113 if (lll_trylock ((NAME).lock) == 0) \ 114 { \ 115 (NAME).owner = self; \ 116 (NAME).cnt = 1; \ 117 } \ 118 else \ 119 result = EBUSY; \ 120 } \ 121 else \ 122 ++(NAME).cnt; \ 123 result; \ 124 }) 125 #else 126 # define __libc_lock_trylock_recursive(NAME) \ 127 __libc_maybe_call (__pthread_mutex_trylock, (&(NAME).mutex), 0) 128 #endif 129 130 /* Unlock the recursive named lock variable. */ 131 #if defined _LIBC && (IS_IN (libc) || IS_IN (libpthread)) 132 /* We do no error checking here. */ 133 # define __libc_lock_unlock_recursive(NAME) \ 134 do { \ 135 if (--(NAME).cnt == 0) \ 136 { \ 137 (NAME).owner = NULL; \ 138 lll_unlock ((NAME).lock, LLL_PRIVATE); \ 139 } \ 140 } while (0) 141 #else 142 # define __libc_lock_unlock_recursive(NAME) \ 143 __libc_maybe_call (__pthread_mutex_unlock, (&(NAME).mutex), 0) 144 #endif 145 146 /* Put the unwind buffer BUFFER on the per-thread callback stack. The 147 caller must fill BUFFER->__routine and BUFFER->__arg before calling 148 this function. */ 149 void __libc_cleanup_push_defer (struct _pthread_cleanup_buffer *buffer); 150 libc_hidden_proto (__libc_cleanup_push_defer) 151 /* Remove BUFFER from the unwind callback stack. The caller must invoke 152 the callback if desired. */ 153 void __libc_cleanup_pop_restore (struct _pthread_cleanup_buffer *buffer); 154 libc_hidden_proto (__libc_cleanup_pop_restore) 155 156 /* Start critical region with cleanup. */ 157 #define __libc_cleanup_region_start(DOIT, FCT, ARG) \ 158 { bool _cleanup_start_doit; \ 159 struct _pthread_cleanup_buffer _buffer; \ 160 /* Non-addressable copy of FCT, so that we avoid indirect calls on \ 161 the non-unwinding path. */ \ 162 void (*_cleanup_routine) (void *) = (FCT); \ 163 _buffer.__arg = (ARG); \ 164 if (DOIT) \ 165 { \ 166 _cleanup_start_doit = true; \ 167 _buffer.__routine = _cleanup_routine; \ 168 __libc_cleanup_push_defer (&_buffer); \ 169 } \ 170 else \ 171 _cleanup_start_doit = false; 172 173 /* End critical region with cleanup. */ 174 #define __libc_cleanup_region_end(DOIT) \ 175 if (_cleanup_start_doit) \ 176 __libc_cleanup_pop_restore (&_buffer); \ 177 if (DOIT) \ 178 _cleanup_routine (_buffer.__arg); \ 179 } /* matches __libc_cleanup_region_start */ 180 181 182 /* Hide the definitions which are only supposed to be used inside libc in 183 a separate file. This file is not present in the installation! */ 184 #ifdef _LIBC 185 # include "libc-lockP.h" 186 #endif 187 188 #endif /* libc-lock.h */ 189