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, bigtime_t timeout) 61 { 62 if (mutex->owner != find_thread(NULL)) { 63 // calling thread isn't mutex owner 64 return EPERM; 65 } 66 67 if (cond->mutex != NULL && cond->mutex != mutex) { 68 // condition variable already used with different mutex 69 return EINVAL; 70 } 71 72 cond->mutex = mutex; 73 cond->waiter_count++; 74 75 // make sure the user mutex we use for blocking is locked 76 atomic_or((int32*)&cond->lock, B_USER_MUTEX_LOCKED); 77 78 // atomically unlock the mutex and start waiting on the user mutex 79 mutex->owner = -1; 80 mutex->owner_count = 0; 81 82 int32 flags = (cond->flags & COND_FLAG_MONOTONIC) != 0 ? B_ABSOLUTE_TIMEOUT 83 : B_ABSOLUTE_REAL_TIME_TIMEOUT; 84 85 status_t status = _kern_mutex_switch_lock((int32*)&mutex->lock, 86 (int32*)&cond->lock, "pthread condition", 87 timeout == B_INFINITE_TIMEOUT ? 0 : 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 // If there are no more waiters, we can change mutexes. 99 if (cond->waiter_count == 0) 100 cond->mutex = NULL; 101 102 return status; 103 } 104 105 106 static inline void 107 cond_signal(pthread_cond_t* cond, bool broadcast) 108 { 109 if (cond->waiter_count == 0) 110 return; 111 112 // release the condition lock 113 _kern_mutex_unlock((int32*)&cond->lock, 114 broadcast ? B_USER_MUTEX_UNBLOCK_ALL : 0); 115 } 116 117 118 int 119 pthread_cond_wait(pthread_cond_t* cond, pthread_mutex_t* _mutex) 120 { 121 RETURN_AND_TEST_CANCEL(cond_wait(cond, _mutex, B_INFINITE_TIMEOUT)); 122 } 123 124 125 int 126 pthread_cond_timedwait(pthread_cond_t* cond, pthread_mutex_t* mutex, 127 const struct timespec* tv) 128 { 129 if (tv == NULL || tv->tv_nsec < 0 || tv->tv_nsec >= 1000 * 1000 * 1000) 130 RETURN_AND_TEST_CANCEL(EINVAL); 131 132 RETURN_AND_TEST_CANCEL( 133 cond_wait(cond, mutex, tv->tv_sec * 1000000LL + tv->tv_nsec / 1000LL)); 134 } 135 136 137 int 138 pthread_cond_broadcast(pthread_cond_t* cond) 139 { 140 cond_signal(cond, true); 141 return 0; 142 } 143 144 145 int 146 pthread_cond_signal(pthread_cond_t* cond) 147 { 148 cond_signal(cond, false); 149 return 0; 150 } 151