/* * Copyright (c) 2014 - 2016, 2018 The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted * provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this list of * conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its contributors may be used to * endorse or promote products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __LOCKER_H__ #define __LOCKER_H__ #include #include #include #include #define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker) #define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker) #define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker) #define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker) #define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker) namespace sdm { class Locker { public: class ScopeLock { public: explicit ScopeLock(Locker& locker) : locker_(locker) { locker_.Lock(); } ~ScopeLock() { locker_.Unlock(); } private: Locker &locker_; }; class SequenceEntryScopeLock { public: explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) { locker_.Lock(); locker_.sequence_wait_ = 1; } ~SequenceEntryScopeLock() { locker_.Unlock(); } private: Locker &locker_; }; class SequenceExitScopeLock { public: explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) { locker_.Lock(); locker_.sequence_wait_ = 0; } ~SequenceExitScopeLock() { locker_.Broadcast(); locker_.Unlock(); } private: Locker &locker_; }; class SequenceWaitScopeLock { public: explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) { locker_.Lock(); while (locker_.sequence_wait_ == 1) { locker_.Wait(); error_ = (locker_.sequence_wait_ == -1); } } ~SequenceWaitScopeLock() { locker_.Unlock(); } bool IsError() { return error_; } private: Locker &locker_; bool error_; }; class SequenceCancelScopeLock { public: explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) { locker_.Lock(); locker_.sequence_wait_ = -1; } ~SequenceCancelScopeLock() { locker_.Broadcast(); locker_.Unlock(); } private: Locker &locker_; }; Locker() : sequence_wait_(0) { pthread_mutex_init(&mutex_, 0); pthread_condattr_init(&cond_attr); pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC); pthread_cond_init(&condition_, &cond_attr); } ~Locker() { pthread_mutex_destroy(&mutex_); pthread_cond_destroy(&condition_); pthread_condattr_destroy(&cond_attr); } void Lock() { pthread_mutex_lock(&mutex_); } void Unlock() { pthread_mutex_unlock(&mutex_); } void Signal() { pthread_cond_signal(&condition_); } void Broadcast() { pthread_cond_broadcast(&condition_); } void Wait() { pthread_cond_wait(&condition_, &mutex_); } int WaitFinite(uint32_t ms) { struct timespec ts; if (clock_gettime(CLOCK_MONOTONIC, &ts)) { return EINVAL; } uint64_t ns = (uint64_t)ts.tv_nsec + (ms * 1000000L); ts.tv_sec = ts.tv_sec + (time_t)(ns / 1000000000L); ts.tv_nsec = ns % 1000000000L; return pthread_cond_timedwait(&condition_, &mutex_, &ts); } private: pthread_mutex_t mutex_; pthread_cond_t condition_; pthread_condattr_t cond_attr; int sequence_wait_; // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel. // Some routines will wait for sequence of function calls to finish // so that capturing a transitionary snapshot of context is prevented. // If flag is set to -1, these routines will exit without doing any // further processing. }; } // namespace sdm #endif // __LOCKER_H__