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 #include <time_private.h> 17 18 #include <syscalls.h> 19 #include <user_mutex_defs.h> 20 21 22 #define COND_FLAG_SHARED 0x01 23 #define COND_FLAG_MONOTONIC 0x02 24 25 26 static const pthread_condattr pthread_condattr_default = { 27 false, 28 CLOCK_REALTIME 29 }; 30 31 32 int 33 pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* _attr) 34 { 35 const pthread_condattr* attr = _attr != NULL 36 ? *_attr : &pthread_condattr_default; 37 38 cond->flags = 0; 39 if (attr->process_shared) 40 cond->flags |= COND_FLAG_SHARED; 41 42 if (attr->clock_id == CLOCK_MONOTONIC) 43 cond->flags |= COND_FLAG_MONOTONIC; 44 45 cond->mutex = NULL; 46 cond->waiter_count = 0; 47 cond->lock = 0; 48 49 return 0; 50 } 51 52 53 int 54 pthread_cond_destroy(pthread_cond_t* cond) 55 { 56 return 0; 57 } 58 59 60 static status_t 61 cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex, uint32 flags, 62 bigtime_t timeout) 63 { 64 if (mutex->owner != find_thread(NULL)) { 65 // calling thread isn't mutex owner 66 return EPERM; 67 } 68 69 if (cond->mutex != NULL && cond->mutex != mutex) { 70 // condition variable already used with different mutex 71 return EINVAL; 72 } 73 74 cond->mutex = mutex; 75 cond->waiter_count++; 76 77 // make sure the user mutex we use for blocking is locked 78 atomic_test_and_set((int32*)&cond->lock, B_USER_MUTEX_LOCKED, 0); 79 80 // atomically unlock the mutex and start waiting on the user mutex 81 mutex->owner = -1; 82 mutex->owner_count = 0; 83 84 if ((cond->flags & COND_FLAG_SHARED) != 0) 85 flags |= B_USER_MUTEX_SHARED; 86 status_t status = _kern_mutex_switch_lock((int32*)&mutex->lock, 87 ((mutex->flags & MUTEX_FLAG_SHARED) ? B_USER_MUTEX_SHARED : 0), 88 (int32*)&cond->lock, "pthread condition", flags, timeout); 89 90 if (status == B_INTERRUPTED) { 91 // EINTR is not an allowed return value. We either have to restart 92 // waiting -- which we can't atomically -- or return a spurious 0. 93 status = 0; 94 } 95 96 pthread_mutex_lock(mutex); 97 98 cond->waiter_count--; 99 100 // If there are no more waiters, we can change mutexes. 101 if (cond->waiter_count == 0) 102 cond->mutex = NULL; 103 104 return status; 105 } 106 107 108 static inline void 109 cond_signal(pthread_cond_t* cond, bool broadcast) 110 { 111 if (cond->waiter_count == 0) 112 return; 113 114 uint32 flags = 0; 115 if (broadcast) 116 flags |= B_USER_MUTEX_UNBLOCK_ALL; 117 if ((cond->flags & COND_FLAG_SHARED) != 0) 118 flags |= B_USER_MUTEX_SHARED; 119 120 // release the condition lock 121 atomic_and((int32*)&cond->lock, ~(int32)B_USER_MUTEX_LOCKED); 122 _kern_mutex_unblock((int32*)&cond->lock, flags); 123 } 124 125 126 int 127 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* _mutex) 128 { 129 RETURN_AND_TEST_CANCEL(cond_wait(cond, _mutex, 0, B_INFINITE_TIMEOUT)); 130 } 131 132 133 int 134 pthread_cond_clockwait(pthread_cond_t* cond, pthread_mutex_t* mutex, 135 clockid_t clock_id, const struct timespec* abstime) 136 { 137 bigtime_t timeoutMicros; 138 if (abstime == NULL || !timespec_to_bigtime(*abstime, timeoutMicros)) 139 RETURN_AND_TEST_CANCEL(EINVAL); 140 141 uint32 flags = 0; 142 switch (clock_id) { 143 case CLOCK_REALTIME: 144 flags = B_ABSOLUTE_REAL_TIME_TIMEOUT; 145 break; 146 case CLOCK_MONOTONIC : 147 flags = B_ABSOLUTE_TIMEOUT; 148 break; 149 default: 150 return B_BAD_VALUE; 151 } 152 153 RETURN_AND_TEST_CANCEL(cond_wait(cond, mutex, flags, timeoutMicros)); 154 } 155 156 157 int 158 pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, 159 const struct timespec* abstime) 160 { 161 return pthread_cond_clockwait(cond, mutex, 162 (cond->flags & COND_FLAG_MONOTONIC) != 0 ? CLOCK_MONOTONIC : CLOCK_REALTIME, 163 abstime); 164 } 165 166 167 int 168 pthread_cond_broadcast(pthread_cond_t* cond) 169 { 170 cond_signal(cond, true); 171 return 0; 172 } 173 174 175 int 176 pthread_cond_signal(pthread_cond_t* cond) 177 { 178 cond_signal(cond, false); 179 return 0; 180 } 181