Remove all the special code to handle cond_timedwait. Use timedsuspend 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 /* Function called by pthread_cancel to remove the thread from
43    waiting on a condition variable queue. */
44
45 static int cond_extricate_func(void *obj, pthread_descr th)
46 {
47   volatile pthread_descr self = thread_self();
48   pthread_cond_t *cond = obj;
49   int did_remove = 0;
50
51   __pthread_lock(&cond->__c_lock, self);
52   did_remove = remove_from_queue(&cond->__c_waiting, th);
53   __pthread_spin_unlock(&cond->__c_lock);
54
55   return did_remove;
56 }
57
58 int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
59 {
60   volatile pthread_descr self = thread_self();
61   pthread_extricate_if extr;
62   int already_canceled = 0;
63
64   /* Check whether the mutex is locked and owned by this thread.  */
65   if (mutex->__m_kind != PTHREAD_MUTEX_FAST_NP && mutex->__m_owner != self)
66     return EINVAL;
67
68   /* Set up extrication interface */
69   extr.pu_object = cond;
70   extr.pu_extricate_func = cond_extricate_func;
71
72   /* Register extrication interface */
73   __pthread_set_own_extricate_if(self, &extr);
74
75   /* Atomically enqueue thread for waiting, but only if it is not
76      canceled. If the thread is canceled, then it will fall through the
77      suspend call below, and then call pthread_exit without
78      having to worry about whether it is still on the condition variable queue.
79      This depends on pthread_cancel setting p_canceled before calling the
80      extricate function. */
81
82   __pthread_lock(&cond->__c_lock, self);
83   if (!(THREAD_GETMEM(self, p_canceled)
84       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
85     enqueue(&cond->__c_waiting, self);
86   else
87     already_canceled = 1;
88   __pthread_spin_unlock(&cond->__c_lock);
89
90   if (already_canceled) {
91     __pthread_set_own_extricate_if(self, 0);
92     pthread_exit(PTHREAD_CANCELED);
93   }
94
95   pthread_mutex_unlock(mutex);
96
97   suspend(self);
98   __pthread_set_own_extricate_if(self, 0);
99
100   /* Check for cancellation again, to provide correct cancellation
101      point behavior */
102
103   if (THREAD_GETMEM(self, p_woken_by_cancel)
104       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
105     THREAD_SETMEM(self, p_woken_by_cancel, 0);
106     pthread_mutex_lock(mutex);
107     pthread_exit(PTHREAD_CANCELED);
108   }
109
110   pthread_mutex_lock(mutex);
111   return 0;
112 }
113
114 static int
115 pthread_cond_timedwait_relative(pthread_cond_t *cond,
116                                 pthread_mutex_t *mutex,
117                                 const struct timespec * abstime)
118 {
119   volatile pthread_descr self = thread_self();
120   int already_canceled = 0;
121   pthread_extricate_if extr;
122
123   /* Check whether the mutex is locked and owned by this thread.  */
124   if (mutex->__m_owner != self)
125     return EINVAL;
126
127   already_canceled = 0;
128
129   /* Set up extrication interface */
130   extr.pu_object = cond;
131   extr.pu_extricate_func = cond_extricate_func;
132
133   /* Register extrication interface */
134   __pthread_set_own_extricate_if(self, &extr);
135
136   /* Enqueue to wait on the condition and check for cancellation. */
137   __pthread_lock(&cond->__c_lock, self);
138   if (!(THREAD_GETMEM(self, p_canceled)
139       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE))
140     enqueue(&cond->__c_waiting, self);
141   else
142     already_canceled = 1;
143   __pthread_spin_unlock(&cond->__c_lock);
144
145   if (already_canceled) {
146     __pthread_set_own_extricate_if(self, 0);
147     pthread_exit(PTHREAD_CANCELED);
148   }
149
150   pthread_mutex_unlock(mutex);
151
152   if (!timedsuspend(self, abstime) == 0) {
153     int was_on_queue;
154
155     /* __pthread_lock will queue back any spurious restarts that
156        may happen to it. */
157
158     __pthread_lock(&cond->__c_lock, self);
159     was_on_queue = remove_from_queue(&cond->__c_waiting, self);
160     __pthread_spin_unlock(&cond->__c_lock);
161
162     if (was_on_queue) {
163       __pthread_set_own_extricate_if(self, 0);
164       pthread_mutex_lock(mutex);
165       return ETIMEDOUT;
166     }
167
168     /* Eat the outstanding restart() from the signaller */
169     suspend(self);
170   }
171
172   __pthread_set_own_extricate_if(self, 0);
173
174   /* The remaining logic is the same as in other cancellable waits,
175      such as pthread_join sem_wait or pthread_cond wait. */
176
177   if (THREAD_GETMEM(self, p_woken_by_cancel)
178       && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) {
179     THREAD_SETMEM(self, p_woken_by_cancel, 0);
180     pthread_mutex_lock(mutex);
181     pthread_exit(PTHREAD_CANCELED);
182   }
183
184   pthread_mutex_lock(mutex);
185   return 0;
186 }
187
188 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
189                            const struct timespec * abstime)
190 {
191   /* Indirect call through pointer! */
192   return pthread_cond_timedwait_relative(cond, mutex, abstime);
193 }
194
195 int pthread_cond_signal(pthread_cond_t *cond)
196 {
197   pthread_descr th;
198
199   __pthread_lock(&cond->__c_lock, NULL);
200   th = dequeue(&cond->__c_waiting);
201   __pthread_spin_unlock(&cond->__c_lock);
202   if (th != NULL) restart(th);
203   return 0;
204 }
205
206 int pthread_cond_broadcast(pthread_cond_t *cond)
207 {
208   pthread_descr tosignal, th;
209
210   __pthread_lock(&cond->__c_lock, NULL);
211   /* Copy the current state of the waiting queue and empty it */
212   tosignal = cond->__c_waiting;
213   cond->__c_waiting = NULL;
214   __pthread_spin_unlock(&cond->__c_lock);
215   /* Now signal each process in the queue */
216   while ((th = dequeue(&tosignal)) != NULL) restart(th);
217   return 0;
218 }
219
220 int pthread_condattr_init(pthread_condattr_t *attr)
221 {
222   return 0;
223 }
224
225 int pthread_condattr_destroy(pthread_condattr_t *attr)
226 {
227   return 0;
228 }