1 /*
2 * Copyright (c) 2014 - 2016, 2018 - 2019, 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 #ifdef SDM_VIRTUAL_DRIVER
130     pthread_mutexattr_t attr;
131     pthread_mutexattr_init(&attr);
132     pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
133     pthread_mutex_init(&mutex_, &attr);
134 #else
135     pthread_mutex_init(&mutex_, 0);
136 #endif
137     pthread_condattr_init(&cond_attr_);
138     pthread_condattr_setclock(&cond_attr_, CLOCK_MONOTONIC);
139     pthread_cond_init(&condition_, &cond_attr_);
140   }
141 
~Locker()142   ~Locker() {
143     pthread_mutex_destroy(&mutex_);
144     pthread_cond_destroy(&condition_);
145     pthread_condattr_destroy(&cond_attr_);
146   }
147 
Lock()148   void Lock() { pthread_mutex_lock(&mutex_); }
TryLock()149   int32_t TryLock() { return pthread_mutex_trylock(&mutex_); }
Unlock()150   void Unlock() { pthread_mutex_unlock(&mutex_); }
Signal()151   void Signal() { pthread_cond_signal(&condition_); }
Broadcast()152   void Broadcast() { pthread_cond_broadcast(&condition_); }
Wait()153   void Wait() { pthread_cond_wait(&condition_, &mutex_); }
WaitFinite(uint32_t ms)154   int WaitFinite(uint32_t ms) {
155     struct timespec ts;
156     if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
157        return EINVAL;
158     }
159     uint64_t ns = (uint64_t)ts.tv_nsec + (ms * 1000000L);
160     ts.tv_sec   = ts.tv_sec + (time_t)(ns / 1000000000L);
161     ts.tv_nsec  = ns % 1000000000L;
162     return pthread_cond_timedwait(&condition_, &mutex_, &ts);
163   }
164 
165  private:
166   pthread_mutex_t mutex_;
167   pthread_cond_t condition_;
168   pthread_condattr_t cond_attr_;
169   int sequence_wait_;   // This flag is set to 1 on sequence entry, 0 on exit, and -1 on cancel.
170                         // Some routines will wait for sequence of function calls to finish
171                         // so that capturing a transitionary snapshot of context is prevented.
172                         // If flag is set to -1, these routines will exit without doing any
173                         // further processing.
174 };
175 
176 }  // namespace sdm
177 
178 #endif  // __LOCKER_H__
179 
180