Fix last change.
[kopensolaris-gnu/glibc.git] / linuxthreads / condvar.c
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.                 */
15
16 /* Condition variables */
17
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"
27
28 static int pthread_cond_timedwait_relative_old(pthread_cond_t *,
29     pthread_mutex_t *, const struct timespec *);
30
31 static int pthread_cond_timedwait_relative_new(pthread_cond_t *,
32     pthread_mutex_t *, const struct timespec *);
33
34 static int (*pthread_cond_tw_rel)(pthread_cond_t *, pthread_mutex_t *,
35     const struct timespec *) = pthread_cond_timedwait_relative_old;
36
37 /* initialize this module */
38 void __pthread_init_condvar(int rt_sig_available)
39 {
40   if (rt_sig_available)
41     pthread_cond_tw_rel = pthread_cond_timedwait_relative_new;
42 }
43
44 int pthread_cond_init(pthread_cond_t *cond,
45                       const pthread_condattr_t *cond_attr)
46 {
47   __pthread_init_lock(&cond->__c_lock);
48   cond->__c_waiting = NULL;
49   return 0;
50 }
51
52 int pthread_cond_destroy(pthread_cond_t *cond)
53 {
54   if (cond->__c_waiting != NULL) return EBUSY;
55   return 0;
56 }
57
58 /* Function called by pthread_cancel to remove the thread from
59    waiting on a condition variable queue. */
60
61 static int cond_extricate_func(void *obj, pthread_descr th)
62 {
63   volatile pthread_descr self = thread_self();
64   pthread_cond_t *cond = obj;
65   int did_remove = 0;
66
67   __pthread_lock(&cond->__c_lock, self);
68   did_remove = remove_from_queue(&cond->__c_waiting, th);
69   __pthread_unlock(&cond->__c_lock);
70
71   return did_remove;
72 }
73
74 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
75 {
76   volatile pthread_descr self = thread_self();
77   pthread_extricate_if extr;
78   int already_canceled = 0;
79
80   /* Check whether the mutex is locked and owned by this thread.  */
81   if (mutex->__m_owner != self)
82     return EINVAL;
83
84   /* Set up extrication interface */
85   extr.pu_object = cond;
86   extr.pu_extricate_func = cond_extricate_func;
87
88   /* Register extrication interface */
89   __pthread_set_own_extricate_if(self, &extr);
90
91   /* Atomically enqueue thread for waiting, but only if it is not
92      canceled. If the thread is canceled, then it will fall through the
93      suspend call below, and then call pthread_exit without
94      having to worry about whether it is still on the condition variable queue.
95      This depends on pthread_cancel setting p_canceled before calling the
96      extricate function. */
97
98   __pthread_lock(&cond->__c_lock, self);
99   if (!(THREAD_GETMEM(self, p_canceled)
100       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
101     enqueue(&cond->__c_waiting, self);
102   else
103     already_canceled = 1;
104   __pthread_unlock(&cond->__c_lock);
105
106   if (already_canceled) {
107     __pthread_set_own_extricate_if(self, 0);
108     pthread_exit(PTHREAD_CANCELED);
109   }
110
111   pthread_mutex_unlock(mutex);
112
113   suspend(self);
114   __pthread_set_own_extricate_if(self, 0);
115
116   /* Check for cancellation again, to provide correct cancellation
117      point behavior */
118
119   if (THREAD_GETMEM(self, p_woken_by_cancel)
120       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
121     THREAD_SETMEM(self, p_woken_by_cancel, 0);
122     pthread_mutex_lock(mutex);
123     pthread_exit(PTHREAD_CANCELED);
124   }
125
126   pthread_mutex_lock(mutex);
127   return 0;
128 }
129
130 /* The following function is used on kernels that don't have rt signals.
131    SIGUSR1 is used as the restart signal. The different code is needed
132    because that ordinary signal does not queue. */
133
134 static int
135 pthread_cond_timedwait_relative_old(pthread_cond_t *cond,
136                                 pthread_mutex_t *mutex,
137                                 const struct timespec * abstime)
138 {
139   volatile pthread_descr self = thread_self();
140   sigset_t unblock, initial_mask;
141   int already_canceled = 0;
142   int was_signalled = 0;
143   sigjmp_buf jmpbuf;
144   pthread_extricate_if extr;
145
146   /* Check whether the mutex is locked and owned by this thread.  */
147   if (mutex->__m_owner != self)
148     return EINVAL;
149
150   /* Set up extrication interface */
151   extr.pu_object = cond;
152   extr.pu_extricate_func = cond_extricate_func;
153
154   /* Register extrication interface */
155   __pthread_set_own_extricate_if(self, &extr);
156
157   /* Enqueue to wait on the condition and check for cancellation. */
158   __pthread_lock(&cond->__c_lock, self);
159   if (!(THREAD_GETMEM(self, p_canceled)
160       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
161     enqueue(&cond->__c_waiting, self);
162   else
163     already_canceled = 1;
164   __pthread_unlock(&cond->__c_lock);
165
166   if (already_canceled) {
167     __pthread_set_own_extricate_if(self, 0);
168     pthread_exit(PTHREAD_CANCELED);
169   }
170
171   pthread_mutex_unlock(mutex);
172
173   if (atomic_decrement(&self->p_resume_count) == 0) {
174     /* Set up a longjmp handler for the restart signal, unblock
175        the signal and sleep. */
176
177     if (sigsetjmp(jmpbuf, 1) == 0) {
178       THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
179       THREAD_SETMEM(self, p_signal, 0);
180       /* Unblock the restart signal */
181       sigemptyset(&unblock);
182       sigaddset(&unblock, __pthread_sig_restart);
183       sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
184
185       while (1) {
186         struct timeval now;
187         struct timespec reltime;
188
189         /* Compute a time offset relative to now.  */
190         __gettimeofday (&now, NULL);
191         reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
192         reltime.tv_sec = abstime->tv_sec - now.tv_sec;
193         if (reltime.tv_nsec < 0) {
194           reltime.tv_nsec += 1000000000;
195           reltime.tv_sec -= 1;
196         }
197
198         /* Sleep for the required duration. If woken by a signal,
199            resume waiting as required by Single Unix Specification.  */
200         if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
201           break;
202       }
203
204       /* Block the restart signal again */
205       sigprocmask(SIG_SETMASK, &initial_mask, NULL);
206       was_signalled = 0;
207     } else {
208       was_signalled = 1;
209     }
210     THREAD_SETMEM(self, p_signal_jmp, NULL);
211   }
212
213   /* Now was_signalled is true if we exited the above code
214      due to the delivery of a restart signal.  In that case,
215      we know we have been dequeued and resumed and that the
216      resume count is balanced.  Otherwise, there are some
217      cases to consider. First, try to bump up the resume count
218      back to zero. If it goes to 1, it means restart() was
219      invoked on this thread. The signal must be consumed
220      and the count bumped down and everything is cool.
221      Otherwise, no restart was delivered yet, so we remove
222      the thread from the queue. If this succeeds, it's a clear
223      case of timeout. If we fail to remove from the queue, then we
224      must wait for a restart. */
225
226   if (!was_signalled) {
227     if (atomic_increment(&self->p_resume_count) != -1) {
228       __pthread_wait_for_restart_signal(self);
229       atomic_decrement(&self->p_resume_count); /* should be zero now! */
230     } else {
231       int was_on_queue;
232       __pthread_lock(&cond->__c_lock, self);
233       was_on_queue = remove_from_queue(&cond->__c_waiting, self);
234       __pthread_unlock(&cond->__c_lock);
235
236       if (was_on_queue) {
237         __pthread_set_own_extricate_if(self, 0);
238         pthread_mutex_lock(mutex);
239         return ETIMEDOUT;
240       }
241
242       suspend(self);
243     }
244   }
245
246   __pthread_set_own_extricate_if(self, 0);
247
248   /* The remaining logic is the same as in other cancellable waits,
249      such as pthread_join sem_wait or pthread_cond wait. */
250
251   if (THREAD_GETMEM(self, p_woken_by_cancel)
252       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
253     THREAD_SETMEM(self, p_woken_by_cancel, 0);
254     pthread_mutex_lock(mutex);
255     pthread_exit(PTHREAD_CANCELED);
256   }
257
258   pthread_mutex_lock(mutex);
259   return 0;
260 }
261
262 /* The following function is used on new (late 2.1 and 2.2 and higher) kernels
263    that have rt signals which queue. */
264
265 static int
266 pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
267                                 pthread_mutex_t *mutex,
268                                 const struct timespec * abstime)
269 {
270   volatile pthread_descr self = thread_self();
271   sigset_t unblock, initial_mask;
272   int already_canceled = 0;
273   int was_signalled = 0;
274   sigjmp_buf jmpbuf;
275   pthread_extricate_if extr;
276
277   /* Check whether the mutex is locked and owned by this thread.  */
278   if (mutex->__m_owner != self)
279     return EINVAL;
280
281   already_canceled = 0;
282   was_signalled = 0;
283
284   /* Set up extrication interface */
285   extr.pu_object = cond;
286   extr.pu_extricate_func = cond_extricate_func;
287
288   /* Register extrication interface */
289   __pthread_set_own_extricate_if(self, &extr);
290
291   /* Enqueue to wait on the condition and check for cancellation. */
292   __pthread_lock(&cond->__c_lock, self);
293   if (!(THREAD_GETMEM(self, p_canceled)
294       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
295     enqueue(&cond->__c_waiting, self);
296   else
297     already_canceled = 1;
298   __pthread_unlock(&cond->__c_lock);
299
300   if (already_canceled) {
301     __pthread_set_own_extricate_if(self, 0);
302     pthread_exit(PTHREAD_CANCELED);
303   }
304
305   pthread_mutex_unlock(mutex);
306
307   /* Set up a longjmp handler for the restart signal, unblock
308      the signal and sleep. */
309
310   if (sigsetjmp(jmpbuf, 1) == 0) {
311     THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
312     THREAD_SETMEM(self, p_signal, 0);
313     /* Unblock the restart signal */
314     sigemptyset(&unblock);
315     sigaddset(&unblock, __pthread_sig_restart);
316     sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
317
318       while (1) {
319         struct timeval now;
320         struct timespec reltime;
321
322         /* Compute a time offset relative to now.  */
323         __gettimeofday (&now, NULL);
324         reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
325         reltime.tv_sec = abstime->tv_sec - now.tv_sec;
326         if (reltime.tv_nsec < 0) {
327           reltime.tv_nsec += 1000000000;
328           reltime.tv_sec -= 1;
329         }
330
331         /* Sleep for the required duration. If woken by a signal,
332            resume waiting as required by Single Unix Specification.  */
333         if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
334           break;
335       }
336
337     /* Block the restart signal again */
338     sigprocmask(SIG_SETMASK, &initial_mask, NULL);
339     was_signalled = 0;
340   } else {
341     was_signalled = 1;
342   }
343   THREAD_SETMEM(self, p_signal_jmp, NULL);
344
345   /* Now was_signalled is true if we exited the above code
346      due to the delivery of a restart signal.  In that case,
347      everything is cool. We have been removed from the queue
348      by the other thread, and consumed its signal.
349
350      Otherwise we this thread woke up spontaneously, or due to a signal other
351      than restart. The next thing to do is to try to remove the thread
352      from the queue. This may fail due to a race against another thread
353      trying to do the same. In the failed case, we know we were signalled,
354      and we may also have to consume a restart signal. */
355
356   if (!was_signalled) {
357     int was_on_queue;
358
359     /* __pthread_lock will queue back any spurious restarts that
360        may happen to it. */
361
362     __pthread_lock(&cond->__c_lock, self);
363     was_on_queue = remove_from_queue(&cond->__c_waiting, self);
364     __pthread_unlock(&cond->__c_lock);
365
366     if (was_on_queue) {
367       __pthread_set_own_extricate_if(self, 0);
368       pthread_mutex_lock(mutex);
369       return ETIMEDOUT;
370     }
371
372     /* Eat the outstanding restart() from the signaller */
373     suspend(self);
374   }
375
376   __pthread_set_own_extricate_if(self, 0);
377
378   /* The remaining logic is the same as in other cancellable waits,
379      such as pthread_join sem_wait or pthread_cond wait. */
380
381   if (THREAD_GETMEM(self, p_woken_by_cancel)
382       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
383     THREAD_SETMEM(self, p_woken_by_cancel, 0);
384     pthread_mutex_lock(mutex);
385     pthread_exit(PTHREAD_CANCELED);
386   }
387
388   pthread_mutex_lock(mutex);
389   return 0;
390 }
391
392 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
393                            const struct timespec * abstime)
394 {
395   /* Indirect call through pointer! */
396   return pthread_cond_tw_rel(cond, mutex, abstime);
397 }
398
399 int pthread_cond_signal(pthread_cond_t *cond)
400 {
401   pthread_descr th;
402
403   __pthread_lock(&cond->__c_lock, NULL);
404   th = dequeue(&cond->__c_waiting);
405   __pthread_unlock(&cond->__c_lock);
406   if (th != NULL) restart(th);
407   return 0;
408 }
409
410 int pthread_cond_broadcast(pthread_cond_t *cond)
411 {
412   pthread_descr tosignal, th;
413
414   __pthread_lock(&cond->__c_lock, NULL);
415   /* Copy the current state of the waiting queue and empty it */
416   tosignal = cond->__c_waiting;
417   cond->__c_waiting = NULL;
418   __pthread_unlock(&cond->__c_lock);
419   /* Now signal each process in the queue */
420   while ((th = dequeue(&tosignal)) != NULL) restart(th);
421   return 0;
422 }
423
424 int pthread_condattr_init(pthread_condattr_t *attr)
425 {
426   return 0;
427 }
428
429 int pthread_condattr_destroy(pthread_condattr_t *attr)
430 {
431   return 0;
432 }