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

source code of glibc/sysdeps/nptl/libc-lock.h