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 int pthread_cond_wait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
)
44 volatile pthread_descr self
= thread_self();
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
);
64 pthread_cond_timedwait_relative(pthread_cond_t
*cond
,
65 pthread_mutex_t
*mutex
,
66 const struct timespec
* reltime
)
68 volatile pthread_descr self
= thread_self();
69 sigset_t unblock
, initial_mask
;
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
;
83 /* Check for cancellation */
84 if (self
->p_canceled
&& self
->p_cancelstate
== PTHREAD_CANCEL_ENABLE
) {
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
);
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
);
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
;
121 /* Otherwise, return normally */
122 pthread_mutex_lock(mutex
);
126 int pthread_cond_timedwait(pthread_cond_t
*cond
, pthread_mutex_t
*mutex
,
127 const struct timespec
* abstime
)
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;
139 if (reltime
.tv_sec
< 0) return ETIMEDOUT
;
140 return pthread_cond_timedwait_relative(cond
, mutex
, &reltime
);
143 int pthread_cond_signal(pthread_cond_t
*cond
)
147 __pthread_lock(&cond
->c_lock
);
148 th
= dequeue(&cond
->c_waiting
);
149 __pthread_unlock(&cond
->c_lock
);
150 if (th
!= NULL
) restart(th
);
154 int pthread_cond_broadcast(pthread_cond_t
*cond
)
156 pthread_descr tosignal
, th
;
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
);
168 int pthread_condattr_init(pthread_condattr_t
*attr
)
173 int pthread_condattr_destroy(pthread_condattr_t
*attr
)