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 1165a76a0fSAugustin 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> 18*b8fdef84SAugustin Cavalier #include <time_private.h> 19f7127458SIngo Weinhold 20f7127458SIngo Weinhold 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 776f3f29c7SAugustin Cavalier const int32 oldValue = atomic_test_and_set((int32*)&mutex->lock, B_USER_MUTEX_LOCKED, 0); 786f3f29c7SAugustin Cavalier if (oldValue != 0) { 79f7127458SIngo Weinhold // someone else has the lock or is at least waiting for it 80f7127458SIngo Weinhold if (timeout < 0) 81f7127458SIngo Weinhold return EBUSY; 8293d7d1c5SAugustin Cavalier if ((mutex->flags & MUTEX_FLAG_SHARED) != 0) 8393d7d1c5SAugustin Cavalier flags |= B_USER_MUTEX_SHARED; 84f7127458SIngo Weinhold 85f7127458SIngo Weinhold // we have to call the kernel 86f7127458SIngo Weinhold status_t error; 87f7127458SIngo Weinhold do { 88e41d4bd1SJérôme Duval error = _kern_mutex_lock((int32*)&mutex->lock, NULL, flags, timeout); 89f7127458SIngo Weinhold } while (error == B_INTERRUPTED); 90f7127458SIngo Weinhold 91f7127458SIngo Weinhold if (error != B_OK) 92f7127458SIngo Weinhold return error; 93f7127458SIngo Weinhold } 94f7127458SIngo Weinhold 95f7127458SIngo Weinhold // we have locked the mutex for the first time 9665a76a0fSAugustin Cavalier assert(mutex->owner == -1); 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 { 107e41d4bd1SJérôme Duval return __pthread_mutex_lock(mutex, 0, B_INFINITE_TIMEOUT); 108f7127458SIngo Weinhold } 109f7127458SIngo Weinhold 110f7127458SIngo Weinhold 111f7127458SIngo Weinhold int 112f7127458SIngo Weinhold pthread_mutex_trylock(pthread_mutex_t* mutex) 113f7127458SIngo Weinhold { 114e41d4bd1SJérôme Duval return __pthread_mutex_lock(mutex, B_ABSOLUTE_REAL_TIME_TIMEOUT, -1); 115f7127458SIngo Weinhold } 116f7127458SIngo Weinhold 117f7127458SIngo Weinhold 118f7127458SIngo Weinhold int 119e41d4bd1SJérôme Duval pthread_mutex_clocklock(pthread_mutex_t* mutex, clockid_t clock_id, 120e41d4bd1SJérôme Duval const struct timespec* abstime) 121f7127458SIngo Weinhold { 122f7127458SIngo Weinhold bigtime_t timeout = 0; 123*b8fdef84SAugustin Cavalier bool invalidTime = false; 124*b8fdef84SAugustin Cavalier if (abstime == NULL || !timespec_to_bigtime(*abstime, timeout)) 125f7127458SIngo Weinhold invalidTime = true; 126f7127458SIngo Weinhold 127e41d4bd1SJérôme Duval uint32 flags = 0; 128e41d4bd1SJérôme Duval switch (clock_id) { 129e41d4bd1SJérôme Duval case CLOCK_REALTIME: 130e41d4bd1SJérôme Duval flags = B_ABSOLUTE_REAL_TIME_TIMEOUT; 131e41d4bd1SJérôme Duval break; 132e41d4bd1SJérôme Duval case CLOCK_MONOTONIC: 133e41d4bd1SJérôme Duval flags = B_ABSOLUTE_TIMEOUT; 134e41d4bd1SJérôme Duval break; 135e41d4bd1SJérôme Duval default: 136e41d4bd1SJérôme Duval invalidTime = true; 137e41d4bd1SJérôme Duval break; 138e41d4bd1SJérôme Duval } 139e41d4bd1SJérôme Duval 140e41d4bd1SJérôme Duval status_t status = __pthread_mutex_lock(mutex, flags, timeout); 141f7127458SIngo Weinhold if (status != B_OK && invalidTime) { 142f7127458SIngo Weinhold // The timespec was not valid and the mutex could not be locked 143f7127458SIngo Weinhold // immediately. 144f7127458SIngo Weinhold return EINVAL; 145f7127458SIngo Weinhold } 146f7127458SIngo Weinhold 147f7127458SIngo Weinhold return status; 148f7127458SIngo Weinhold } 149f7127458SIngo Weinhold 150f7127458SIngo Weinhold 151f7127458SIngo Weinhold int 152e41d4bd1SJérôme Duval pthread_mutex_timedlock(pthread_mutex_t* mutex, const struct timespec* abstime) 153e41d4bd1SJérôme Duval { 154e41d4bd1SJérôme Duval return pthread_mutex_clocklock(mutex, CLOCK_REALTIME, abstime); 155e41d4bd1SJérôme Duval } 156e41d4bd1SJérôme Duval 157e41d4bd1SJérôme Duval 158e41d4bd1SJérôme Duval int 159f7127458SIngo Weinhold pthread_mutex_unlock(pthread_mutex_t* mutex) 160f7127458SIngo Weinhold { 161f7127458SIngo Weinhold if (mutex->owner != find_thread(NULL)) 162f7127458SIngo Weinhold return EPERM; 163f7127458SIngo Weinhold 164f7127458SIngo Weinhold if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_RECURSIVE 165f7127458SIngo Weinhold && --mutex->owner_count > 0) { 166f7127458SIngo Weinhold // still locked 167f7127458SIngo Weinhold return 0; 168f7127458SIngo Weinhold } 169f7127458SIngo Weinhold 170f7127458SIngo Weinhold mutex->owner = -1; 171f7127458SIngo Weinhold 172f7127458SIngo Weinhold // clear the locked flag 173f7127458SIngo Weinhold int32 oldValue = atomic_and((int32*)&mutex->lock, 174f7127458SIngo Weinhold ~(int32)B_USER_MUTEX_LOCKED); 17593d7d1c5SAugustin Cavalier if ((oldValue & B_USER_MUTEX_WAITING) != 0) { 17693d7d1c5SAugustin Cavalier _kern_mutex_unblock((int32*)&mutex->lock, 17793d7d1c5SAugustin Cavalier (mutex->flags & MUTEX_FLAG_SHARED) ? B_USER_MUTEX_SHARED : 0); 17893d7d1c5SAugustin Cavalier } 179f7127458SIngo Weinhold 18065a76a0fSAugustin Cavalier if (MUTEX_TYPE(mutex) == PTHREAD_MUTEX_ERRORCHECK 18165a76a0fSAugustin Cavalier || MUTEX_TYPE(mutex) == PTHREAD_MUTEX_DEFAULT) { 18265a76a0fSAugustin Cavalier if ((oldValue & B_USER_MUTEX_LOCKED) == 0) 18365a76a0fSAugustin Cavalier return EPERM; 18465a76a0fSAugustin Cavalier } 18565a76a0fSAugustin Cavalier 186f7127458SIngo Weinhold return 0; 187f7127458SIngo Weinhold } 188f7127458SIngo Weinhold 189f7127458SIngo Weinhold 190f7127458SIngo Weinhold int 1910bec83a8SJérôme Duval pthread_mutex_getprioceiling(const pthread_mutex_t* mutex, int* _prioCeiling) 192f7127458SIngo Weinhold { 193f7127458SIngo Weinhold if (mutex == NULL || _prioCeiling == NULL) 194f7127458SIngo Weinhold return EINVAL; 195f7127458SIngo Weinhold 196f7127458SIngo Weinhold *_prioCeiling = 0; 197f7127458SIngo Weinhold // not implemented 198f7127458SIngo Weinhold 199f7127458SIngo Weinhold return 0; 200f7127458SIngo Weinhold } 201f7127458SIngo Weinhold 202f7127458SIngo Weinhold 203f7127458SIngo Weinhold int 204f7127458SIngo Weinhold pthread_mutex_setprioceiling(pthread_mutex_t* mutex, int prioCeiling, 205f7127458SIngo Weinhold int* _oldCeiling) 206f7127458SIngo Weinhold { 207f7127458SIngo Weinhold if (mutex == NULL) 208f7127458SIngo Weinhold return EINVAL; 209f7127458SIngo Weinhold 210f7127458SIngo Weinhold // not implemented 211f7127458SIngo Weinhold return EPERM; 212f7127458SIngo Weinhold } 213