• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // Concurreny classess for cuttlefish.
19 //
20 // These more or less mimic the interface of the C++ classes:
21 //   Mutex is similar to std::mutex
22 //   ConditionVariable is similar to std::condition_variable
23 //   LockGuard is similar to std::lock_guard
24 //
25 // There are some extensions:
26 //   ScopedThread creates a Thread and joins it when the class is destroyed
27 //   This comes in handy during unit tests. It should be used cautiously, if
28 //   at all, in production code because thread creation isn't free.
29 
30 #include <stdint.h>
31 #include <pthread.h>
32 #include "common/libs/time/monotonic_time.h"
33 
34 namespace cvd {
35 
36 class Mutex {
37  friend class ConditionVariable;
38 
39  public:
Mutex()40   Mutex() {
41     pthread_mutex_init(&mutex_, NULL);
42   }
43 
~Mutex()44   ~Mutex() {
45     pthread_mutex_destroy(&mutex_);
46   }
47 
Lock()48   void Lock() {
49     pthread_mutex_lock(&mutex_);
50   }
51 
Unlock()52   void Unlock() {
53     pthread_mutex_unlock(&mutex_);
54   }
55 
56   // TODO(ghartman): Add TryLock if and only if there's a good use case.
57 
58  protected:
59 
GetMutex()60   pthread_mutex_t* GetMutex() {
61     return &mutex_;
62   }
63 
64   pthread_mutex_t mutex_;
65 
66  private:
67   Mutex(const Mutex&);
68   Mutex& operator= (const Mutex&);
69 };
70 
71 class ConditionVariable {
72  public:
ConditionVariable(Mutex * mutex)73   explicit ConditionVariable(Mutex* mutex) : mutex_(mutex) {
74     pthread_condattr_t attr;
75     pthread_condattr_init(&attr);
76     pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
77     pthread_cond_init(&cond_, &attr);
78     pthread_condattr_destroy(&attr);
79   }
80 
~ConditionVariable()81   ~ConditionVariable() {
82     pthread_cond_destroy(&cond_);
83   }
84 
NotifyOne()85   int NotifyOne() {
86     return pthread_cond_signal(&cond_);
87   }
88 
NotifyAll()89   int NotifyAll() {
90     return pthread_cond_broadcast(&cond_);
91   }
92 
Wait()93   int Wait() {
94     return pthread_cond_wait(&cond_, mutex_->GetMutex());
95   }
96 
WaitUntil(const cvd::time::MonotonicTimePoint & tp)97   int WaitUntil(const cvd::time::MonotonicTimePoint& tp) {
98     struct timespec ts;
99     tp.ToTimespec(&ts);
100     return pthread_cond_timedwait(&cond_, mutex_->GetMutex(), &ts);
101   }
102 
103  protected:
104   Mutex* mutex_;
105   pthread_cond_t cond_;
106 
107  private:
108   ConditionVariable(const ConditionVariable&);
109   ConditionVariable& operator= (const ConditionVariable&);
110 };
111 
112 template <typename M> class LockGuard {
113  public:
LockGuard(M & mutex)114   explicit LockGuard(M& mutex) : mutex_(mutex) {
115     mutex_.Lock();
116   }
117 
~LockGuard()118   ~LockGuard() {
119     mutex_.Unlock();
120   }
121 
122  private:
123   M& mutex_;
124 
125   LockGuard(const LockGuard&);
126   LockGuard& operator= (const LockGuard&);
127 };
128 
129 // Use only in cases where the mutex can't be upgraded to a Mutex.
130 template<> class LockGuard<pthread_mutex_t> {
131  public:
LockGuard(pthread_mutex_t & mutex)132   explicit LockGuard(pthread_mutex_t& mutex) : mutex_(mutex), unlock_(false) {
133     unlock_ = (pthread_mutex_lock(&mutex_) == 0);
134   }
135 
~LockGuard()136   ~LockGuard() {
137     if (unlock_) {
138       pthread_mutex_unlock(&mutex_);
139     }
140   }
141 
142  private:
143   pthread_mutex_t& mutex_;
144   bool unlock_;
145 
146   LockGuard(const LockGuard&);
147   LockGuard& operator= (const LockGuard&);
148 };
149 
150 class ScopedThread {
151  public:
ScopedThread(void * (* start)(void *),void * arg)152   ScopedThread(void* (*start)(void*), void* arg) {
153     pthread_create(&thread_, NULL, start, arg);
154   }
155 
~ScopedThread()156   ~ScopedThread() {
157     void* value;
158     pthread_join(thread_, &value);
159   }
160 
161  protected:
162   pthread_t thread_;
163 
164  private:
165   ScopedThread(const ScopedThread&);
166   ScopedThread& operator= (const ScopedThread&);
167 };
168 
169 }  // namespace cvd
170