Use __pthread_sig_cancel and __pthread_sig_restart everywhere instead
[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 int pthread_cond_init(pthread_cond_t *cond,
29                       const pthread_condattr_t *cond_attr)
30 {
31   __pthread_init_lock(&cond->c_lock);
32   cond->c_waiting = NULL;
33   return 0;
34 }
35
36 int pthread_cond_destroy(pthread_cond_t *cond)
37 {
38   if (cond->c_waiting != NULL) return EBUSY;
39   return 0;
40 }
41
42 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
43 {
44   volatile pthread_descr self = thread_self();
45
46   __pthread_lock(&cond->c_lock);
47   enqueue(&cond->c_waiting, self);
48   __pthread_unlock(&cond->c_lock);
49   pthread_mutex_unlock(mutex);
50   suspend_with_cancellation(self);
51   pthread_mutex_lock(mutex);
52   /* This is a cancellation point */
53   if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
54     /* Remove ourselves from the waiting queue if we're still on it */
55     __pthread_lock(&cond->c_lock);
56     remove_from_queue(&cond->c_waiting, self);
57     __pthread_unlock(&cond->c_lock);
58     pthread_exit(PTHREAD_CANCELED);
59   }
60   return 0;
61 }
62
63 static inline int
64 pthread_cond_timedwait_relative(pthread_cond_t *cond,
65                                 pthread_mutex_t *mutex,
66                                 const struct timespec * reltime)
67 {
68   volatile pthread_descr self = thread_self();
69   sigset_t unblock, initial_mask;
70   int retsleep;
71   sigjmp_buf jmpbuf;
72
73   /* Wait on the condition */
74   __pthread_lock(&cond->c_lock);
75   enqueue(&cond->c_waiting, self);
76   __pthread_unlock(&cond->c_lock);
77   pthread_mutex_unlock(mutex);
78   /* Set up a longjmp handler for the restart and cancel signals */
79   if (sigsetjmp(jmpbuf, 1) == 0) {
80     self->p_signal_jmp = &jmpbuf;
81     self->p_cancel_jmp = &jmpbuf;
82     self->p_signal = 0;
83     /* Check for cancellation */
84     if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
85       retsleep = -1;
86     } else {
87       /* Unblock the restart signal */
88       sigemptyset(&unblock);
89       sigaddset(&unblock, __pthread_sig_restart);
90       sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask);
91       /* Sleep for the required duration */
92       retsleep = __libc_nanosleep(reltime, NULL);
93       /* Block the restart signal again */
94       sigprocmask(SIG_SETMASK, &initial_mask, NULL);
95     }
96   } else {
97     retsleep = -1;
98   }
99   self->p_signal_jmp = NULL;
100   self->p_cancel_jmp = NULL;
101   /* Here, either the condition was signaled (self->p_signal != 0)
102                    or we got canceled (self->p_canceled != 0)
103                    or the timeout occurred (retsleep == 0)
104                    or another interrupt occurred (retsleep == -1) */
105   /* This is a cancellation point */
106   if (self->p_canceled && self->p_cancelstate == PTHREAD_CANCEL_ENABLE) {
107     __pthread_lock(&cond->c_lock);
108     remove_from_queue(&cond->c_waiting, self);
109     __pthread_unlock(&cond->c_lock);
110     pthread_mutex_lock(mutex);
111     pthread_exit(PTHREAD_CANCELED);
112   }
113   /* If not signaled: also remove ourselves and return an error code */
114   if (self->p_signal == 0) {
115     __pthread_lock(&cond->c_lock);
116     remove_from_queue(&cond->c_waiting, self);
117     __pthread_unlock(&cond->c_lock);
118     pthread_mutex_lock(mutex);
119     return retsleep == 0 ? ETIMEDOUT : EINTR;
120   }
121   /* Otherwise, return normally */
122   pthread_mutex_lock(mutex);
123   return 0;
124 }
125
126 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
127                            const struct timespec * abstime)
128 {
129   struct timeval now;
130   struct timespec reltime;
131   /* Compute a time offset relative to now */
132   __gettimeofday(&now, NULL);
133   reltime.tv_sec = abstime->tv_sec - now.tv_sec;
134   reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000;
135   if (reltime.tv_nsec < 0) {
136     reltime.tv_nsec += 1000000000;
137     reltime.tv_sec -= 1;
138   }
139   if (reltime.tv_sec < 0) return ETIMEDOUT;
140   return pthread_cond_timedwait_relative(cond, mutex, &reltime);
141 }
142
143 int pthread_cond_signal(pthread_cond_t *cond)
144 {
145   pthread_descr th;
146
147   __pthread_lock(&cond->c_lock);
148   th = dequeue(&cond->c_waiting);
149   __pthread_unlock(&cond->c_lock);
150   if (th != NULL) restart(th);
151   return 0;
152 }
153
154 int pthread_cond_broadcast(pthread_cond_t *cond)
155 {
156   pthread_descr tosignal, th;
157
158   __pthread_lock(&cond->c_lock);
159   /* Copy the current state of the waiting queue and empty it */
160   tosignal = cond->c_waiting;
161   cond->c_waiting = NULL;
162   __pthread_unlock(&cond->c_lock);
163   /* Now signal each process in the queue */
164   while ((th = dequeue(&tosignal)) != NULL) restart(th);
165   return 0;
166 }
167
168 int pthread_condattr_init(pthread_condattr_t *attr)
169 {
170   return 0;
171 }
172
173 int pthread_condattr_destroy(pthread_condattr_t *attr)
174 {
175   return 0;
176 }