| #pragma once |
| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Concurreny classess for Cloud Android projects. |
| // |
| // These more or less mimic the interface of the C++ classes: |
| // Mutex is similar to std::mutex |
| // ConditionVariable is similar to std::condition_variable |
| // LockGuard is similar to std::lock_guard |
| // |
| // There are some extensions: |
| // ScopedThread creates a Thread and joins it when the class is destroyed |
| // This comes in handy during unit tests. It should be used cautiously, if |
| // at all, in production code because thread creation isn't free. |
| |
| #include <stdint.h> |
| #include <pthread.h> |
| #include "common/libs/time/monotonic_time.h" |
| |
| namespace avd { |
| |
| class Mutex { |
| friend class ConditionVariable; |
| |
| public: |
| Mutex() { |
| pthread_mutex_init(&mutex_, NULL); |
| } |
| |
| ~Mutex() { |
| pthread_mutex_destroy(&mutex_); |
| } |
| |
| void Lock() { |
| pthread_mutex_lock(&mutex_); |
| } |
| |
| void Unlock() { |
| pthread_mutex_unlock(&mutex_); |
| } |
| |
| // TODO(ghartman): Add TryLock if and only if there's a good use case. |
| |
| protected: |
| |
| pthread_mutex_t* GetMutex() { |
| return &mutex_; |
| } |
| |
| pthread_mutex_t mutex_; |
| |
| private: |
| Mutex(const Mutex&); |
| Mutex& operator= (const Mutex&); |
| }; |
| |
| class ConditionVariable { |
| public: |
| explicit ConditionVariable(Mutex* mutex) : mutex_(mutex) { |
| pthread_condattr_t attr; |
| pthread_condattr_init(&attr); |
| pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); |
| pthread_cond_init(&cond_, &attr); |
| pthread_condattr_destroy(&attr); |
| } |
| |
| ~ConditionVariable() { |
| pthread_cond_destroy(&cond_); |
| } |
| |
| int NotifyOne() { |
| return pthread_cond_signal(&cond_); |
| } |
| |
| int NotifyAll() { |
| return pthread_cond_broadcast(&cond_); |
| } |
| |
| int Wait() { |
| return pthread_cond_wait(&cond_, mutex_->GetMutex()); |
| } |
| |
| int WaitUntil(const avd::time::MonotonicTimePoint& tp) { |
| struct timespec ts; |
| tp.ToTimespec(&ts); |
| return pthread_cond_timedwait(&cond_, mutex_->GetMutex(), &ts); |
| } |
| |
| protected: |
| Mutex* mutex_; |
| pthread_cond_t cond_; |
| |
| private: |
| ConditionVariable(const ConditionVariable&); |
| ConditionVariable& operator= (const ConditionVariable&); |
| }; |
| |
| template <typename M> class LockGuard { |
| public: |
| explicit LockGuard(M& mutex) : mutex_(mutex) { |
| mutex_.Lock(); |
| } |
| |
| ~LockGuard() { |
| mutex_.Unlock(); |
| } |
| |
| private: |
| M& mutex_; |
| |
| LockGuard(const LockGuard&); |
| LockGuard& operator= (const LockGuard&); |
| }; |
| |
| // Use only in cases where the mutex can't be upgraded to a Mutex. |
| template<> class LockGuard<pthread_mutex_t> { |
| public: |
| explicit LockGuard(pthread_mutex_t& mutex) : mutex_(mutex), unlock_(false) { |
| unlock_ = (pthread_mutex_lock(&mutex_) == 0); |
| } |
| |
| ~LockGuard() { |
| if (unlock_) { |
| pthread_mutex_unlock(&mutex_); |
| } |
| } |
| |
| private: |
| pthread_mutex_t& mutex_; |
| bool unlock_; |
| |
| LockGuard(const LockGuard&); |
| LockGuard& operator= (const LockGuard&); |
| }; |
| |
| class ScopedThread { |
| public: |
| ScopedThread(void* (*start)(void*), void* arg) { |
| pthread_create(&thread_, NULL, start, arg); |
| } |
| |
| ~ScopedThread() { |
| void* value; |
| pthread_join(thread_, &value); |
| } |
| |
| protected: |
| pthread_t thread_; |
| |
| private: |
| ScopedThread(const ScopedThread&); |
| ScopedThread& operator= (const ScopedThread&); |
| }; |
| |
| } // namespace avd |