Update.
[glibc.git] / linuxthreads / condvar.c
blob91067d2d170080b2fb28a8bab8caee2014454a70
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. */
16 /* Condition variables */
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"
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;
33 return 0;
36 int pthread_cond_destroy(pthread_cond_t *cond)
38 if (cond->c_waiting != NULL) return EBUSY;
39 return 0;
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);
60 return 0;
63 static inline int
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;
70 int retsleep;
71 sigjmp_buf jmpbuf;
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);
96 } else {
97 retsleep = -1;
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);
123 return 0;
126 int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
127 const struct timespec * abstime)
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;
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)
145 pthread_descr th;
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;
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);
165 return 0;
168 int pthread_condattr_init(pthread_condattr_t *attr)
170 return 0;
173 int pthread_condattr_destroy(pthread_condattr_t *attr)
175 return 0;