1 /* 2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2007, Ryan Leavengood, leavengood@gmail.com. 4 * All rights reserved. Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <pthread.h> 9 #include "pthread_private.h" 10 11 #include <stdlib.h> 12 #include <stdio.h> 13 #include <string.h> 14 15 #include <syscall_utils.h> 16 17 #include <syscalls.h> 18 #include <user_mutex_defs.h> 19 20 21 #define COND_FLAG_SHARED 0x01 22 23 24 static const pthread_condattr pthread_condattr_default = { 25 false 26 }; 27 28 29 int 30 pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* _attr) 31 { 32 const pthread_condattr* attr = _attr != NULL 33 ? *_attr : &pthread_condattr_default; 34 35 cond->flags = 0; 36 if (attr->process_shared) 37 cond->flags |= COND_FLAG_SHARED; 38 39 cond->mutex = NULL; 40 cond->waiter_count = 0; 41 cond->lock = 0; 42 43 return 0; 44 } 45 46 47 int 48 pthread_cond_destroy(pthread_cond_t* cond) 49 { 50 return 0; 51 } 52 53 54 static status_t 55 cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex, bigtime_t timeout) 56 { 57 if (mutex->owner != find_thread(NULL)) { 58 // calling thread isn't mutex owner 59 return EPERM; 60 } 61 62 if (cond->mutex != NULL && cond->mutex != mutex) { 63 // condition variable already used with different mutex 64 return EINVAL; 65 } 66 67 cond->mutex = mutex; 68 cond->waiter_count++; 69 70 // make sure the user mutex we use for blocking is locked 71 atomic_or((int32*)&cond->lock, B_USER_MUTEX_LOCKED); 72 73 // atomically unlock the mutex and start waiting on the user mutex 74 mutex->owner = -1; 75 mutex->owner_count = 0; 76 77 status_t status = _kern_mutex_switch_lock((int32*)&mutex->lock, 78 (int32*)&cond->lock, "pthread condition", 79 timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, 80 timeout); 81 82 if (status == B_INTERRUPTED) { 83 // EINTR is not an allowed return value. We either have to restart 84 // waiting -- which we can't atomically -- or return a spurious 0. 85 status = 0; 86 } 87 88 pthread_mutex_lock(mutex); 89 90 cond->waiter_count--; 91 // If there are no more waiters, we can change mutexes. 92 if (cond->waiter_count == 0) 93 cond->mutex = NULL; 94 95 return status; 96 } 97 98 99 static inline void 100 cond_signal(pthread_cond_t* cond, bool broadcast) 101 { 102 if (cond->waiter_count == 0) 103 return; 104 105 // release the condition lock 106 _kern_mutex_unlock((int32*)&cond->lock, 107 broadcast ? B_USER_MUTEX_UNBLOCK_ALL : 0); 108 } 109 110 111 int 112 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* _mutex) 113 { 114 RETURN_AND_TEST_CANCEL(cond_wait(cond, _mutex, B_INFINITE_TIMEOUT)); 115 } 116 117 118 int 119 pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, 120 const struct timespec* tv) 121 { 122 if (tv == NULL || tv->tv_nsec < 0 || tv->tv_nsec >= 1000 * 1000 * 1000) 123 RETURN_AND_TEST_CANCEL(EINVAL); 124 125 RETURN_AND_TEST_CANCEL( 126 cond_wait(cond, mutex, tv->tv_sec * 1000000LL + tv->tv_nsec / 1000LL)); 127 } 128 129 130 int 131 pthread_cond_broadcast(pthread_cond_t* cond) 132 { 133 cond_signal(cond, true); 134 return 0; 135 } 136 137 138 int 139 pthread_cond_signal(pthread_cond_t* cond) 140 { 141 cond_signal(cond, false); 142 return 0; 143 } 144