Update.
[glibc.git] / linuxthreads / condvar.c
blobfd0db50fa20df273044d4c81607888ae61d8974e
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). */
5 /* */
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. */
10 /* */
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 */
18 #include <errno.h>
19 #include <sched.h>
20 #include <stddef.h>
21 #include <sys/time.h>
22 #include "pthread.h"
23 #include "internals.h"
24 #include "spinlock.h"
25 #include "queue.h"
26 #include "restart.h"
28 int pthread_cond_init(pthread_cond_t *cond,
29 const pthread_condattr_t *cond_attr)
31 __pthread_init_lock(&cond->__c_lock);
32 cond->__c_waiting = NULL;
33 return 0;
36 int pthread_cond_destroy(pthread_cond_t *cond)
38 if (cond->__c_waiting != NULL) return EBUSY;
39 return 0;
42 /* Function called by pthread_cancel to remove the thread from
43 waiting on a condition variable queue. */
45 static int cond_extricate_func(void *obj, pthread_descr th)
47 volatile pthread_descr self = thread_self();
48 pthread_cond_t *cond = obj;
49 int did_remove = 0;
51 __pthread_lock(&cond->__c_lock, self);
52 did_remove = remove_from_queue(&cond->__c_waiting, th);
53 __pthread_unlock(&cond->__c_lock);
55 return did_remove;
58 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
60 volatile pthread_descr self = thread_self();
61 pthread_extricate_if extr;
62 int already_canceled = 0;
63 int spurious_wakeup_count;
65 /* Check whether the mutex is locked and owned by this thread. */
66 if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
67 && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
68 && mutex->__m_owner != self)
69 return EINVAL;
71 /* Set up extrication interface */
72 extr.pu_object = cond;
73 extr.pu_extricate_func = cond_extricate_func;
75 /* Register extrication interface */
76 THREAD_SETMEM(self, p_condvar_avail, 0);
77 __pthread_set_own_extricate_if(self, &extr);
79 /* Atomically enqueue thread for waiting, but only if it is not
80 canceled. If the thread is canceled, then it will fall through the
81 suspend call below, and then call pthread_exit without
82 having to worry about whether it is still on the condition variable queue.
83 This depends on pthread_cancel setting p_canceled before calling the
84 extricate function. */
86 __pthread_lock(&cond->__c_lock, self);
87 if (!(THREAD_GETMEM(self, p_canceled)
88 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
89 enqueue(&cond->__c_waiting, self);
90 else
91 already_canceled = 1;
92 __pthread_unlock(&cond->__c_lock);
94 if (already_canceled) {
95 __pthread_set_own_extricate_if(self, 0);
96 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
99 pthread_mutex_unlock(mutex);
101 spurious_wakeup_count = 0;
102 while (1)
104 suspend(self);
105 if (THREAD_GETMEM(self, p_condvar_avail) == 0
106 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
107 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
109 /* Count resumes that don't belong to us. */
110 spurious_wakeup_count++;
111 continue;
113 break;
116 __pthread_set_own_extricate_if(self, 0);
118 /* Check for cancellation again, to provide correct cancellation
119 point behavior */
121 if (THREAD_GETMEM(self, p_woken_by_cancel)
122 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
123 THREAD_SETMEM(self, p_woken_by_cancel, 0);
124 pthread_mutex_lock(mutex);
125 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
128 /* Put back any resumes we caught that don't belong to us. */
129 while (spurious_wakeup_count--)
130 restart(self);
132 pthread_mutex_lock(mutex);
133 return 0;
136 static int
137 pthread_cond_timedwait_relative(pthread_cond_t *cond,
138 pthread_mutex_t *mutex,
139 const struct timespec * abstime)
141 volatile pthread_descr self = thread_self();
142 int already_canceled = 0;
143 pthread_extricate_if extr;
144 int spurious_wakeup_count;
146 /* Check whether the mutex is locked and owned by this thread. */
147 if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP
148 && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP
149 && mutex->__m_owner != self)
150 return EINVAL;
152 /* Set up extrication interface */
153 extr.pu_object = cond;
154 extr.pu_extricate_func = cond_extricate_func;
156 /* Register extrication interface */
157 THREAD_SETMEM(self, p_condvar_avail, 0);
158 __pthread_set_own_extricate_if(self, &extr);
160 /* Enqueue to wait on the condition and check for cancellation. */
161 __pthread_lock(&cond->__c_lock, self);
162 if (!(THREAD_GETMEM(self, p_canceled)
163 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
164 enqueue(&cond->__c_waiting, self);
165 else
166 already_canceled = 1;
167 __pthread_unlock(&cond->__c_lock);
169 if (already_canceled) {
170 __pthread_set_own_extricate_if(self, 0);
171 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
174 pthread_mutex_unlock(mutex);
176 spurious_wakeup_count = 0;
177 while (1)
179 if (!timedsuspend(self, abstime)) {
180 int was_on_queue;
182 /* __pthread_lock will queue back any spurious restarts that
183 may happen to it. */
185 __pthread_lock(&cond->__c_lock, self);
186 was_on_queue = remove_from_queue(&cond->__c_waiting, self);
187 __pthread_unlock(&cond->__c_lock);
189 if (was_on_queue) {
190 __pthread_set_own_extricate_if(self, 0);
191 pthread_mutex_lock(mutex);
192 return ETIMEDOUT;
195 /* Eat the outstanding restart() from the signaller */
196 suspend(self);
199 if (THREAD_GETMEM(self, p_condvar_avail) == 0
200 && (THREAD_GETMEM(self, p_woken_by_cancel) == 0
201 || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE))
203 /* Count resumes that don't belong to us. */
204 spurious_wakeup_count++;
205 continue;
207 break;
210 __pthread_set_own_extricate_if(self, 0);
212 /* The remaining logic is the same as in other cancellable waits,
213 such as pthread_join sem_wait or pthread_cond wait. */
215 if (THREAD_GETMEM(self, p_woken_by_cancel)
216 && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
217 THREAD_SETMEM(self, p_woken_by_cancel, 0);
218 pthread_mutex_lock(mutex);
219 __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
222 /* Put back any resumes we caught that don't belong to us. */
223 while (spurious_wakeup_count--)
224 restart(self);
226 pthread_mutex_lock(mutex);
227 return 0;
230 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
231 const struct timespec * abstime)
233 /* Indirect call through pointer! */
234 return pthread_cond_timedwait_relative(cond, mutex, abstime);
237 int pthread_cond_signal(pthread_cond_t *cond)
239 pthread_descr th;
241 __pthread_lock(&cond->__c_lock, NULL);
242 th = dequeue(&cond->__c_waiting);
243 __pthread_unlock(&cond->__c_lock);
244 if (th != NULL) {
245 th->p_condvar_avail = 1;
246 WRITE_MEMORY_BARRIER();
247 restart(th);
249 return 0;
252 int pthread_cond_broadcast(pthread_cond_t *cond)
254 pthread_descr tosignal, th;
256 __pthread_lock(&cond->__c_lock, NULL);
257 /* Copy the current state of the waiting queue and empty it */
258 tosignal = cond->__c_waiting;
259 cond->__c_waiting = NULL;
260 __pthread_unlock(&cond->__c_lock);
261 /* Now signal each process in the queue */
262 while ((th = dequeue(&tosignal)) != NULL) {
263 th->p_condvar_avail = 1;
264 WRITE_MEMORY_BARRIER();
265 restart(th);
267 return 0;
270 int pthread_condattr_init(pthread_condattr_t *attr)
272 return 0;
275 int pthread_condattr_destroy(pthread_condattr_t *attr)
277 return 0;
280 int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
282 *pshared = PTHREAD_PROCESS_PRIVATE;
283 return 0;
286 int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared)
288 if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED)
289 return EINVAL;
291 /* For now it is not possible to shared a conditional variable. */
292 if (pshared != PTHREAD_PROCESS_PRIVATE)
293 return ENOSYS;
295 return 0;