//===--- MutexPThread.cpp - Supports Mutex.h using PThreads ---------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Mutex and Read/Write lock implementations using pthreads. // // Darwin shares the pthreads implementation for read/write locks, but // uses inline implementations for os_unfair_lock. // //===----------------------------------------------------------------------===// #if __has_include() #include #endif #if defined(_POSIX_THREADS) && !defined(SWIFT_STDLIB_SINGLE_THREADED_RUNTIME) // Notes: swift::fatalError is not shared between libswiftCore and libswift_Concurrency // and libswift_Concurrency uses swift_Concurrency_fatalError instead. #ifndef SWIFT_FATAL_ERROR #define SWIFT_FATAL_ERROR swift::fatalError #endif #include "swift/Runtime/Mutex.h" #include "swift/Runtime/Debug.h" #include #include using namespace swift; #define reportError(PThreadFunction) \ do { \ int errorcode = PThreadFunction; \ if (errorcode != 0) { \ SWIFT_FATAL_ERROR(/* flags = */ 0, "'%s' failed with error '%s'(%d)\n", \ #PThreadFunction, errorName(errorcode), errorcode); \ } \ } while (false) #define returnTrueOrReportError(PThreadFunction, returnFalseOnEBUSY) \ do { \ int errorcode = PThreadFunction; \ if (errorcode == 0) \ return true; \ if (returnFalseOnEBUSY && errorcode == EBUSY) \ return false; \ SWIFT_FATAL_ERROR(/* flags = */ 0, "'%s' failed with error '%s'(%d)\n", \ #PThreadFunction, errorName(errorcode), errorcode); \ } while (false) static const char *errorName(int errorcode) { switch (errorcode) { case EINVAL: return "EINVAL"; case EPERM: return "EPERM"; case EDEADLK: return "EDEADLK"; case ENOMEM: return "ENOMEM"; case EAGAIN: return "EAGAIN"; case EBUSY: return "EBUSY"; default: return ""; } } #if !HAS_OS_UNFAIR_LOCK void MutexPlatformHelper::init(pthread_mutex_t &mutex, bool checked) { pthread_mutexattr_t attr; int kind = (checked ? PTHREAD_MUTEX_ERRORCHECK : PTHREAD_MUTEX_NORMAL); reportError(pthread_mutexattr_init(&attr)); reportError(pthread_mutexattr_settype(&attr, kind)); reportError(pthread_mutex_init(&mutex, &attr)); reportError(pthread_mutexattr_destroy(&attr)); } void MutexPlatformHelper::destroy(pthread_mutex_t &mutex) { reportError(pthread_mutex_destroy(&mutex)); } void MutexPlatformHelper::lock(pthread_mutex_t &mutex) { reportError(pthread_mutex_lock(&mutex)); } void MutexPlatformHelper::unlock(pthread_mutex_t &mutex) { reportError(pthread_mutex_unlock(&mutex)); } bool MutexPlatformHelper::try_lock(pthread_mutex_t &mutex) { returnTrueOrReportError(pthread_mutex_trylock(&mutex), /* returnFalseOnEBUSY = */ true); } #endif void ReadWriteLockPlatformHelper::init(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_init(&rwlock, nullptr)); } void ReadWriteLockPlatformHelper::destroy(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_destroy(&rwlock)); } void ReadWriteLockPlatformHelper::readLock(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_rdlock(&rwlock)); } bool ReadWriteLockPlatformHelper::try_readLock(pthread_rwlock_t &rwlock) { returnTrueOrReportError(pthread_rwlock_tryrdlock(&rwlock), /* returnFalseOnEBUSY = */ true); } void ReadWriteLockPlatformHelper::writeLock(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_wrlock(&rwlock)); } bool ReadWriteLockPlatformHelper::try_writeLock(pthread_rwlock_t &rwlock) { returnTrueOrReportError(pthread_rwlock_trywrlock(&rwlock), /* returnFalseOnEBUSY = */ true); } void ReadWriteLockPlatformHelper::readUnlock(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_unlock(&rwlock)); } void ReadWriteLockPlatformHelper::writeUnlock(pthread_rwlock_t &rwlock) { reportError(pthread_rwlock_unlock(&rwlock)); } #endif