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. */
22 #include "internals.h"
27 int attribute_hidden
__pthread_mutex_init(pthread_mutex_t
* mutex
,
28 const pthread_mutexattr_t
* mutex_attr
)
30 __pthread_init_lock(&mutex
->__m_lock
);
32 mutex_attr
== NULL
? PTHREAD_MUTEX_TIMED_NP
: mutex_attr
->__mutexkind
;
34 mutex
->__m_owner
= NULL
;
37 strong_alias (__pthread_mutex_init
, pthread_mutex_init
)
39 int attribute_hidden
__pthread_mutex_destroy(pthread_mutex_t
* mutex
)
41 switch (mutex
->__m_kind
) {
42 case PTHREAD_MUTEX_ADAPTIVE_NP
:
43 case PTHREAD_MUTEX_RECURSIVE_NP
:
44 if ((mutex
->__m_lock
.__status
& 1) != 0)
47 case PTHREAD_MUTEX_ERRORCHECK_NP
:
48 case PTHREAD_MUTEX_TIMED_NP
:
49 if (mutex
->__m_lock
.__status
!= 0)
56 strong_alias (__pthread_mutex_destroy
, pthread_mutex_destroy
)
58 int attribute_hidden
__pthread_mutex_trylock(pthread_mutex_t
* mutex
)
63 switch(mutex
->__m_kind
) {
64 case PTHREAD_MUTEX_ADAPTIVE_NP
:
65 retcode
= __pthread_trylock(&mutex
->__m_lock
);
67 case PTHREAD_MUTEX_RECURSIVE_NP
:
69 if (mutex
->__m_owner
== self
) {
73 retcode
= __pthread_trylock(&mutex
->__m_lock
);
75 mutex
->__m_owner
= self
;
79 case PTHREAD_MUTEX_ERRORCHECK_NP
:
80 retcode
= __pthread_alt_trylock(&mutex
->__m_lock
);
82 mutex
->__m_owner
= thread_self();
85 case PTHREAD_MUTEX_TIMED_NP
:
86 retcode
= __pthread_alt_trylock(&mutex
->__m_lock
);
92 strong_alias (__pthread_mutex_trylock
, pthread_mutex_trylock
)
94 int attribute_hidden
__pthread_mutex_lock(pthread_mutex_t
* mutex
)
98 switch(mutex
->__m_kind
) {
99 case PTHREAD_MUTEX_ADAPTIVE_NP
:
100 __pthread_lock(&mutex
->__m_lock
, NULL
);
102 case PTHREAD_MUTEX_RECURSIVE_NP
:
103 self
= thread_self();
104 if (mutex
->__m_owner
== self
) {
108 __pthread_lock(&mutex
->__m_lock
, self
);
109 mutex
->__m_owner
= self
;
110 mutex
->__m_count
= 0;
112 case PTHREAD_MUTEX_ERRORCHECK_NP
:
113 self
= thread_self();
114 if (mutex
->__m_owner
== self
) return EDEADLK
;
115 __pthread_alt_lock(&mutex
->__m_lock
, self
);
116 mutex
->__m_owner
= self
;
118 case PTHREAD_MUTEX_TIMED_NP
:
119 __pthread_alt_lock(&mutex
->__m_lock
, NULL
);
125 strong_alias (__pthread_mutex_lock
, pthread_mutex_lock
)
127 int pthread_mutex_timedlock (pthread_mutex_t
*mutex
,
128 const struct timespec
*abstime
)
133 if (__builtin_expect (abstime
->tv_nsec
, 0) < 0
134 || __builtin_expect (abstime
->tv_nsec
, 0) >= 1000000000)
137 switch(mutex
->__m_kind
) {
138 case PTHREAD_MUTEX_ADAPTIVE_NP
:
139 __pthread_lock(&mutex
->__m_lock
, NULL
);
141 case PTHREAD_MUTEX_RECURSIVE_NP
:
142 self
= thread_self();
143 if (mutex
->__m_owner
== self
) {
147 __pthread_lock(&mutex
->__m_lock
, self
);
148 mutex
->__m_owner
= self
;
149 mutex
->__m_count
= 0;
151 case PTHREAD_MUTEX_ERRORCHECK_NP
:
152 self
= thread_self();
153 if (mutex
->__m_owner
== self
) return EDEADLK
;
154 res
= __pthread_alt_timedlock(&mutex
->__m_lock
, self
, abstime
);
157 mutex
->__m_owner
= self
;
161 case PTHREAD_MUTEX_TIMED_NP
:
162 /* Only this type supports timed out lock. */
163 return (__pthread_alt_timedlock(&mutex
->__m_lock
, NULL
, abstime
)
170 int attribute_hidden
__pthread_mutex_unlock(pthread_mutex_t
* mutex
)
172 switch (mutex
->__m_kind
) {
173 case PTHREAD_MUTEX_ADAPTIVE_NP
:
174 __pthread_unlock(&mutex
->__m_lock
);
176 case PTHREAD_MUTEX_RECURSIVE_NP
:
177 if (mutex
->__m_owner
!= thread_self())
179 if (mutex
->__m_count
> 0) {
183 mutex
->__m_owner
= NULL
;
184 __pthread_unlock(&mutex
->__m_lock
);
186 case PTHREAD_MUTEX_ERRORCHECK_NP
:
187 if (mutex
->__m_owner
!= thread_self() || mutex
->__m_lock
.__status
== 0)
189 mutex
->__m_owner
= NULL
;
190 __pthread_alt_unlock(&mutex
->__m_lock
);
192 case PTHREAD_MUTEX_TIMED_NP
:
193 __pthread_alt_unlock(&mutex
->__m_lock
);
199 strong_alias (__pthread_mutex_unlock
, pthread_mutex_unlock
)
201 int attribute_hidden
__pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
203 attr
->__mutexkind
= PTHREAD_MUTEX_TIMED_NP
;
206 strong_alias(__pthread_mutexattr_init
,pthread_mutexattr_init
)
208 int attribute_hidden
__pthread_mutexattr_destroy(pthread_mutexattr_t
*attr attribute_unused
)
212 strong_alias(__pthread_mutexattr_destroy
,pthread_mutexattr_destroy
)
214 int attribute_hidden
__pthread_mutexattr_settype(pthread_mutexattr_t
*attr
, int kind
)
216 if (kind
!= PTHREAD_MUTEX_ADAPTIVE_NP
217 && kind
!= PTHREAD_MUTEX_RECURSIVE_NP
218 && kind
!= PTHREAD_MUTEX_ERRORCHECK_NP
219 && kind
!= PTHREAD_MUTEX_TIMED_NP
)
221 attr
->__mutexkind
= kind
;
224 strong_alias(__pthread_mutexattr_settype
,pthread_mutexattr_settype
)
225 strong_alias (__pthread_mutexattr_settype
, __pthread_mutexattr_setkind_np
)
226 weak_alias (__pthread_mutexattr_setkind_np
, pthread_mutexattr_setkind_np
)
228 int __pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
, int *kind
) attribute_hidden
;
229 int __pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
, int *kind
)
231 *kind
= attr
->__mutexkind
;
234 weak_alias (__pthread_mutexattr_gettype
, pthread_mutexattr_gettype
)
235 strong_alias (__pthread_mutexattr_gettype
, __pthread_mutexattr_getkind_np
)
236 weak_alias (__pthread_mutexattr_getkind_np
, pthread_mutexattr_getkind_np
)
238 int __pthread_mutexattr_getpshared (const pthread_mutexattr_t
*attr attribute_unused
,
239 int *pshared
) attribute_hidden
;
240 int __pthread_mutexattr_getpshared (const pthread_mutexattr_t
*attr attribute_unused
,
243 *pshared
= PTHREAD_PROCESS_PRIVATE
;
246 weak_alias (__pthread_mutexattr_getpshared
, pthread_mutexattr_getpshared
)
248 int __pthread_mutexattr_setpshared (pthread_mutexattr_t
*attr attribute_unused
, int pshared
) attribute_hidden
;
249 int __pthread_mutexattr_setpshared (pthread_mutexattr_t
*attr attribute_unused
, int pshared
)
251 if (pshared
!= PTHREAD_PROCESS_PRIVATE
&& pshared
!= PTHREAD_PROCESS_SHARED
)
254 /* For now it is not possible to shared a conditional variable. */
255 if (pshared
!= PTHREAD_PROCESS_PRIVATE
)
260 weak_alias (__pthread_mutexattr_setpshared
, pthread_mutexattr_setpshared
)
262 /* Once-only execution */
264 static pthread_mutex_t once_masterlock
= PTHREAD_MUTEX_INITIALIZER
;
265 static pthread_cond_t once_finished
= PTHREAD_COND_INITIALIZER
;
266 static int fork_generation
= 0; /* Child process increments this after fork. */
268 enum { NEVER
= 0, IN_PROGRESS
= 1, DONE
= 2 };
270 /* If a thread is canceled while calling the init_routine out of
271 pthread once, this handler will reset the once_control variable
272 to the NEVER state. */
274 static void pthread_once_cancelhandler(void *arg
)
276 pthread_once_t
*once_control
= arg
;
278 __pthread_mutex_lock(&once_masterlock
);
279 *once_control
= NEVER
;
280 __pthread_mutex_unlock(&once_masterlock
);
281 pthread_cond_broadcast(&once_finished
);
284 int __pthread_once(pthread_once_t
* once_control
, void (*init_routine
)(void))
286 /* flag for doing the condition broadcast outside of mutex */
289 /* Test without locking first for speed */
290 if (*once_control
== DONE
) {
291 READ_MEMORY_BARRIER();
294 /* Lock and test again */
298 __pthread_mutex_lock(&once_masterlock
);
300 /* If this object was left in an IN_PROGRESS state in a parent
301 process (indicated by stale generation field), reset it to NEVER. */
302 if ((*once_control
& 3) == IN_PROGRESS
&& (*once_control
& ~3) != fork_generation
)
303 *once_control
= NEVER
;
305 /* If init_routine is being called from another routine, wait until
307 while ((*once_control
& 3) == IN_PROGRESS
) {
308 pthread_cond_wait(&once_finished
, &once_masterlock
);
310 /* Here *once_control is stable and either NEVER or DONE. */
311 if (*once_control
== NEVER
) {
312 *once_control
= IN_PROGRESS
| fork_generation
;
313 __pthread_mutex_unlock(&once_masterlock
);
314 pthread_cleanup_push(pthread_once_cancelhandler
, once_control
);
316 pthread_cleanup_pop(0);
317 __pthread_mutex_lock(&once_masterlock
);
318 WRITE_MEMORY_BARRIER();
319 *once_control
= DONE
;
322 __pthread_mutex_unlock(&once_masterlock
);
325 pthread_cond_broadcast(&once_finished
);
329 strong_alias (__pthread_once
, pthread_once
)
332 * Handle the state of the pthread_once mechanism across forks. The
333 * once_masterlock is acquired in the parent process prior to a fork to ensure
334 * that no thread is in the critical region protected by the lock. After the
335 * fork, the lock is released. In the child, the lock and the condition
336 * variable are simply reset. The child also increments its generation
337 * counter which lets pthread_once calls detect stale IN_PROGRESS states
338 * and reset them back to NEVER.
341 void __pthread_once_fork_prepare(void);
342 void __pthread_once_fork_prepare(void)
344 __pthread_mutex_lock(&once_masterlock
);
347 void __pthread_once_fork_parent(void);
348 void __pthread_once_fork_parent(void)
350 __pthread_mutex_unlock(&once_masterlock
);
353 void __pthread_once_fork_child(void);
354 void __pthread_once_fork_child(void)
356 __pthread_mutex_init(&once_masterlock
, NULL
);
357 pthread_cond_init(&once_finished
, NULL
);
358 if (fork_generation
<= INT_MAX
- 4)
359 fork_generation
+= 4; /* leave least significant two bits zero */