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