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