thr_cond.c revision 22315
1/* 2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by John Birrell. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33#include <stdlib.h> 34#include <errno.h> 35#ifdef _THREAD_SAFE 36#include <pthread.h> 37#include "pthread_private.h" 38 39int 40pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr) 41{ 42 enum pthread_cond_type type; 43 pthread_cond_t pcond; 44 int rval = 0; 45 46 if (cond == NULL) { 47 errno = EINVAL; 48 rval = -1; 49 } else { 50 /* 51 * Check if a pointer to a condition variable attribute structure was 52 * passed by the caller: 53 */ 54 if (cond_attr != NULL && *cond_attr != NULL) { 55 /* Default to a fast condition variable: */ 56 type = (*cond_attr)->c_type; 57 } else { 58 /* Default to a fast condition variable: */ 59 type = COND_TYPE_FAST; 60 } 61 62 /* Process according to condition variable type: */ 63 switch (type) { 64 /* Fast condition variable: */ 65 case COND_TYPE_FAST: 66 /* Nothing to do here. */ 67 break; 68 69 /* Trap invalid condition variable types: */ 70 default: 71 /* Return an invalid argument error: */ 72 errno = EINVAL; 73 rval = -1; 74 break; 75 } 76 77 /* Check for no errors: */ 78 if (rval == 0) { 79 if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) { 80 errno = ENOMEM; 81 rval = -1; 82 } else { 83 /* 84 * Initialise the condition variable 85 * structure: 86 */ 87 _thread_queue_init(&pcond->c_queue); 88 pcond->c_flags |= COND_FLAGS_INITED; 89 pcond->c_type = type; 90 *cond = pcond; 91 } 92 } 93 } 94 /* Return the completion status: */ 95 return (rval); 96} 97 98int 99pthread_cond_destroy(pthread_cond_t * cond) 100{ 101 int rval = 0; 102 103 if (cond == NULL || *cond == NULL) { 104 errno = EINVAL; 105 rval = -1; 106 } else { 107 /* Process according to condition variable type: */ 108 switch ((*cond)->c_type) { 109 /* Fast condition variable: */ 110 case COND_TYPE_FAST: 111 /* Nothing to do here. */ 112 break; 113 114 /* Trap invalid condition variable types: */ 115 default: 116 /* Return an invalid argument error: */ 117 errno = EINVAL; 118 rval = -1; 119 break; 120 } 121 122 /* Check for errors: */ 123 if (rval == 0) { 124 /* Destroy the contents of the condition structure: */ 125 _thread_queue_init(&(*cond)->c_queue); 126 (*cond)->c_flags = 0; 127 free(*cond); 128 *cond = NULL; 129 } 130 } 131 /* Return the completion status: */ 132 return (rval); 133} 134 135int 136pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex) 137{ 138 int rval = 0; 139 int status; 140 141 if (cond == NULL || *cond == NULL) { 142 errno = EINVAL; 143 rval = -1; 144 } else { 145 /* Block signals: */ 146 _thread_kern_sig_block(&status); 147 148 /* Process according to condition variable type: */ 149 switch ((*cond)->c_type) { 150 /* Fast condition variable: */ 151 case COND_TYPE_FAST: 152 /* Queue the running thread for the condition variable: */ 153 _thread_queue_enq(&(*cond)->c_queue, _thread_run); 154 155 /* Unlock the mutex: */ 156 pthread_mutex_unlock(mutex); 157 158 /* Schedule the next thread: */ 159 _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); 160 161 /* Block signals: */ 162 _thread_kern_sig_block(NULL); 163 164 /* Lock the mutex: */ 165 rval = pthread_mutex_lock(mutex); 166 break; 167 168 /* Trap invalid condition variable types: */ 169 default: 170 /* Return an invalid argument error: */ 171 errno = EINVAL; 172 rval = -1; 173 break; 174 } 175 176 /* Unblock signals: */ 177 _thread_kern_sig_unblock(status); 178 } 179 180 /* Return the completion status: */ 181 return (rval); 182} 183 184int 185pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, 186 const struct timespec * abstime) 187{ 188 int rval = 0; 189 int status; 190 191 if (cond == NULL || *cond == NULL) { 192 errno = EINVAL; 193 rval = -1; 194 } else { 195 /* Block signals: */ 196 _thread_kern_sig_block(&status); 197 198 /* Process according to condition variable type: */ 199 switch ((*cond)->c_type) { 200 /* Fast condition variable: */ 201 case COND_TYPE_FAST: 202 /* Set the wakeup time: */ 203 _thread_run->wakeup_time.tv_sec = abstime->tv_sec; 204 _thread_run->wakeup_time.tv_nsec = abstime->tv_nsec; 205 206 /* Reset the timeout flag: */ 207 _thread_run->timeout = 0; 208 209 /* Queue the running thread for the condition variable: */ 210 _thread_queue_enq(&(*cond)->c_queue, _thread_run); 211 212 /* Unlock the mutex: */ 213 if ((rval = pthread_mutex_unlock(mutex)) != 0) { 214 /* 215 * Cannot unlock the mutex, so remove the running 216 * thread from the condition variable queue: 217 */ 218 _thread_queue_deq(&(*cond)->c_queue); 219 } else { 220 /* Schedule the next thread: */ 221 _thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__); 222 223 /* Block signals: */ 224 _thread_kern_sig_block(NULL); 225 226 /* Lock the mutex: */ 227 if ((rval = pthread_mutex_lock(mutex)) != 0) { 228 } 229 /* Check if the wait timed out: */ 230 else if (_thread_run->timeout) { 231 /* Return a timeout error: */ 232 errno = EAGAIN; 233 rval = -1; 234 } 235 } 236 break; 237 238 /* Trap invalid condition variable types: */ 239 default: 240 /* Return an invalid argument error: */ 241 errno = EINVAL; 242 rval = -1; 243 break; 244 } 245 246 /* Unblock signals: */ 247 _thread_kern_sig_unblock(status); 248 } 249 250 /* Return the completion status: */ 251 return (rval); 252} 253 254int 255pthread_cond_signal(pthread_cond_t * cond) 256{ 257 int rval = 0; 258 int status; 259 pthread_t pthread; 260 261 if (cond == NULL || *cond == NULL) { 262 errno = EINVAL; 263 rval = -1; 264 } else { 265 /* Block signals: */ 266 _thread_kern_sig_block(&status); 267 268 /* Process according to condition variable type: */ 269 switch ((*cond)->c_type) { 270 /* Fast condition variable: */ 271 case COND_TYPE_FAST: 272 /* Bring the next thread off the condition queue: */ 273 if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { 274 /* Allow the thread to run: */ 275 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 276 } 277 break; 278 279 /* Trap invalid condition variable types: */ 280 default: 281 /* Return an invalid argument error: */ 282 errno = EINVAL; 283 rval = -1; 284 break; 285 } 286 287 /* Unblock signals: */ 288 _thread_kern_sig_unblock(status); 289 } 290 291 /* Return the completion status: */ 292 return (rval); 293} 294 295int 296pthread_cond_broadcast(pthread_cond_t * cond) 297{ 298 int rval = 0; 299 int status; 300 pthread_t pthread; 301 302 /* Block signals: */ 303 _thread_kern_sig_block(&status); 304 305 /* Process according to condition variable type: */ 306 switch ((*cond)->c_type) { 307 /* Fast condition variable: */ 308 case COND_TYPE_FAST: 309 /* Enter a loop to bring all threads off the condition queue: */ 310 while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) { 311 /* Allow the thread to run: */ 312 PTHREAD_NEW_STATE(pthread,PS_RUNNING); 313 } 314 break; 315 316 /* Trap invalid condition variable types: */ 317 default: 318 /* Return an invalid argument error: */ 319 errno = EINVAL; 320 rval = -1; 321 break; 322 } 323 324 /* Unblock signals: */ 325 _thread_kern_sig_unblock(status); 326 327 /* Return the completion status: */ 328 return (rval); 329} 330#endif 331