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