1 /* 2 * Copyright (c) 2014 - 2016, 2018 The Linux Foundation. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are permitted 5 * provided that the following conditions are met: 6 * * Redistributions of source code must retain the above copyright notice, this list of 7 * conditions and the following disclaimer. 8 * * Redistributions in binary form must reproduce the above copyright notice, this list of 9 * conditions and the following disclaimer in the documentation and/or other materials provided 10 * with the distribution. 11 * * Neither the name of The Linux Foundation nor the names of its contributors may be used to 12 * endorse or promote products derived from this software without specific prior written 13 * permission. 14 * 15 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 21 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #ifndef __LOCKER_H__ 26 #define __LOCKER_H__ 27 28 #include <stdint.h> 29 #include <errno.h> 30 #include <pthread.h> 31 #include <sys/time.h> 32 33 #define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker) 34 #define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker) 35 #define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker) 36 #define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker) 37 #define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker) 38 39 namespace sdm { 40 41 class Locker { 42 public: 43 class ScopeLock { 44 public: ScopeLock(Locker & locker)45 explicit ScopeLock(Locker& locker) : locker_(locker) { 46 locker_.Lock(); 47 } 48 ~ScopeLock()49 ~ScopeLock() { 50 locker_.Unlock(); 51 } 52 53 private: 54 Locker &locker_; 55 }; 56 57 class SequenceEntryScopeLock { 58 public: SequenceEntryScopeLock(Locker & locker)59 explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) { 60 locker_.Lock(); 61 locker_.sequence_wait_ = 1; 62 } 63 ~SequenceEntryScopeLock()64 ~SequenceEntryScopeLock() { 65 locker_.Unlock(); 66 } 67 68 private: 69 Locker &locker_; 70 }; 71 72 class SequenceExitScopeLock { 73 public: SequenceExitScopeLock(Locker & locker)74 explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) { 75 locker_.Lock(); 76 locker_.sequence_wait_ = 0; 77 } 78 ~SequenceExitScopeLock()79 ~SequenceExitScopeLock() { 80 locker_.Broadcast(); 81 locker_.Unlock(); 82 } 83 84 private: 85 Locker &locker_; 86 }; 87 88 class SequenceWaitScopeLock { 89 public: SequenceWaitScopeLock(Locker & locker)90 explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) { 91 locker_.Lock(); 92 93 while (locker_.sequence_wait_ == 1) { 94 locker_.Wait(); 95 error_ = (locker_.sequence_wait_ == -1); 96 } 97 } 98 ~SequenceWaitScopeLock()99 ~SequenceWaitScopeLock() { 100 locker_.Unlock(); 101 } 102 IsError()103 bool IsError() { 104 return error_; 105 } 106 107 private: 108 Locker &locker_; 109 bool error_; 110 }; 111 112 class SequenceCancelScopeLock { 113 public: SequenceCancelScopeLock(Locker & locker)114 explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) { 115 locker_.Lock(); 116 locker_.sequence_wait_ = -1; 117 } 118 ~SequenceCancelScopeLock()119 ~SequenceCancelScopeLock() { 120 locker_.Broadcast(); 121 locker_.Unlock(); 122 } 123 124 private: 125 Locker &locker_; 126 }; 127 Locker()128 Locker() : sequence_wait_(0) { 129 pthread_mutex_init(&mutex_, 0); 130 pthread_condattr_init(&cond_attr); 131 pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC); 132 pthread_cond_init(&condition_, &cond_attr); 133 } 134 ~Locker()135 ~Locker() { 136 pthread_mutex_destroy(&mutex_); 137 pthread_cond_destroy(&condition_); 138 pthread_condattr_destroy(&cond_attr); 139 } 140 Lock()141 void Lock() { pthread_mutex_lock(&mutex_); } Unlock()142 void Unlock() { pthread_mutex_unlock(&mutex_); } Signal()143 void Signal() { pthread_cond_signal(&condition_); } Broadcast()144 void Broadcast() { pthread_cond_broadcast(&condition_); } Wait()145 void Wait() { pthread_cond_wait(&condition_, &mutex_); } WaitFinite(uint32_t ms)146 int WaitFinite(uint32_t ms) { 147 struct timespec ts; 148 if (clock_gettime(CLOCK_MONOTONIC, &ts)) { 149 return EINVAL; 150 } 151 uint64_t ns = (uint64_t)ts.tv_nsec + (ms * 1000000L); 152 ts.tv_sec = ts.tv_sec + (time_t)(ns / 1000000000L); 153 ts.tv_nsec = ns % 1000000000L; 154 return pthread_cond_timedwait(&condition_, &mutex_, &ts); 155 } 156 157 private: 158 pthread_mutex_t mutex_; 159 pthread_cond_t condition_; 160 pthread_condattr_t cond_attr; 161 int sequence_wait_; // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel. 162 // Some routines will wait for sequence of function calls to finish 163 // so that capturing a transitionary snapshot of context is prevented. 164 // If flag is set to -1, these routines will exit without doing any 165 // further processing. 166 }; 167 168 } // namespace sdm 169 170 #endif // __LOCKER_H__ 171 172