1 /*
2 * Copyright (c) 2014 - 2015, 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       if (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