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