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