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). */
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. */
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 */
23 #include "internals.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
;
36 int pthread_cond_destroy(pthread_cond_t
*cond
)
38 if (cond
->__c_waiting
!= NULL
) return EBUSY
;
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
;
51 __pthread_lock(&cond
->__c_lock
, self
);
52 did_remove
= remove_from_queue(&cond
->__c_waiting
, th
);
53 __pthread_unlock(&cond
->__c_lock
);
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
)
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
);
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;
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
++;
116 __pthread_set_own_extricate_if(self
, 0);
118 /* Check for cancellation again, to provide correct cancellation
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
--)
132 pthread_mutex_lock(mutex
);
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
)
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
);
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;
179 if (!timedsuspend(self
, abstime
)) {
182 /* __pthread_lock will queue back any spurious restarts that
185 __pthread_lock(&cond
->__c_lock
, self
);
186 was_on_queue
= remove_from_queue(&cond
->__c_waiting
, self
);
187 __pthread_unlock(&cond
->__c_lock
);
190 __pthread_set_own_extricate_if(self
, 0);
191 pthread_mutex_lock(mutex
);
195 /* Eat the outstanding restart() from the signaller */
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
++;
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
--)
226 pthread_mutex_lock(mutex
);
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
)
241 __pthread_lock(&cond
->__c_lock
, NULL
);
242 th
= dequeue(&cond
->__c_waiting
);
243 __pthread_unlock(&cond
->__c_lock
);
245 th
->p_condvar_avail
= 1;
246 WRITE_MEMORY_BARRIER();
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();
270 int pthread_condattr_init(pthread_condattr_t
*attr
)
275 int pthread_condattr_destroy(pthread_condattr_t
*attr
)
280 int pthread_condattr_getpshared (const pthread_condattr_t
*attr
, int *pshared
)
282 *pshared
= PTHREAD_PROCESS_PRIVATE
;
286 int pthread_condattr_setpshared (pthread_condattr_t
*attr
, int pshared
)
288 if (pshared
!= PTHREAD_PROCESS_PRIVATE
&& pshared
!= PTHREAD_PROCESS_SHARED
)
291 /* For now it is not possible to shared a conditional variable. */
292 if (pshared
!= PTHREAD_PROCESS_PRIVATE
)