1 /* POSIX mutexes (locks).
2 Copyright (C) 2010-2021 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
16
17 /* Written by Paul Eggert, 2010, and Bruno Haible <bruno@clisp.org>, 2019. */
18
19 #include <config.h>
20
21 /* Specification. */
22 #include <pthread.h>
23
24 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
25 # include "windows-timedmutex.h"
26 # include "windows-timedrecmutex.h"
27 #else
28 # include <stdlib.h>
29 #endif
30
31 #if ((defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS) || !HAVE_PTHREAD_H
32
33 int
pthread_mutexattr_init(pthread_mutexattr_t * attr)34 pthread_mutexattr_init (pthread_mutexattr_t *attr)
35 {
36 *attr = (PTHREAD_MUTEX_STALLED << 2) | PTHREAD_MUTEX_DEFAULT;
37 return 0;
38 }
39
40 int
pthread_mutexattr_gettype(const pthread_mutexattr_t * attr,int * typep)41 pthread_mutexattr_gettype (const pthread_mutexattr_t *attr, int *typep)
42 {
43 *typep = *attr & (PTHREAD_MUTEX_DEFAULT | PTHREAD_MUTEX_NORMAL
44 | PTHREAD_MUTEX_ERRORCHECK | PTHREAD_MUTEX_RECURSIVE);
45 return 0;
46 }
47
48 int
pthread_mutexattr_settype(pthread_mutexattr_t * attr,int type)49 pthread_mutexattr_settype (pthread_mutexattr_t *attr, int type)
50 {
51 if (!(type == PTHREAD_MUTEX_DEFAULT
52 || type == PTHREAD_MUTEX_NORMAL
53 || type == PTHREAD_MUTEX_ERRORCHECK
54 || type == PTHREAD_MUTEX_RECURSIVE))
55 return EINVAL;
56 *attr ^= (*attr ^ type)
57 & (PTHREAD_MUTEX_DEFAULT | PTHREAD_MUTEX_NORMAL
58 | PTHREAD_MUTEX_ERRORCHECK | PTHREAD_MUTEX_RECURSIVE);
59 return 0;
60 }
61
62 int
pthread_mutexattr_getrobust(const pthread_mutexattr_t * attr,int * robustp)63 pthread_mutexattr_getrobust (const pthread_mutexattr_t *attr, int *robustp)
64 {
65 *robustp = (*attr >> 2) & (PTHREAD_MUTEX_STALLED | PTHREAD_MUTEX_ROBUST);
66 return 0;
67 }
68
69 int
pthread_mutexattr_setrobust(pthread_mutexattr_t * attr,int robust)70 pthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int robust)
71 {
72 if (!(robust == PTHREAD_MUTEX_STALLED || robust == PTHREAD_MUTEX_ROBUST))
73 return EINVAL;
74 *attr ^= (*attr ^ (robust << 2))
75 & ((PTHREAD_MUTEX_STALLED | PTHREAD_MUTEX_ROBUST) << 2);
76 return 0;
77 }
78
79 int
pthread_mutexattr_destroy(pthread_mutexattr_t * attr _GL_UNUSED)80 pthread_mutexattr_destroy (pthread_mutexattr_t *attr _GL_UNUSED)
81 {
82 return 0;
83 }
84
85 #elif PTHREAD_MUTEXATTR_ROBUST_UNIMPLEMENTED
86
87 int
pthread_mutexattr_getrobust(const pthread_mutexattr_t * attr,int * robustp)88 pthread_mutexattr_getrobust (const pthread_mutexattr_t *attr, int *robustp)
89 {
90 *robustp = PTHREAD_MUTEX_STALLED;
91 return 0;
92 }
93
94 int
pthread_mutexattr_setrobust(pthread_mutexattr_t * attr,int robust)95 pthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int robust)
96 {
97 if (!(robust == PTHREAD_MUTEX_STALLED || robust == PTHREAD_MUTEX_ROBUST))
98 return EINVAL;
99 if (!(robust == PTHREAD_MUTEX_STALLED))
100 return ENOTSUP;
101 return 0;
102 }
103
104 #endif
105
106 #if (defined _WIN32 && ! defined __CYGWIN__) && USE_WINDOWS_THREADS
107 /* Use Windows threads. */
108
109 int
pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t * attr)110 pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
111 {
112 /* This implementation does not support PTHREAD_MUTEX_ERRORCHECK
113 and ignores the 'robust' attribute. */
114 if (attr != NULL
115 && (*attr & (PTHREAD_MUTEX_DEFAULT | PTHREAD_MUTEX_NORMAL
116 | PTHREAD_MUTEX_ERRORCHECK | PTHREAD_MUTEX_RECURSIVE))
117 == PTHREAD_MUTEX_RECURSIVE)
118 {
119 mutex->type = 2;
120 return glwthread_timedrecmutex_init (&mutex->u.u_timedrecmutex);
121 }
122 else
123 {
124 mutex->type = 1;
125 return glwthread_timedmutex_init (&mutex->u.u_timedmutex);
126 }
127 }
128
129 int
pthread_mutex_lock(pthread_mutex_t * mutex)130 pthread_mutex_lock (pthread_mutex_t *mutex)
131 {
132 switch (mutex->type)
133 {
134 case 1:
135 return glwthread_timedmutex_lock (&mutex->u.u_timedmutex);
136 case 2:
137 return glwthread_timedrecmutex_lock (&mutex->u.u_timedrecmutex);
138 default:
139 abort ();
140 }
141 }
142
143 int
pthread_mutex_trylock(pthread_mutex_t * mutex)144 pthread_mutex_trylock (pthread_mutex_t *mutex)
145 {
146 switch (mutex->type)
147 {
148 case 1:
149 return glwthread_timedmutex_trylock (&mutex->u.u_timedmutex);
150 case 2:
151 return glwthread_timedrecmutex_trylock (&mutex->u.u_timedrecmutex);
152 default:
153 abort ();
154 }
155 }
156
157 int
pthread_mutex_timedlock(pthread_mutex_t * mutex,const struct timespec * abstime)158 pthread_mutex_timedlock (pthread_mutex_t *mutex, const struct timespec *abstime)
159 {
160 switch (mutex->type)
161 {
162 case 1:
163 return glwthread_timedmutex_timedlock (&mutex->u.u_timedmutex, abstime);
164 case 2:
165 return glwthread_timedrecmutex_timedlock (&mutex->u.u_timedrecmutex,
166 abstime);
167 default:
168 abort ();
169 }
170 }
171
172 int
pthread_mutex_unlock(pthread_mutex_t * mutex)173 pthread_mutex_unlock (pthread_mutex_t *mutex)
174 {
175 switch (mutex->type)
176 {
177 case 1:
178 return glwthread_timedmutex_unlock (&mutex->u.u_timedmutex);
179 case 2:
180 return glwthread_timedrecmutex_unlock (&mutex->u.u_timedrecmutex);
181 default:
182 abort ();
183 }
184 }
185
186 int
pthread_mutex_destroy(pthread_mutex_t * mutex)187 pthread_mutex_destroy (pthread_mutex_t *mutex)
188 {
189 switch (mutex->type)
190 {
191 case 1:
192 return glwthread_timedmutex_destroy (&mutex->u.u_timedmutex);
193 case 2:
194 return glwthread_timedrecmutex_destroy (&mutex->u.u_timedrecmutex);
195 default:
196 abort ();
197 }
198 }
199
200 #elif HAVE_PTHREAD_H
201 /* Provide workarounds for POSIX threads. */
202
203 /* pthread_mutex_timedlock is defined by the 'pthread_mutex_timedlock'
204 module. */
205
206 #else
207 /* Provide a dummy implementation for single-threaded applications. */
208
209 int
pthread_mutex_init(pthread_mutex_t * mutex _GL_UNUSED,const pthread_mutexattr_t * attr _GL_UNUSED)210 pthread_mutex_init (pthread_mutex_t *mutex _GL_UNUSED,
211 const pthread_mutexattr_t *attr _GL_UNUSED)
212 {
213 /* MUTEX is never seriously used. */
214 return 0;
215 }
216
217 int
pthread_mutex_lock(pthread_mutex_t * mutex _GL_UNUSED)218 pthread_mutex_lock (pthread_mutex_t *mutex _GL_UNUSED)
219 {
220 /* There is only one thread, so it always gets the lock. This
221 implementation does not support PTHREAD_MUTEX_ERRORCHECK. */
222 return 0;
223 }
224
225 int
pthread_mutex_trylock(pthread_mutex_t * mutex _GL_UNUSED)226 pthread_mutex_trylock (pthread_mutex_t *mutex _GL_UNUSED)
227 {
228 /* There is only one thread, so it always gets the lock. This
229 implementation does not support PTHREAD_MUTEX_ERRORCHECK. */
230 return 0;
231 }
232
233 int
pthread_mutex_timedlock(pthread_mutex_t * mutex _GL_UNUSED,const struct timespec * abstime _GL_UNUSED)234 pthread_mutex_timedlock (pthread_mutex_t *mutex _GL_UNUSED,
235 const struct timespec *abstime _GL_UNUSED)
236 {
237 /* There is only one thread, so it always gets the lock. This
238 implementation does not support PTHREAD_MUTEX_ERRORCHECK. */
239 return 0;
240 }
241
242 int
pthread_mutex_unlock(pthread_mutex_t * mutex _GL_UNUSED)243 pthread_mutex_unlock (pthread_mutex_t *mutex _GL_UNUSED)
244 {
245 /* There is only one thread, so it always unlocks successfully.
246 This implementation does not support robust mutexes or
247 PTHREAD_MUTEX_ERRORCHECK. */
248 return 0;
249 }
250
251 int
pthread_mutex_destroy(pthread_mutex_t * mutex _GL_UNUSED)252 pthread_mutex_destroy (pthread_mutex_t *mutex _GL_UNUSED)
253 {
254 /* MUTEX is never seriously used. */
255 return 0;
256 }
257
258 #endif
259