(pthread_cond_wait): Check whether mutex is owned by current thread
[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   /* Set up extrication interface */
147   extr.pu_object = cond;
148   extr.pu_extricate_func = cond_extricate_func;
149
150   /* Register extrication interface */
151   __pthread_set_own_extricate_if(self, &extr);
152
153   /* Enqueue to wait on the condition and check for cancellation. */
154   __pthread_lock(&cond->__c_lock, self);
155   if (!(THREAD_GETMEM(self, p_canceled)
156       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
157     enqueue(&cond->__c_waiting, self);
158   else
159     already_canceled = 1;
160   __pthread_unlock(&cond->__c_lock);
161
162   if (already_canceled) {
163     __pthread_set_own_extricate_if(self, 0);
164     pthread_exit(PTHREAD_CANCELED);
165   }
166
167   pthread_mutex_unlock(mutex);
168
169   if (atomic_decrement(&self->p_resume_count) == 0) {
170     /* Set up a longjmp handler for the restart signal, unblock
171        the signal and sleep. */
172
173     if (sigsetjmp(jmpbuf, 1) == 0) {
174       THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
175       THREAD_SETMEM(self, p_signal, 0);
176       /* Unblock the restart signal */
177       sigemptyset(&unblock);
178       sigaddset(&unblock, __pthread_sig_restart);
179       sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
180
181       while (1) {
182         struct timeval now;
183         struct timespec reltime;
184
185         /* Compute a time offset relative to now.  */
186         __gettimeofday (&now, NULL);
187         reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
188         reltime.tv_sec = abstime->tv_sec - now.tv_sec;
189         if (reltime.tv_nsec < 0) {
190           reltime.tv_nsec += 1000000000;
191           reltime.tv_sec -= 1;
192         }
193
194         /* Sleep for the required duration. If woken by a signal,
195            resume waiting as required by Single Unix Specification.  */
196         if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
197           break;
198       }
199
200       /* Block the restart signal again */
201       sigprocmask(SIG_SETMASK, &initial_mask, NULL);
202       was_signalled = 0;
203     } else {
204       was_signalled = 1;
205     }
206     THREAD_SETMEM(self, p_signal_jmp, NULL);
207   }
208
209   /* Now was_signalled is true if we exited the above code
210      due to the delivery of a restart signal.  In that case,
211      we know we have been dequeued and resumed and that the
212      resume count is balanced.  Otherwise, there are some
213      cases to consider. First, try to bump up the resume count
214      back to zero. If it goes to 1, it means restart() was
215      invoked on this thread. The signal must be consumed
216      and the count bumped down and everything is cool.
217      Otherwise, no restart was delivered yet, so we remove
218      the thread from the queue. If this succeeds, it's a clear
219      case of timeout. If we fail to remove from the queue, then we
220      must wait for a restart. */
221
222   if (!was_signalled) {
223     if (atomic_increment(&self->p_resume_count) != -1) {
224       __pthread_wait_for_restart_signal(self);
225       atomic_decrement(&self->p_resume_count); /* should be zero now! */
226     } else {
227       int was_on_queue;
228       __pthread_lock(&cond->__c_lock, self);
229       was_on_queue = remove_from_queue(&cond->__c_waiting, self);
230       __pthread_unlock(&cond->__c_lock);
231
232       if (was_on_queue) {
233         __pthread_set_own_extricate_if(self, 0);
234         pthread_mutex_lock(mutex);
235         return ETIMEDOUT;
236       }
237
238       suspend(self);
239     }
240   }
241
242   __pthread_set_own_extricate_if(self, 0);
243
244   /* The remaining logic is the same as in other cancellable waits,
245      such as pthread_join sem_wait or pthread_cond wait. */
246
247   if (THREAD_GETMEM(self, p_woken_by_cancel)
248       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
249     THREAD_SETMEM(self, p_woken_by_cancel, 0);
250     pthread_mutex_lock(mutex);
251     pthread_exit(PTHREAD_CANCELED);
252   }
253
254   pthread_mutex_lock(mutex);
255   return 0;
256 }
257
258 /* The following function is used on new (late 2.1 and 2.2 and higher) kernels
259    that have rt signals which queue. */
260
261 static int
262 pthread_cond_timedwait_relative_new(pthread_cond_t *cond,
263                                 pthread_mutex_t *mutex,
264                                 const struct timespec * abstime)
265 {
266   volatile pthread_descr self = thread_self();
267   sigset_t unblock, initial_mask;
268   int already_canceled = 0;
269   int was_signalled = 0;
270   sigjmp_buf jmpbuf;
271   pthread_extricate_if extr;
272
273   already_canceled = 0;
274   was_signalled = 0;
275
276   /* Set up extrication interface */
277   extr.pu_object = cond;
278   extr.pu_extricate_func = cond_extricate_func;
279
280   /* Register extrication interface */
281   __pthread_set_own_extricate_if(self, &extr);
282
283   /* Enqueue to wait on the condition and check for cancellation. */
284   __pthread_lock(&cond->__c_lock, self);
285   if (!(THREAD_GETMEM(self, p_canceled)
286       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
287     enqueue(&cond->__c_waiting, self);
288   else
289     already_canceled = 1;
290   __pthread_unlock(&cond->__c_lock);
291
292   if (already_canceled) {
293     __pthread_set_own_extricate_if(self, 0);
294     pthread_exit(PTHREAD_CANCELED);
295   }
296
297   pthread_mutex_unlock(mutex);
298
299   /* Set up a longjmp handler for the restart signal, unblock
300      the signal and sleep. */
301
302   if (sigsetjmp(jmpbuf, 1) == 0) {
303     THREAD_SETMEM(self, p_signal_jmp, &jmpbuf);
304     THREAD_SETMEM(self, p_signal, 0);
305     /* Unblock the restart signal */
306     sigemptyset(&unblock);
307     sigaddset(&unblock, __pthread_sig_restart);
308     sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
309
310       while (1) {
311         struct timeval now;
312         struct timespec reltime;
313
314         /* Compute a time offset relative to now.  */
315         __gettimeofday (&now, NULL);
316         reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
317         reltime.tv_sec = abstime->tv_sec - now.tv_sec;
318         if (reltime.tv_nsec < 0) {
319           reltime.tv_nsec += 1000000000;
320           reltime.tv_sec -= 1;
321         }
322
323         /* Sleep for the required duration. If woken by a signal,
324            resume waiting as required by Single Unix Specification.  */
325         if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0)
326           break;
327       }
328
329     /* Block the restart signal again */
330     sigprocmask(SIG_SETMASK, &initial_mask, NULL);
331     was_signalled = 0;
332   } else {
333     was_signalled = 1;
334   }
335   THREAD_SETMEM(self, p_signal_jmp, NULL);
336
337   /* Now was_signalled is true if we exited the above code
338      due to the delivery of a restart signal.  In that case,
339      everything is cool. We have been removed from the queue
340      by the other thread, and consumed its signal.
341
342      Otherwise we this thread woke up spontaneously, or due to a signal other
343      than restart. The next thing to do is to try to remove the thread
344      from the queue. This may fail due to a race against another thread
345      trying to do the same. In the failed case, we know we were signalled,
346      and we may also have to consume a restart signal. */
347
348   if (!was_signalled) {
349     int was_on_queue;
350
351     /* __pthread_lock will queue back any spurious restarts that
352        may happen to it. */
353
354     __pthread_lock(&cond->__c_lock, self);
355     was_on_queue = remove_from_queue(&cond->__c_waiting, self);
356     __pthread_unlock(&cond->__c_lock);
357
358     if (was_on_queue) {
359       __pthread_set_own_extricate_if(self, 0);
360       pthread_mutex_lock(mutex);
361       return ETIMEDOUT;
362     }
363
364     /* Eat the outstanding restart() from the signaller */
365     suspend(self);
366   }
367
368   __pthread_set_own_extricate_if(self, 0);
369
370   /* The remaining logic is the same as in other cancellable waits,
371      such as pthread_join sem_wait or pthread_cond wait. */
372
373   if (THREAD_GETMEM(self, p_woken_by_cancel)
374       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
375     THREAD_SETMEM(self, p_woken_by_cancel, 0);
376     pthread_mutex_lock(mutex);
377     pthread_exit(PTHREAD_CANCELED);
378   }
379
380   pthread_mutex_lock(mutex);
381   return 0;
382 }
383
384 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
385                            const struct timespec * abstime)
386 {
387   /* Check whether the mutex is locked and owned by this thread.  */
388   if (mutex->__m_owner != self)
389     return EINVAL;
390
391   /* Indirect call through pointer! */
392   return pthread_cond_tw_rel(cond, mutex, abstime);
393 }
394
395 int pthread_cond_signal(pthread_cond_t *cond)
396 {
397   pthread_descr th;
398
399   __pthread_lock(&cond->__c_lock, NULL);
400   th = dequeue(&cond->__c_waiting);
401   __pthread_unlock(&cond->__c_lock);
402   if (th != NULL) restart(th);
403   return 0;
404 }
405
406 int pthread_cond_broadcast(pthread_cond_t *cond)
407 {
408   pthread_descr tosignal, th;
409
410   __pthread_lock(&cond->__c_lock, NULL);
411   /* Copy the current state of the waiting queue and empty it */
412   tosignal = cond->__c_waiting;
413   cond->__c_waiting = NULL;
414   __pthread_unlock(&cond->__c_lock);
415   /* Now signal each process in the queue */
416   while ((th = dequeue(&tosignal)) != NULL) restart(th);
417   return 0;
418 }
419
420 int pthread_condattr_init(pthread_condattr_t *attr)
421 {
422   return 0;
423 }
424
425 int pthread_condattr_destroy(pthread_condattr_t *attr)
426 {
427   return 0;
428 }