1 /* Linuxthreads - a simple clone()-based implementation of Posix */
2 /* threads for Linux. */
3 /* Copyright (C) 1996 Xavier Leroy (Xavier.Leroy@inria.fr) */
4 /* and Pavel Krauz (krauz@fsid.cvut.cz). */
6 /* This program is free software; you can redistribute it and/or */
7 /* modify it under the terms of the GNU Library General Public License */
8 /* as published by the Free Software Foundation; either version 2 */
9 /* of the License, or (at your option) any later version. */
11 /* This program is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU Library General Public License for more details. */
16 /* Condition variables */
23 #include "internals.h"
28 int pthread_cond_init(pthread_cond_t *cond,
29 const pthread_condattr_t *cond_attr attribute_unused)
31 __pthread_init_lock(&cond->__c_lock);
32 cond->__c_waiting = NULL;
35 libpthread_hidden_def(pthread_cond_init)
37 int pthread_cond_destroy(pthread_cond_t *cond)
39 if (cond->__c_waiting != NULL) return EBUSY;
42 libpthread_hidden_def(pthread_cond_destroy)
44 /* Function called by pthread_cancel to remove the thread from
45 waiting on a condition variable queue. */
47 static int cond_extricate_func(void *obj, pthread_descr th)
49 volatile pthread_descr self = thread_self();
50 pthread_cond_t *cond = obj;
53 __pthread_lock(&cond->__c_lock, self);
54 did_remove = remove_from_queue(&cond->__c_waiting, th);
55 __pthread_unlock(&cond->__c_lock);
60 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
62 volatile pthread_descr self = thread_self();
63 pthread_extricate_if extr;
64 int already_canceled = 0;
65 int spurious_wakeup_count;
67 /* Check whether the mutex is locked and owned by this thread. */
68 if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
69 && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
70 && mutex->__m_owner != self)
73 /* Set up extrication interface */
74 extr.pu_object = cond;
75 extr.pu_extricate_func = cond_extricate_func;
77 /* Register extrication interface */
78 THREAD_SETMEM(self, p_condvar_avail, 0);
79 __pthread_set_own_extricate_if(self, &extr);
81 /* Atomically enqueue thread for waiting, but only if it is not
82 canceled. If the thread is canceled, then it will fall through the
83 suspend call below, and then call pthread_exit without
84 having to worry about whether it is still on the condition variable queue.
85 This depends on pthread_cancel setting p_canceled before calling the
86 extricate function. */
88 __pthread_lock(&cond->__c_lock, self);
89 if (!(THREAD_GETMEM(self, p_canceled)
90 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
91 enqueue(&cond->__c_waiting, self);
94 __pthread_unlock(&cond->__c_lock);
96 if (already_canceled) {
97 __pthread_set_own_extricate_if(self, 0);
98 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
101 __pthread_mutex_unlock(mutex);
103 spurious_wakeup_count = 0;
107 if (THREAD_GETMEM(self, p_condvar_avail) == 0
108 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
109 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
111 /* Count resumes that don't belong to us. */
112 spurious_wakeup_count++;
118 __pthread_set_own_extricate_if(self, 0);
120 /* Check for cancellation again, to provide correct cancellation
123 if (THREAD_GETMEM(self, p_woken_by_cancel)
124 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
125 THREAD_SETMEM(self, p_woken_by_cancel, 0);
126 __pthread_mutex_lock(mutex);
127 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
130 /* Put back any resumes we caught that don't belong to us. */
131 while (spurious_wakeup_count--)
134 __pthread_mutex_lock(mutex);
137 libpthread_hidden_def(pthread_cond_wait)
140 pthread_cond_timedwait_relative(pthread_cond_t *cond,
141 pthread_mutex_t *mutex,
142 const struct timespec * abstime)
144 volatile pthread_descr self = thread_self();
145 int already_canceled = 0;
146 pthread_extricate_if extr;
147 int spurious_wakeup_count;
149 /* Check whether the mutex is locked and owned by this thread. */
150 if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
151 && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
152 && mutex->__m_owner != self)
155 /* Set up extrication interface */
156 extr.pu_object = cond;
157 extr.pu_extricate_func = cond_extricate_func;
159 /* Register extrication interface */
160 THREAD_SETMEM(self, p_condvar_avail, 0);
161 __pthread_set_own_extricate_if(self, &extr);
163 /* Enqueue to wait on the condition and check for cancellation. */
164 __pthread_lock(&cond->__c_lock, self);
165 if (!(THREAD_GETMEM(self, p_canceled)
166 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
167 enqueue(&cond->__c_waiting, self);
169 already_canceled = 1;
170 __pthread_unlock(&cond->__c_lock);
172 if (already_canceled) {
173 __pthread_set_own_extricate_if(self, 0);
174 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
177 __pthread_mutex_unlock(mutex);
179 spurious_wakeup_count = 0;
182 if (!timedsuspend(self, abstime)) {
185 /* __pthread_lock will queue back any spurious restarts that
188 __pthread_lock(&cond->__c_lock, self);
189 was_on_queue = remove_from_queue(&cond->__c_waiting, self);
190 __pthread_unlock(&cond->__c_lock);
193 __pthread_set_own_extricate_if(self, 0);
194 __pthread_mutex_lock(mutex);
198 /* Eat the outstanding restart() from the signaller */
202 if (THREAD_GETMEM(self, p_condvar_avail) == 0
203 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
204 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
206 /* Count resumes that don't belong to us. */
207 spurious_wakeup_count++;
213 __pthread_set_own_extricate_if(self, 0);
215 /* The remaining logic is the same as in other cancellable waits,
216 such as pthread_join sem_wait or pthread_cond wait. */
218 if (THREAD_GETMEM(self, p_woken_by_cancel)
219 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
220 THREAD_SETMEM(self, p_woken_by_cancel, 0);
221 __pthread_mutex_lock(mutex);
222 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
225 /* Put back any resumes we caught that don't belong to us. */
226 while (spurious_wakeup_count--)
229 __pthread_mutex_lock(mutex);
233 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
234 const struct timespec * abstime)
236 /* Indirect call through pointer! */
237 return pthread_cond_timedwait_relative(cond, mutex, abstime);
239 libpthread_hidden_def(pthread_cond_timedwait)
241 int pthread_cond_signal(pthread_cond_t *cond)
245 __pthread_lock(&cond->__c_lock, NULL);
246 th = dequeue(&cond->__c_waiting);
247 __pthread_unlock(&cond->__c_lock);
249 th->p_condvar_avail = 1;
250 WRITE_MEMORY_BARRIER();
255 libpthread_hidden_def(pthread_cond_signal)
257 int pthread_cond_broadcast(pthread_cond_t *cond)
259 pthread_descr tosignal, th;
261 __pthread_lock(&cond->__c_lock, NULL);
262 /* Copy the current state of the waiting queue and empty it */
263 tosignal = cond->__c_waiting;
264 cond->__c_waiting = NULL;
265 __pthread_unlock(&cond->__c_lock);
266 /* Now signal each process in the queue */
267 while ((th = dequeue(&tosignal)) != NULL) {
268 th->p_condvar_avail = 1;
269 WRITE_MEMORY_BARRIER();
274 libpthread_hidden_def(pthread_cond_broadcast)
276 int pthread_condattr_init(pthread_condattr_t *attr attribute_unused)
280 libpthread_hidden_def(pthread_condattr_init)
282 int pthread_condattr_destroy(pthread_condattr_t *attr attribute_unused)
286 libpthread_hidden_def(pthread_condattr_destroy)
288 int pthread_condattr_getpshared (const pthread_condattr_t *attr attribute_unused, int *pshared)
290 *pshared = PTHREAD_PROCESS_PRIVATE;
294 int pthread_condattr_setpshared (pthread_condattr_t *attr attribute_unused, int pshared)
296 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
299 /* For now it is not possible to shared a conditional variable. */
300 if (pshared != PTHREAD_PROCESS_PRIVATE)