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 __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_FAST_NP
: mutex_attr
->__mutexkind
;
34 mutex
->__m_owner
= NULL
;
37 strong_alias (__pthread_mutex_init
, pthread_mutex_init
)
39 int __pthread_mutex_destroy(pthread_mutex_t
* mutex
)
41 if (mutex
->__m_lock
.__status
!= 0) return EBUSY
;
44 strong_alias (__pthread_mutex_destroy
, pthread_mutex_destroy
)
46 int __pthread_mutex_trylock(pthread_mutex_t
* mutex
)
51 switch(mutex
->__m_kind
) {
52 case PTHREAD_MUTEX_FAST_NP
:
53 retcode
= __pthread_trylock(&mutex
->__m_lock
);
55 case PTHREAD_MUTEX_RECURSIVE_NP
:
57 if (mutex
->__m_owner
== self
) {
61 retcode
= __pthread_trylock(&mutex
->__m_lock
);
63 mutex
->__m_owner
= self
;
67 case PTHREAD_MUTEX_ERRORCHECK_NP
:
68 retcode
= __pthread_trylock(&mutex
->__m_lock
);
70 mutex
->__m_owner
= thread_self();
77 strong_alias (__pthread_mutex_trylock
, pthread_mutex_trylock
)
79 int __pthread_mutex_lock(pthread_mutex_t
* mutex
)
83 switch(mutex
->__m_kind
) {
84 case PTHREAD_MUTEX_FAST_NP
:
85 __pthread_lock(&mutex
->__m_lock
, NULL
);
87 case PTHREAD_MUTEX_RECURSIVE_NP
:
89 if (mutex
->__m_owner
== self
) {
93 __pthread_lock(&mutex
->__m_lock
, self
);
94 mutex
->__m_owner
= self
;
97 case PTHREAD_MUTEX_ERRORCHECK_NP
:
99 if (mutex
->__m_owner
== self
) return EDEADLK
;
100 __pthread_lock(&mutex
->__m_lock
, self
);
101 mutex
->__m_owner
= self
;
107 strong_alias (__pthread_mutex_lock
, pthread_mutex_lock
)
109 int __pthread_mutex_unlock(pthread_mutex_t
* mutex
)
111 switch (mutex
->__m_kind
) {
112 case PTHREAD_MUTEX_FAST_NP
:
113 __pthread_unlock(&mutex
->__m_lock
);
115 case PTHREAD_MUTEX_RECURSIVE_NP
:
116 if (mutex
->__m_count
> 0) {
120 mutex
->__m_owner
= NULL
;
121 __pthread_unlock(&mutex
->__m_lock
);
123 case PTHREAD_MUTEX_ERRORCHECK_NP
:
124 if (mutex
->__m_owner
!= thread_self() || mutex
->__m_lock
.__status
== 0)
126 mutex
->__m_owner
= NULL
;
127 __pthread_unlock(&mutex
->__m_lock
);
133 strong_alias (__pthread_mutex_unlock
, pthread_mutex_unlock
)
135 int __pthread_mutexattr_init(pthread_mutexattr_t
*attr
)
137 attr
->__mutexkind
= PTHREAD_MUTEX_FAST_NP
;
140 strong_alias (__pthread_mutexattr_init
, pthread_mutexattr_init
)
142 int __pthread_mutexattr_destroy(pthread_mutexattr_t
*attr
)
146 strong_alias (__pthread_mutexattr_destroy
, pthread_mutexattr_destroy
)
148 int __pthread_mutexattr_settype(pthread_mutexattr_t
*attr
, int kind
)
150 if (kind
!= PTHREAD_MUTEX_FAST_NP
151 && kind
!= PTHREAD_MUTEX_RECURSIVE_NP
152 && kind
!= PTHREAD_MUTEX_ERRORCHECK_NP
)
154 attr
->__mutexkind
= kind
;
157 weak_alias (__pthread_mutexattr_settype
, pthread_mutexattr_settype
)
158 strong_alias ( __pthread_mutexattr_settype
, __pthread_mutexattr_setkind_np
)
159 weak_alias (__pthread_mutexattr_setkind_np
, pthread_mutexattr_setkind_np
)
161 int __pthread_mutexattr_gettype(const pthread_mutexattr_t
*attr
, int *kind
)
163 *kind
= attr
->__mutexkind
;
166 weak_alias (__pthread_mutexattr_gettype
, pthread_mutexattr_gettype
)
167 strong_alias (__pthread_mutexattr_gettype
, __pthread_mutexattr_getkind_np
)
168 weak_alias (__pthread_mutexattr_getkind_np
, pthread_mutexattr_getkind_np
)
170 /* Once-only execution */
172 static pthread_mutex_t once_masterlock
= PTHREAD_MUTEX_INITIALIZER
;
173 static pthread_cond_t once_finished
= PTHREAD_COND_INITIALIZER
;
174 static int fork_generation
= 0; /* Child process increments this after fork. */
176 enum { NEVER
= 0, IN_PROGRESS
= 1, DONE
= 2 };
178 /* If a thread is canceled while calling the init_routine out of
179 pthread once, this handler will reset the once_control variable
180 to the NEVER state. */
182 static void pthread_once_cancelhandler(void *arg
)
184 pthread_once_t
*once_control
= arg
;
186 pthread_mutex_lock(&once_masterlock
);
187 *once_control
= NEVER
;
188 pthread_mutex_unlock(&once_masterlock
);
189 pthread_cond_broadcast(&once_finished
);
192 int __pthread_once(pthread_once_t
* once_control
, void (*init_routine
)(void))
194 /* flag for doing the condition broadcast outside of mutex */
197 /* Test without locking first for speed */
198 if (*once_control
== DONE
) return 0;
199 /* Lock and test again */
203 pthread_mutex_lock(&once_masterlock
);
205 /* If this object was left in an IN_PROGRESS state in a parent
206 process (indicated by stale generation field), reset it to NEVER. */
207 if ((*once_control
& 3) == IN_PROGRESS
&& (*once_control
& ~3) != fork_generation
)
208 *once_control
= NEVER
;
210 /* If init_routine is being called from another routine, wait until
212 while ((*once_control
& 3) == IN_PROGRESS
) {
213 pthread_cond_wait(&once_finished
, &once_masterlock
);
215 /* Here *once_control is stable and either NEVER or DONE. */
216 if (*once_control
== NEVER
) {
217 *once_control
= IN_PROGRESS
| fork_generation
;
218 pthread_mutex_unlock(&once_masterlock
);
219 pthread_cleanup_push(pthread_once_cancelhandler
, once_control
);
221 pthread_cleanup_pop(0);
222 pthread_mutex_lock(&once_masterlock
);
223 *once_control
= DONE
;
226 pthread_mutex_unlock(&once_masterlock
);
229 pthread_cond_broadcast(&once_finished
);
233 strong_alias (__pthread_once
, pthread_once
)
236 * Handle the state of the pthread_once mechanism across forks. The
237 * once_masterlock is acquired in the parent process prior to a fork to ensure
238 * that no thread is in the critical region protected by the lock. After the
239 * fork, the lock is released. In the child, the lock and the condition
240 * variable are simply reset. The child also increments its generation
241 * counter which lets pthread_once calls detect stale IN_PROGRESS states
242 * and reset them back to NEVER.
245 void __pthread_once_fork_prepare(void)
247 pthread_mutex_lock(&once_masterlock
);
250 void __pthread_once_fork_parent(void)
252 pthread_mutex_unlock(&once_masterlock
);
255 void __pthread_once_fork_child(void)
257 pthread_mutex_init(&once_masterlock
, NULL
);
258 pthread_cond_init(&once_finished
, NULL
);
259 if (fork_generation
<= INT_MAX
- 4)
260 fork_generation
+= 4; /* leave least significant two bits zero */