1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
5 /* This program is free software; you can redistribute it and/or */
6 /* modify it under the terms of the GNU Library General Public License */
7 /* as published by the Free Software Foundation; either version 2 */
8 /* of the License, or (at your option) any later version. */
10 /* This program 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 */
13 /* GNU Library General Public License for more details. */
17 #include <bits/libc-lock.h>
23 #include "internals.h"
28 int __pthread_mutex_init(pthread_mutex_t
* mutex
,
29 const pthread_mutexattr_t
* mutex_attr
)
31 __pthread_init_lock(&mutex
->__m_lock
);
33 mutex_attr
== NULL
? PTHREAD_MUTEX_TIMED_NP
: mutex_attr
->__mutexkind
;
35 mutex
->__m_owner
= NULL
;
38 strong_alias (__pthread_mutex_init
, pthread_mutex_init
)
40 int __pthread_mutex_destroy(pthread_mutex_t
* mutex
)
42 switch (mutex
->__m_kind
) {
43 case PTHREAD_MUTEX_ADAPTIVE_NP
:
44 case PTHREAD_MUTEX_RECURSIVE_NP
:
45 if ((mutex
->__m_lock
.__status
& 1) != 0)
48 case PTHREAD_MUTEX_ERRORCHECK_NP
:
49 case PTHREAD_MUTEX_TIMED_NP
:
50 if (mutex
->__m_lock
.__status
!= 0)
57 strong_alias (__pthread_mutex_destroy
, pthread_mutex_destroy
)
59 int __pthread_mutex_trylock(pthread_mutex_t
* mutex
)
64 switch(mutex
->__m_kind
) {
65 case PTHREAD_MUTEX_ADAPTIVE_NP
:
66 retcode
= __pthread_trylock(&mutex
->__m_lock
);
68 case PTHREAD_MUTEX_RECURSIVE_NP
:
70 if (mutex
->__m_owner
== self
) {
74 retcode
= __pthread_trylock(&mutex
->__m_lock
);
76 mutex
->__m_owner
= self
;
80 case PTHREAD_MUTEX_ERRORCHECK_NP
:
81 retcode
= __pthread_alt_trylock(&mutex
->__m_lock
);
83 mutex
->__m_owner
= thread_self();
86 case PTHREAD_MUTEX_TIMED_NP
:
87 retcode
= __pthread_alt_trylock(&mutex
->__m_lock
);
93 strong_alias (__pthread_mutex_trylock
, pthread_mutex_trylock
)
95 int __pthread_mutex_lock(pthread_mutex_t
* mutex
)
99 switch(mutex
->__m_kind
) {
100 case PTHREAD_MUTEX_ADAPTIVE_NP
:
101 __pthread_lock(&mutex
->__m_lock
, NULL
);
103 case PTHREAD_MUTEX_RECURSIVE_NP
:
104 self
= thread_self();
105 if (mutex
->__m_owner
== self
) {
109 __pthread_lock(&mutex
->__m_lock
, self
);
110 mutex
->__m_owner
= self
;
111 mutex
->__m_count
= 0;
113 case PTHREAD_MUTEX_ERRORCHECK_NP
:
114 self
= thread_self();
115 if (mutex
->__m_owner
== self
) return EDEADLK
;
116 __pthread_alt_lock(&mutex
->__m_lock
, self
);
117 mutex
->__m_owner
= self
;
119 case PTHREAD_MUTEX_TIMED_NP
:
120 __pthread_alt_lock(&mutex
->__m_lock
, NULL
);
126 strong_alias (__pthread_mutex_lock
, pthread_mutex_lock
)
128 int __pthread_mutex_timedlock (pthread_mutex_t
*mutex
,
129 const struct timespec
*abstime
)
134 if (__builtin_expect (abstime
->tv_nsec
, 0) < 0
135 || __builtin_expect (abstime
->tv_nsec
, 0) >= 1000000000)
138 switch(mutex
->__m_kind
) {
139 case PTHREAD_MUTEX_ADAPTIVE_NP
:
140 __pthread_lock(&mutex
->__m_lock
, NULL
);
142 case PTHREAD_MUTEX_RECURSIVE_NP
:
143 self
= thread_self();
144 if (mutex
->__m_owner
== self
) {
148 __pthread_lock(&mutex
->__m_lock
, self
);
149 mutex
->__m_owner
= self
;
150 mutex
->__m_count
= 0;
152 case PTHREAD_MUTEX_ERRORCHECK_NP
:
153 self
= thread_self();
154 if (mutex
->__m_owner
== self
) return EDEADLK
;
155 res
= __pthread_alt_timedlock(&mutex
->__m_lock
, self
, abstime
);
158 mutex
->__m_owner
= self
;
162 case PTHREAD_MUTEX_TIMED_NP
:
163 /* Only this type supports timed out lock. */
164 return (__pthread_alt_timedlock(&mutex
->__m_lock
, NULL
, abstime
)
170 strong_alias (__pthread_mutex_timedlock
, pthread_mutex_timedlock
)
172 int __pthread_mutex_unlock(pthread_mutex_t
* mutex
)
174 switch (mutex
->__m_kind
) {
175 case PTHREAD_MUTEX_ADAPTIVE_NP
:
176 __pthread_unlock(&mutex
->__m_lock
);
178 case PTHREAD_MUTEX_RECURSIVE_NP
:
179 if (mutex
->__m_owner
!= thread_self())
181 if (mutex
->__m_count
> 0) {
185 mutex
->__m_owner
= NULL
;
186 __pthread_unlock(&mutex
->__m_lock
);
188 case PTHREAD_MUTEX_ERRORCHECK_NP
:
189 if (mutex
->__m_owner
!= thread_self() || mutex
->__m_lock
.__status
== 0)
191 mutex
->__m_owner
= NULL
;
192 __pthread_alt_unlock(&mutex
->__m_lock
);
194 case PTHREAD_MUTEX_TIMED_NP
:
195 __pthread_alt_unlock(&mutex
->__m_lock
);
201 strong_alias (__pthread_mutex_unlock
, pthread_mutex_unlock
)
203 int __pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
205 attr
->__mutexkind
= PTHREAD_MUTEX_TIMED_NP
;
208 strong_alias (__pthread_mutexattr_init
, pthread_mutexattr_init
)
210 int __pthread_mutexattr_destroy(pthread_mutexattr_t
*attr
)
214 strong_alias (__pthread_mutexattr_destroy
, pthread_mutexattr_destroy
)
216 int __pthread_mutexattr_settype(pthread_mutexattr_t
*attr
, int kind
)
218 if (kind
!= PTHREAD_MUTEX_ADAPTIVE_NP
219 && kind
!= PTHREAD_MUTEX_RECURSIVE_NP
220 && kind
!= PTHREAD_MUTEX_ERRORCHECK_NP
221 && kind
!= PTHREAD_MUTEX_TIMED_NP
)
223 attr
->__mutexkind
= kind
;
226 weak_alias (__pthread_mutexattr_settype
, pthread_mutexattr_settype
)
227 strong_alias ( __pthread_mutexattr_settype
, __pthread_mutexattr_setkind_np
)
228 weak_alias (__pthread_mutexattr_setkind_np
, pthread_mutexattr_setkind_np
)
230 int __pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
, int *kind
)
232 *kind
= attr
->__mutexkind
;
235 weak_alias (__pthread_mutexattr_gettype
, pthread_mutexattr_gettype
)
236 strong_alias (__pthread_mutexattr_gettype
, __pthread_mutexattr_getkind_np
)
237 weak_alias (__pthread_mutexattr_getkind_np
, pthread_mutexattr_getkind_np
)
239 int __pthread_mutexattr_getpshared (const pthread_mutexattr_t
*attr
,
242 *pshared
= PTHREAD_PROCESS_PRIVATE
;
245 weak_alias (__pthread_mutexattr_getpshared
, pthread_mutexattr_getpshared
)
247 int __pthread_mutexattr_setpshared (pthread_mutexattr_t
*attr
, int pshared
)
249 if (pshared
!= PTHREAD_PROCESS_PRIVATE
&& pshared
!= PTHREAD_PROCESS_SHARED
)
252 /* For now it is not possible to shared a conditional variable. */
253 if (pshared
!= PTHREAD_PROCESS_PRIVATE
)
258 weak_alias (__pthread_mutexattr_setpshared
, pthread_mutexattr_setpshared
)
260 /* Once-only execution */
262 static pthread_mutex_t once_masterlock
= PTHREAD_MUTEX_INITIALIZER
;
263 static pthread_cond_t once_finished
= PTHREAD_COND_INITIALIZER
;
264 static int fork_generation
= 0; /* Child process increments this after fork. */
266 enum { NEVER
= 0, IN_PROGRESS
= 1, DONE
= 2 };
268 /* If a thread is canceled while calling the init_routine out of
269 pthread once, this handler will reset the once_control variable
270 to the NEVER state. */
272 static void pthread_once_cancelhandler(void *arg
)
274 pthread_once_t
*once_control
= arg
;
276 pthread_mutex_lock(&once_masterlock
);
277 *once_control
= NEVER
;
278 pthread_mutex_unlock(&once_masterlock
);
279 pthread_cond_broadcast(&once_finished
);
282 int __pthread_once(pthread_once_t
* once_control
, void (*init_routine
)(void))
284 /* flag for doing the condition broadcast outside of mutex */
287 /* Test without locking first for speed */
288 if (*once_control
== DONE
) {
289 READ_MEMORY_BARRIER();
292 /* Lock and test again */
296 pthread_mutex_lock(&once_masterlock
);
298 /* If this object was left in an IN_PROGRESS state in a parent
299 process (indicated by stale generation field), reset it to NEVER. */
300 if ((*once_control
& 3) == IN_PROGRESS
&& (*once_control
& ~3) != fork_generation
)
301 *once_control
= NEVER
;
303 /* If init_routine is being called from another routine, wait until
305 while ((*once_control
& 3) == IN_PROGRESS
) {
306 pthread_cond_wait(&once_finished
, &once_masterlock
);
308 /* Here *once_control is stable and either NEVER or DONE. */
309 if (*once_control
== NEVER
) {
310 *once_control
= IN_PROGRESS
| fork_generation
;
311 pthread_mutex_unlock(&once_masterlock
);
312 pthread_cleanup_push(pthread_once_cancelhandler
, once_control
);
314 pthread_cleanup_pop(0);
315 pthread_mutex_lock(&once_masterlock
);
316 WRITE_MEMORY_BARRIER();
317 *once_control
= DONE
;
320 pthread_mutex_unlock(&once_masterlock
);
323 pthread_cond_broadcast(&once_finished
);
327 strong_alias (__pthread_once
, pthread_once
)
330 * Handle the state of the pthread_once mechanism across forks. The
331 * once_masterlock is acquired in the parent process prior to a fork to ensure
332 * that no thread is in the critical region protected by the lock. After the
333 * fork, the lock is released. In the child, the lock and the condition
334 * variable are simply reset. The child also increments its generation
335 * counter which lets pthread_once calls detect stale IN_PROGRESS states
336 * and reset them back to NEVER.
339 void __pthread_once_fork_prepare(void)
341 pthread_mutex_lock(&once_masterlock
);
344 void __pthread_once_fork_parent(void)
346 pthread_mutex_unlock(&once_masterlock
);
349 void __pthread_once_fork_child(void)
351 pthread_mutex_init(&once_masterlock
, NULL
);
352 pthread_cond_init(&once_finished
, NULL
);
353 if (fork_generation
<= INT_MAX
- 4)
354 fork_generation
+= 4; /* leave least significant two bits zero */