1 /* 2 * Copyright (c) 2014 - 2016, 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 <pthread.h> 30 #include <sys/time.h> 31 32 #define SCOPE_LOCK(locker) Locker::ScopeLock lock(locker) 33 #define SEQUENCE_ENTRY_SCOPE_LOCK(locker) Locker::SequenceEntryScopeLock lock(locker) 34 #define SEQUENCE_EXIT_SCOPE_LOCK(locker) Locker::SequenceExitScopeLock lock(locker) 35 #define SEQUENCE_WAIT_SCOPE_LOCK(locker) Locker::SequenceWaitScopeLock lock(locker) 36 #define SEQUENCE_CANCEL_SCOPE_LOCK(locker) Locker::SequenceCancelScopeLock lock(locker) 37 38 namespace sdm { 39 40 class Locker { 41 public: 42 class ScopeLock { 43 public: ScopeLock(Locker & locker)44 explicit ScopeLock(Locker& locker) : locker_(locker) { 45 locker_.Lock(); 46 } 47 ~ScopeLock()48 ~ScopeLock() { 49 locker_.Unlock(); 50 } 51 52 private: 53 Locker &locker_; 54 }; 55 56 class SequenceEntryScopeLock { 57 public: SequenceEntryScopeLock(Locker & locker)58 explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) { 59 locker_.Lock(); 60 locker_.sequence_wait_ = 1; 61 } 62 ~SequenceEntryScopeLock()63 ~SequenceEntryScopeLock() { 64 locker_.Unlock(); 65 } 66 67 private: 68 Locker &locker_; 69 }; 70 71 class SequenceExitScopeLock { 72 public: SequenceExitScopeLock(Locker & locker)73 explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) { 74 locker_.Lock(); 75 locker_.sequence_wait_ = 0; 76 } 77 ~SequenceExitScopeLock()78 ~SequenceExitScopeLock() { 79 locker_.Broadcast(); 80 locker_.Unlock(); 81 } 82 83 private: 84 Locker &locker_; 85 }; 86 87 class SequenceWaitScopeLock { 88 public: SequenceWaitScopeLock(Locker & locker)89 explicit SequenceWaitScopeLock(Locker& locker) : locker_(locker), error_(false) { 90 locker_.Lock(); 91 92 while (locker_.sequence_wait_ == 1) { 93 locker_.Wait(); 94 error_ = (locker_.sequence_wait_ == -1); 95 } 96 } 97 ~SequenceWaitScopeLock()98 ~SequenceWaitScopeLock() { 99 locker_.Unlock(); 100 } 101 IsError()102 bool IsError() { 103 return error_; 104 } 105 106 private: 107 Locker &locker_; 108 bool error_; 109 }; 110 111 class SequenceCancelScopeLock { 112 public: SequenceCancelScopeLock(Locker & locker)113 explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) { 114 locker_.Lock(); 115 locker_.sequence_wait_ = -1; 116 } 117 ~SequenceCancelScopeLock()118 ~SequenceCancelScopeLock() { 119 locker_.Broadcast(); 120 locker_.Unlock(); 121 } 122 123 private: 124 Locker &locker_; 125 }; 126 Locker()127 Locker() : sequence_wait_(0) { 128 pthread_mutex_init(&mutex_, 0); 129 pthread_cond_init(&condition_, 0); 130 } 131 ~Locker()132 ~Locker() { 133 pthread_mutex_destroy(&mutex_); 134 pthread_cond_destroy(&condition_); 135 } 136 Lock()137 void Lock() { pthread_mutex_lock(&mutex_); } Unlock()138 void Unlock() { pthread_mutex_unlock(&mutex_); } Signal()139 void Signal() { pthread_cond_signal(&condition_); } Broadcast()140 void Broadcast() { pthread_cond_broadcast(&condition_); } Wait()141 void Wait() { pthread_cond_wait(&condition_, &mutex_); } WaitFinite(int ms)142 int WaitFinite(int ms) { 143 struct timespec ts; 144 struct timeval tv; 145 gettimeofday(&tv, NULL); 146 ts.tv_sec = tv.tv_sec + ms/1000; 147 ts.tv_nsec = tv.tv_usec*1000 + (ms%1000)*1000000; 148 ts.tv_sec += ts.tv_nsec/1000000000L; 149 ts.tv_nsec += ts.tv_nsec%1000000000L; 150 return pthread_cond_timedwait(&condition_, &mutex_, &ts); 151 } 152 153 private: 154 pthread_mutex_t mutex_; 155 pthread_cond_t condition_; 156 int sequence_wait_; // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel. 157 // Some routines will wait for sequence of function calls to finish 158 // so that capturing a transitionary snapshot of context is prevented. 159 // If flag is set to -1, these routines will exit without doing any 160 // further processing. 161 }; 162 163 } // namespace sdm 164 165 #endif // __LOCKER_H__ 166 167