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