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 #include <time_private.h> 19 20 21 #define MUTEX_TYPE_BITS 0x0000000f 22 #define MUTEX_TYPE(mutex) ((mutex)->flags & MUTEX_TYPE_BITS) 23 24 25 static const pthread_mutexattr pthread_mutexattr_default = { 26 PTHREAD_MUTEX_DEFAULT, 27 false 28 }; 29 30 31 int 32 pthread_mutex_init(pthread_mutex_t* mutex, const pthread_mutexattr_t* _attr) 33 { 34 const pthread_mutexattr* attr = _attr != NULL 35 ? *_attr : &pthread_mutexattr_default; 36 37 mutex->lock = 0; 38 mutex->owner = -1; 39 mutex->owner_count = 0; 40 mutex->flags = attr->type | (attr->process_shared ? MUTEX_FLAG_SHARED : 0); 41 42 return 0; 43 } 44 45 46 int 47 pthread_mutex_destroy(pthread_mutex_t* mutex) 48 { 49 return 0; 50 } 51 52 53 status_t 54 __pthread_mutex_lock(pthread_mutex_t* mutex, uint32 flags, bigtime_t timeout) 55 { 56 thread_id thisThread = find_thread(NULL); 57 58 if (mutex->owner == thisThread) { 59 // recursive locking handling 60 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE) { 61 if (mutex->owner_count == INT32_MAX) 62 return EAGAIN; 63 64 mutex->owner_count++; 65 return 0; 66 } 67 68 // deadlock check (not for PTHREAD_MUTEX_NORMAL as per the specs) 69 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK 70 || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) { 71 // we detect this kind of deadlock and return an error 72 return timeout < 0 ? EBUSY : EDEADLK; 73 } 74 } 75 76 // set the locked flag 77 const int32 oldValue = atomic_test_and_set((int32*)&mutex->lock, B_USER_MUTEX_LOCKED, 0); 78 if (oldValue != 0) { 79 // someone else has the lock or is at least waiting for it 80 if (timeout < 0) 81 return EBUSY; 82 if ((mutex->flags & MUTEX_FLAG_SHARED) != 0) 83 flags |= B_USER_MUTEX_SHARED; 84 85 // we have to call the kernel 86 status_t error; 87 do { 88 error = _kern_mutex_lock((int32*)&mutex->lock, NULL, flags, timeout); 89 } while (error == B_INTERRUPTED); 90 91 if (error != B_OK) 92 return error; 93 } 94 95 // we have locked the mutex for the first time 96 assert(mutex->owner == -1); 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 __pthread_mutex_lock(mutex, 0, B_INFINITE_TIMEOUT); 108 } 109 110 111 int 112 pthread_mutex_trylock(pthread_mutex_t* mutex) 113 { 114 return __pthread_mutex_lock(mutex, B_ABSOLUTE_REAL_TIME_TIMEOUT, -1); 115 } 116 117 118 int 119 pthread_mutex_clocklock(pthread_mutex_t* mutex, clockid_t clock_id, 120 const struct timespec* abstime) 121 { 122 bigtime_t timeout = 0; 123 bool invalidTime = false; 124 if (abstime == NULL || !timespec_to_bigtime(*abstime, timeout)) 125 invalidTime = true; 126 127 uint32 flags = 0; 128 switch (clock_id) { 129 case CLOCK_REALTIME: 130 flags = B_ABSOLUTE_REAL_TIME_TIMEOUT; 131 break; 132 case CLOCK_MONOTONIC: 133 flags = B_ABSOLUTE_TIMEOUT; 134 break; 135 default: 136 invalidTime = true; 137 break; 138 } 139 140 status_t status = __pthread_mutex_lock(mutex, flags, timeout); 141 142 if (status != B_OK && invalidTime) 143 return EINVAL; 144 return status; 145 } 146 147 148 int 149 pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* abstime) 150 { 151 return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime); 152 } 153 154 155 int 156 pthread_mutex_unlock(pthread_mutex_t* mutex) 157 { 158 if (mutex->owner != find_thread(NULL)) 159 return EPERM; 160 161 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE 162 && --mutex->owner_count > 0) { 163 // still locked 164 return 0; 165 } 166 167 mutex->owner = -1; 168 169 // clear the locked flag 170 int32 oldValue = atomic_and((int32*)&mutex->lock, 171 ~(int32)B_USER_MUTEX_LOCKED); 172 if ((oldValue & B_USER_MUTEX_WAITING) != 0) { 173 _kern_mutex_unblock((int32*)&mutex->lock, 174 (mutex->flags & MUTEX_FLAG_SHARED) ? B_USER_MUTEX_SHARED : 0); 175 } 176 177 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK 178 || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) { 179 if ((oldValue & B_USER_MUTEX_LOCKED) == 0) 180 return EPERM; 181 } 182 183 return 0; 184 } 185 186 187 int 188 pthread_mutex_getprioceiling(const pthread_mutex_t* mutex, int* _prioCeiling) 189 { 190 if (mutex == NULL || _prioCeiling == NULL) 191 return EINVAL; 192 193 *_prioCeiling = 0; 194 // not implemented 195 196 return 0; 197 } 198 199 200 int 201 pthread_mutex_setprioceiling(pthread_mutex_t* mutex, int prioCeiling, 202 int* _oldCeiling) 203 { 204 if (mutex == NULL) 205 return EINVAL; 206 207 // not implemented 208 return EPERM; 209 } 210