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 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 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, flags, timeout); 87 } while (error == B_INTERRUPTED); 88 89 if (error != B_OK) 90 return error; 91 } 92 93 // we have locked the mutex for the first time 94 mutex->owner = thisThread; 95 mutex->owner_count = 1; 96 97 return 0; 98 } 99 100 101 int 102 pthread_mutex_lock(pthread_mutex_t* mutex) 103 { 104 return __pthread_mutex_lock(mutex, 0, B_INFINITE_TIMEOUT); 105 } 106 107 108 int 109 pthread_mutex_trylock(pthread_mutex_t* mutex) 110 { 111 return __pthread_mutex_lock(mutex, B_ABSOLUTE_REAL_TIME_TIMEOUT, -1); 112 } 113 114 115 int 116 pthread_mutex_clocklock(pthread_mutex_t* mutex, clockid_t clock_id, 117 const struct timespec* abstime) 118 { 119 // translate the timeout 120 bool invalidTime = false; 121 bigtime_t timeout = 0; 122 if (abstime != NULL && abstime->tv_nsec < 1000 * 1000 * 1000 123 && abstime->tv_nsec >= 0) { 124 timeout = abstime->tv_sec * 1000000LL + abstime->tv_nsec / 1000LL; 125 } else 126 invalidTime = true; 127 128 uint32 flags = 0; 129 switch (clock_id) { 130 case CLOCK_REALTIME: 131 flags = B_ABSOLUTE_REAL_TIME_TIMEOUT; 132 break; 133 case CLOCK_MONOTONIC: 134 flags = B_ABSOLUTE_TIMEOUT; 135 break; 136 default: 137 invalidTime = true; 138 break; 139 } 140 141 status_t status = __pthread_mutex_lock(mutex, flags, timeout); 142 if (status != B_OK && invalidTime) { 143 // The timespec was not valid and the mutex could not be locked 144 // immediately. 145 return EINVAL; 146 } 147 148 return status; 149 } 150 151 152 int 153 pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* abstime) 154 { 155 return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime); 156 } 157 158 159 int 160 pthread_mutex_unlock(pthread_mutex_t* mutex) 161 { 162 if (mutex->owner != find_thread(NULL)) 163 return EPERM; 164 165 if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE 166 && --mutex->owner_count > 0) { 167 // still locked 168 return 0; 169 } 170 171 mutex->owner = -1; 172 173 // clear the locked flag 174 int32 oldValue = atomic_and((int32*)&mutex->lock, 175 ~(int32)B_USER_MUTEX_LOCKED); 176 if ((oldValue & B_USER_MUTEX_WAITING) != 0) 177 _kern_mutex_unlock((int32*)&mutex->lock, 0); 178 179 return 0; 180 } 181 182 183 int 184 pthread_mutex_getprioceiling(const pthread_mutex_t* mutex, int* _prioCeiling) 185 { 186 if (mutex == NULL || _prioCeiling == NULL) 187 return EINVAL; 188 189 *_prioCeiling = 0; 190 // not implemented 191 192 return 0; 193 } 194 195 196 int 197 pthread_mutex_setprioceiling(pthread_mutex_t* mutex, int prioCeiling, 198 int* _oldCeiling) 199 { 200 if (mutex == NULL) 201 return EINVAL; 202 203 // not implemented 204 return EPERM; 205 } 206