1 /* 2 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2003-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 4 * Distributed under the terms of the MIT License. 5 */ 6 7 8 #include <pthread.h> 9 #include "pthread_private.h" 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 15 #include <syscalls.h> 16 #include <user_mutex_defs.h> 17 18 19 #define MUTEX_FLAG_SHARED 0x80000000 20 #define MUTEX_TYPE_BITS 0x0000000f 21 #define MUTEX_TYPE(mutex) ((mutex)->flags & MUTEX_TYPE_BITS) 22 23 24 static const pthread_mutexattr pthread_mutexattr_default = { 25 PTHREAD_MUTEX_DEFAULT, 26 false 27 }; 28 29 30 int 31 pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* _attr) 32 { 33 const pthread_mutexattr* attr = _attr != NULL 34 ? *_attr : &pthread_mutexattr_default; 35 36 mutex->lock = 0; 37 mutex->owner = -1; 38 mutex->owner_count = 0; 39 mutex->flags = attr->type | (attr->process_shared ? MUTEX_FLAG_SHARED : 0); 40 41 return 0; 42 } 43 44 45 int 46 pthread_mutex_destroy(pthread_mutex_t* mutex) 47 { 48 return 0; 49 } 50 51 52 static status_t 53 mutex_lock(pthread_mutex_t* mutex, bigtime_t timeout) 54 { 55 thread_id thisThread = find_thread(NULL); 56 57 if (mutex->owner == thisThread) { 58 // recursive locking handling 59 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE) { 60 if (mutex->owner_count == INT32_MAX) 61 return EAGAIN; 62 63 mutex->owner_count++; 64 return 0; 65 } 66 67 // deadlock check (not for PTHREAD_MUTEX_NORMAL as per the specs) 68 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK 69 || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) { 70 // we detect this kind of deadlock and return an error 71 return timeout < 0 ? EBUSY : EDEADLK; 72 } 73 } 74 75 // set the locked flag 76 int32 oldValue = atomic_or((int32*)&mutex->lock, B_USER_MUTEX_LOCKED); 77 78 if ((oldValue & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) != 0) { 79 // someone else has the lock or is at least waiting for it 80 if (timeout < 0) 81 return EBUSY; 82 83 // we have to call the kernel 84 status_t error; 85 do { 86 error = _kern_mutex_lock((int32*)&mutex->lock, NULL, 87 timeout == B_INFINITE_TIMEOUT 88 ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT, 89 timeout); 90 } while (error == B_INTERRUPTED); 91 92 if (error != B_OK) 93 return error; 94 } 95 96 // we have locked the mutex for the first time 97 mutex->owner = thisThread; 98 mutex->owner_count = 1; 99 100 return 0; 101 } 102 103 104 int 105 pthread_mutex_lock(pthread_mutex_t* mutex) 106 { 107 return mutex_lock(mutex, B_INFINITE_TIMEOUT); 108 } 109 110 111 int 112 pthread_mutex_trylock(pthread_mutex_t* mutex) 113 { 114 return mutex_lock(mutex, -1); 115 } 116 117 118 int 119 pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* tv) 120 { 121 // translate the timeout 122 bool invalidTime = false; 123 bigtime_t timeout = 0; 124 if (tv && tv->tv_nsec < 1000 * 1000 * 1000 && tv->tv_nsec >= 0) 125 timeout = tv->tv_sec * 1000000LL + tv->tv_nsec / 1000LL; 126 else 127 invalidTime = true; 128 129 status_t status = mutex_lock(mutex, timeout); 130 if (status != B_OK && invalidTime) { 131 // The timespec was not valid and the mutex could not be locked 132 // immediately. 133 return EINVAL; 134 } 135 136 return status; 137 } 138 139 140 int 141 pthread_mutex_unlock(pthread_mutex_t* mutex) 142 { 143 if (mutex->owner != find_thread(NULL)) 144 return EPERM; 145 146 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE 147 && --mutex->owner_count > 0) { 148 // still locked 149 return 0; 150 } 151 152 mutex->owner = -1; 153 154 // clear the locked flag 155 int32 oldValue = atomic_and((int32*)&mutex->lock, 156 ~(int32)B_USER_MUTEX_LOCKED); 157 if ((oldValue & B_USER_MUTEX_WAITING) != 0) 158 _kern_mutex_unlock((int32*)&mutex->lock, 0); 159 160 return 0; 161 } 162 163 164 int 165 pthread_mutex_getprioceiling(pthread_mutex_t* mutex, int* _prioCeiling) 166 { 167 if (mutex == NULL || _prioCeiling == NULL) 168 return EINVAL; 169 170 *_prioCeiling = 0; 171 // not implemented 172 173 return 0; 174 } 175 176 177 int 178 pthread_mutex_setprioceiling(pthread_mutex_t* mutex, int prioCeiling, 179 int* _oldCeiling) 180 { 181 if (mutex == NULL) 182 return EINVAL; 183 184 // not implemented 185 return EPERM; 186 } 187