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 #define COND_FLAG_MONOTONIC 0x02 23 24 25 static const pthread_condattr pthread_condattr_default = { 26 false, 27 CLOCK_REALTIME 28 }; 29 30 31 int 32 pthread_cond_init(pthread_cond_t* cond, const pthread_condattr_t* _attr) 33 { 34 const pthread_condattr* attr = _attr != NULL 35 ? *_attr : &pthread_condattr_default; 36 37 cond->flags = 0; 38 if (attr->process_shared) 39 cond->flags |= COND_FLAG_SHARED; 40 41 if (attr->clock_id == CLOCK_MONOTONIC) 42 cond->flags |= COND_FLAG_MONOTONIC; 43 44 cond->mutex = NULL; 45 cond->waiter_count = 0; 46 cond->lock = 0; 47 48 return 0; 49 } 50 51 52 int 53 pthread_cond_destroy(pthread_cond_t* cond) 54 { 55 return 0; 56 } 57 58 59 static status_t 60 cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex, uint32 flags, 61 bigtime_t timeout) 62 { 63 if (mutex->owner != find_thread(NULL)) { 64 // calling thread isn't mutex owner 65 return EPERM; 66 } 67 68 if (cond->mutex != NULL && cond->mutex != mutex) { 69 // condition variable already used with different mutex 70 return EINVAL; 71 } 72 73 cond->mutex = mutex; 74 cond->waiter_count++; 75 76 // make sure the user mutex we use for blocking is locked 77 atomic_test_and_set((int32*)&cond->lock, B_USER_MUTEX_LOCKED, 0); 78 79 // atomically unlock the mutex and start waiting on the user mutex 80 mutex->owner = -1; 81 mutex->owner_count = 0; 82 83 if ((cond->flags & COND_FLAG_SHARED) != 0) 84 flags |= B_USER_MUTEX_SHARED; 85 status_t status = _kern_mutex_switch_lock((int32*)&mutex->lock, 86 ((mutex->flags & MUTEX_FLAG_SHARED) ? B_USER_MUTEX_SHARED : 0), 87 (int32*)&cond->lock, "pthread condition", flags, timeout); 88 89 if (status == B_INTERRUPTED) { 90 // EINTR is not an allowed return value. We either have to restart 91 // waiting -- which we can't atomically -- or return a spurious 0. 92 status = 0; 93 } 94 95 pthread_mutex_lock(mutex); 96 97 cond->waiter_count--; 98 99 // If there are no more waiters, we can change mutexes. 100 if (cond->waiter_count == 0) 101 cond->mutex = NULL; 102 103 return status; 104 } 105 106 107 static inline void 108 cond_signal(pthread_cond_t* cond, bool broadcast) 109 { 110 if (cond->waiter_count == 0) 111 return; 112 113 uint32 flags = 0; 114 if (broadcast) 115 flags |= B_USER_MUTEX_UNBLOCK_ALL; 116 if ((cond->flags & COND_FLAG_SHARED) != 0) 117 flags |= B_USER_MUTEX_SHARED; 118 119 // release the condition lock 120 atomic_and((int32*)&cond->lock, ~(int32)B_USER_MUTEX_LOCKED); 121 _kern_mutex_unblock((int32*)&cond->lock, flags); 122 } 123 124 125 int 126 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* _mutex) 127 { 128 RETURN_AND_TEST_CANCEL(cond_wait(cond, _mutex, 0, B_INFINITE_TIMEOUT)); 129 } 130 131 132 int 133 pthread_cond_clockwait(pthread_cond_t* cond, pthread_mutex_t* mutex, 134 clockid_t clock_id, const struct timespec* abstime) 135 { 136 if (abstime == NULL || abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000 * 1000 * 1000) 137 RETURN_AND_TEST_CANCEL(EINVAL); 138 139 bigtime_t timeoutMicros = ((bigtime_t)abstime->tv_sec) * 1000000 140 + abstime->tv_nsec / 1000; 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