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 <assert.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 16 #include <syscalls.h> 17 #include <user_mutex_defs.h> 18 19 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 status_t 53 __pthread_mutex_lock(pthread_mutex_t* mutex, uint32 flags, 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 const int32 oldValue = atomic_test_and_set((int32*)&mutex->lock, B_USER_MUTEX_LOCKED, 0); 77 if (oldValue != 0) { 78 // someone else has the lock or is at least waiting for it 79 if (timeout < 0) 80 return EBUSY; 81 if ((mutex->flags & MUTEX_FLAG_SHARED) != 0) 82 flags |= B_USER_MUTEX_SHARED; 83 84 // we have to call the kernel 85 status_t error; 86 do { 87 error = _kern_mutex_lock((int32*)&mutex->lock, NULL, flags, timeout); 88 } while (error == B_INTERRUPTED); 89 90 if (error != B_OK) 91 return error; 92 } 93 94 // we have locked the mutex for the first time 95 assert(mutex->owner == -1); 96 mutex->owner = thisThread; 97 mutex->owner_count = 1; 98 99 return 0; 100 } 101 102 103 int 104 pthread_mutex_lock(pthread_mutex_t* mutex) 105 { 106 return __pthread_mutex_lock(mutex, 0, B_INFINITE_TIMEOUT); 107 } 108 109 110 int 111 pthread_mutex_trylock(pthread_mutex_t* mutex) 112 { 113 return __pthread_mutex_lock(mutex, B_ABSOLUTE_REAL_TIME_TIMEOUT, -1); 114 } 115 116 117 int 118 pthread_mutex_clocklock(pthread_mutex_t* mutex, clockid_t clock_id, 119 const struct timespec* abstime) 120 { 121 // translate the timeout 122 bool invalidTime = false; 123 bigtime_t timeout = 0; 124 if (abstime != NULL && abstime->tv_nsec < 1000 * 1000 * 1000 125 && abstime->tv_nsec >= 0) { 126 timeout = abstime->tv_sec * 1000000LL + abstime->tv_nsec / 1000LL; 127 } else 128 invalidTime = true; 129 130 uint32 flags = 0; 131 switch (clock_id) { 132 case CLOCK_REALTIME: 133 flags = B_ABSOLUTE_REAL_TIME_TIMEOUT; 134 break; 135 case CLOCK_MONOTONIC: 136 flags = B_ABSOLUTE_TIMEOUT; 137 break; 138 default: 139 invalidTime = true; 140 break; 141 } 142 143 status_t status = __pthread_mutex_lock(mutex, flags, timeout); 144 if (status != B_OK && invalidTime) { 145 // The timespec was not valid and the mutex could not be locked 146 // immediately. 147 return EINVAL; 148 } 149 150 return status; 151 } 152 153 154 int 155 pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* abstime) 156 { 157 return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime); 158 } 159 160 161 int 162 pthread_mutex_unlock(pthread_mutex_t* mutex) 163 { 164 if (mutex->owner != find_thread(NULL)) 165 return EPERM; 166 167 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE 168 && --mutex->owner_count > 0) { 169 // still locked 170 return 0; 171 } 172 173 mutex->owner = -1; 174 175 // clear the locked flag 176 int32 oldValue = atomic_and((int32*)&mutex->lock, 177 ~(int32)B_USER_MUTEX_LOCKED); 178 if ((oldValue & B_USER_MUTEX_WAITING) != 0) { 179 _kern_mutex_unblock((int32*)&mutex->lock, 180 (mutex->flags & MUTEX_FLAG_SHARED) ? B_USER_MUTEX_SHARED : 0); 181 } 182 183 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK 184 || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) { 185 if ((oldValue & B_USER_MUTEX_LOCKED) == 0) 186 return EPERM; 187 } 188 189 return 0; 190 } 191 192 193 int 194 pthread_mutex_getprioceiling(const pthread_mutex_t* mutex, int* _prioCeiling) 195 { 196 if (mutex == NULL || _prioCeiling == NULL) 197 return EINVAL; 198 199 *_prioCeiling = 0; 200 // not implemented 201 202 return 0; 203 } 204 205 206 int 207 pthread_mutex_setprioceiling(pthread_mutex_t* mutex, int prioCeiling, 208 int* _oldCeiling) 209 { 210 if (mutex == NULL) 211 return EINVAL; 212 213 // not implemented 214 return EPERM; 215 } 216