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 38namespace sdm { 39 40class Locker { 41 public: 42 class ScopeLock { 43 public: 44 explicit ScopeLock(Locker& locker) : locker_(locker) { 45 locker_.Lock(); 46 } 47 48 ~ScopeLock() { 49 locker_.Unlock(); 50 } 51 52 private: 53 Locker &locker_; 54 }; 55 56 class SequenceEntryScopeLock { 57 public: 58 explicit SequenceEntryScopeLock(Locker& locker) : locker_(locker) { 59 locker_.Lock(); 60 locker_.sequence_wait_ = 1; 61 } 62 63 ~SequenceEntryScopeLock() { 64 locker_.Unlock(); 65 } 66 67 private: 68 Locker &locker_; 69 }; 70 71 class SequenceExitScopeLock { 72 public: 73 explicit SequenceExitScopeLock(Locker& locker) : locker_(locker) { 74 locker_.Lock(); 75 locker_.sequence_wait_ = 0; 76 } 77 78 ~SequenceExitScopeLock() { 79 locker_.Broadcast(); 80 locker_.Unlock(); 81 } 82 83 private: 84 Locker &locker_; 85 }; 86 87 class SequenceWaitScopeLock { 88 public: 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 98 ~SequenceWaitScopeLock() { 99 locker_.Unlock(); 100 } 101 102 bool IsError() { 103 return error_; 104 } 105 106 private: 107 Locker &locker_; 108 bool error_; 109 }; 110 111 class SequenceCancelScopeLock { 112 public: 113 explicit SequenceCancelScopeLock(Locker& locker) : locker_(locker) { 114 locker_.Lock(); 115 locker_.sequence_wait_ = -1; 116 } 117 118 ~SequenceCancelScopeLock() { 119 locker_.Broadcast(); 120 locker_.Unlock(); 121 } 122 123 private: 124 Locker &locker_; 125 }; 126 127 Locker() : sequence_wait_(0) { 128 pthread_mutex_init(&mutex_, 0); 129 pthread_cond_init(&condition_, 0); 130 } 131 132 ~Locker() { 133 pthread_mutex_destroy(&mutex_); 134 pthread_cond_destroy(&condition_); 135 } 136 137 void Lock() { pthread_mutex_lock(&mutex_); } 138 void Unlock() { pthread_mutex_unlock(&mutex_); } 139 void Signal() { pthread_cond_signal(&condition_); } 140 void Broadcast() { pthread_cond_broadcast(&condition_); } 141 void Wait() { pthread_cond_wait(&condition_, &mutex_); } 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 %= 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