//------------------------------------------------------------------------------ // File: PthreadRWMutex.cc //------------------------------------------------------------------------------ /************************************************************************ * EOS - the CERN Disk Storage System * * Copyright (C) 2018 CERN/Switzerland * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see .* ************************************************************************/ #include "common/PthreadRWMutex.hh" #include "common/Timing.hh" #include #include EOSCOMMONNAMESPACE_BEGIN //------------------------------------------------------------------------------ // Constructor //------------------------------------------------------------------------------ PthreadRWMutex::PthreadRWMutex(bool prefer_readers) { int retc = 0; pthread_rwlockattr_init(&mAttr); #ifndef __APPLE__ if (prefer_readers) { // Readers go ahead of writers and are reentrant if ((retc = pthread_rwlockattr_setkind_np(&mAttr, PTHREAD_RWLOCK_PREFER_WRITER_NP))) { fprintf(stderr, "%s Failed to set readers priority: %s\n", __FUNCTION__, strerror(retc)); std::terminate(); } } else { // Readers don't go ahead of writers! if ((retc = pthread_rwlockattr_setkind_np(&mAttr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP))) { fprintf(stderr, "%s Failed to set writers priority: %s\n", __FUNCTION__, strerror(retc)); std::terminate(); } } #endif if ((retc = pthread_rwlockattr_setpshared(&mAttr, PTHREAD_PROCESS_SHARED))) { fprintf(stderr, "%s Failed to set process shared mutex: %s\n", __FUNCTION__, strerror(retc)); std::terminate(); } if ((retc = pthread_rwlock_init(&mMutex, &mAttr))) { fprintf(stderr, "%s Failed to initialize mutex: %s\n", __FUNCTION__, strerror(retc)); std::terminate(); } } //------------------------------------------------------------------------------ // Lock for read //------------------------------------------------------------------------------ int PthreadRWMutex::LockRead() { return pthread_rwlock_rdlock(&mMutex); } //------------------------------------------------------------------------------ // Try to read lock the mutex within the timeout //------------------------------------------------------------------------------ int PthreadRWMutex::TimedRdLock(uint64_t timeout_ns) { int retc = 0; struct timespec timeout = {0}; _clock_gettime(CLOCK_REALTIME, &timeout); if (timeout_ns) { if (timeout_ns > 1e9) { timeout.tv_sec += (timeout_ns / 1e9); } timeout.tv_nsec += (timeout_ns % (unsigned long long)1e9); } #ifdef __APPLE__ // Mac does not support timed mutexes retc = pthread_rwlock_rdlock(&mMutex); #else retc = pthread_rwlock_timedrdlock(&mMutex, &timeout); #endif return retc; } //------------------------------------------------------------------------------ // Unlock a read lock //------------------------------------------------------------------------------ int PthreadRWMutex::UnLockRead() { return pthread_rwlock_unlock(&mMutex); } //------------------------------------------------------------------------------ // Lock for write //------------------------------------------------------------------------------ int PthreadRWMutex::LockWrite() { return pthread_rwlock_wrlock(&mMutex); } //------------------------------------------------------------------------------ // Unlock a write lock //------------------------------------------------------------------------------ int PthreadRWMutex::UnLockWrite() { return pthread_rwlock_unlock(&mMutex); } //------------------------------------------------------------------------------ // Try to write lock the mutex within the timeout //------------------------------------------------------------------------------ int PthreadRWMutex::TimedWrLock(uint64_t timeout_ns) { int retc = 0; struct timespec timeout = {0}; _clock_gettime(CLOCK_REALTIME, &timeout); if (timeout_ns) { if (timeout_ns > 1e9) { timeout.tv_sec += (timeout_ns / 1e9); } timeout.tv_nsec += (timeout_ns % (unsigned long long)1e9); } #ifdef __APPLE__ // Mac does not support timed mutexes retc = pthread_rwlock_wrlock(&mMutex); #else retc = pthread_rwlock_timedwrlock(&mMutex, &timeout); #endif return retc; } EOSCOMMONNAMESPACE_END