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