blob: 87489552e0d679832b09f27a9447018e062d1758 [file] [log] [blame]
Greg Hartmana4ff2482017-10-03 16:35:00 -07001#pragma once
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -07002/*
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 */
Tomasz Wiszkowskia449e9c2017-05-25 14:30:56 -070017
18// Concurreny classess for Cloud Android projects.
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
34namespace avd {
35
36class Mutex {
37 friend class ConditionVariable;
38
39 public:
40 Mutex() {
41 pthread_mutex_init(&mutex_, NULL);
42 }
43
44 ~Mutex() {
45 pthread_mutex_destroy(&mutex_);
46 }
47
48 void Lock() {
49 pthread_mutex_lock(&mutex_);
50 }
51
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
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
71class ConditionVariable {
72 public:
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
81 ~ConditionVariable() {
82 pthread_cond_destroy(&cond_);
83 }
84
85 int NotifyOne() {
86 return pthread_cond_signal(&cond_);
87 }
88
89 int NotifyAll() {
90 return pthread_cond_broadcast(&cond_);
91 }
92
93 int Wait() {
94 return pthread_cond_wait(&cond_, mutex_->GetMutex());
95 }
96
97 int WaitUntil(const avd::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
112template <typename M> class LockGuard {
113 public:
114 explicit LockGuard(M& mutex) : mutex_(mutex) {
115 mutex_.Lock();
116 }
117
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.
130template<> class LockGuard<pthread_mutex_t> {
131 public:
132 explicit LockGuard(pthread_mutex_t& mutex) : mutex_(mutex), unlock_(false) {
133 unlock_ = (pthread_mutex_lock(&mutex_) == 0);
134 }
135
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
150class ScopedThread {
151 public:
152 ScopedThread(void* (*start)(void*), void* arg) {
153 pthread_create(&thread_, NULL, start, arg);
154 }
155
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 avd