| /* |
| * 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 <stdint.h> |
| #include <errno.h> |
| #include <pthread.h> |
| #include <sys/time.h> |
| |
| #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__ |
| |