Loading include/media/stagefright/foundation/Mutexed.h 0 → 100644 +195 −0 Original line number Diff line number Diff line /* * Copyright 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. */ #ifndef STAGEFRIGHT_FOUNDATION_MUTEXED_H_ #define STAGEFRIGHT_FOUNDATION_MUTEXED_H_ #include <utils/Mutex.h> #include <utils/Condition.h> namespace android { /* * Wrapper class to programmatically protect a structure using a mutex. * * Mutexed<> objects contain a built-in mutex. Protection is enforced because the structure can * only be accessed by locking the mutex first. * * Usage: * * struct DataToProtect { * State(int var1) : mVar1(var1), mVar2(0) { } * int mVar1; * int mVar2; * Condition mCondition1; * }; * * Mutexed<DataToProtect> mProtectedData; * * // members are inaccessible via mProtectedData directly * * void someFunction() { * Mutexed<DataToProtect>::Locked data(mProtectedData); // access the protected data * * // the mutex is locked here, so accessing the data is safe * * if (data->mVar1 < 5) { * ++data->mVar2; * } * * // if you need to temporarily unlock the mutex, you can use unlock/relock mutex locally * // using the accessor object. * * data.unlock(); * * // data is inaccessible here * * doSomeLongOperation(); * * data.lock(); * * // data is now accessible again. Note: it may have changed since unlock(). * * // you can use the integral mutex to wait for a condition * * data.waitForCondition(data->mCondition1); * * helper(&data); * } * * void trigger() { * Mutexed<DataToProtect>::Locked data(mProtectedData); * data->mCondition1.signal(); * } * * void helper(const Mutexed<DataToProtect>::Locked &data) { * data->mVar1 = 3; * } * */ template<typename T> class Mutexed { public: /* * Accessor-guard of the mutex-protected structure. This can be dereferenced to * access the structure (using -> or * operators). * * Upon creation, the mutex is locked. You can use lock()/unlock() methods to * temporarily lock/unlock the mutex. Using any references to the underlying * structure or its members defeats the protection of this class, so don't do * it. * * Note: The accessor-guard itself is not thread-safe. E.g. you should not call * unlock() or lock() from different threads; they must be called from the thread * that locked the original wrapper. * * Also note: Recursive locking/unlocking is not supported by the accessor. This * is as intended, as it allows lenient locking/unlocking via multiple code paths. */ class Locked { public: inline Locked(Mutexed<T> &mParent); inline ~Locked(); // dereference the protected structure. This returns nullptr if the // mutex is not locked by this accessor-guard. inline T* operator->() const { return mLocked ? &mTreasure : nullptr; } inline T& operator*() const { return mLocked ? mTreasure : *(T*)nullptr; } // Wait on the condition variable using lock. Must be locked. inline status_t waitForCondition(Condition &cond) { return cond.wait(mLock); } // same with relative timeout inline status_t waitForConditionRelative(Condition &cond, nsecs_t reltime) { return cond.waitRelative(mLock, reltime); } // unlocks the integral mutex. No-op if the mutex was already unlocked. inline void unlock(); // locks the integral mutex. No-op if the mutex was already locked. inline void lock(); private: Mutex &mLock; T &mTreasure; bool mLocked; // disable copy constructors Locked(const Locked&) = delete; void operator=(const Locked&) = delete; }; // Wrap all constructors of the underlying structure template<typename ...Args> Mutexed(Args... args) : mTreasure(args...) { } ~Mutexed() { } // Lock the mutex, and create an accessor-guard (a Locked object) to access the underlying // structure. This returns an object that dereferences to the wrapped structure when the mutex // is locked by it, or otherwise to "null". inline Locked&& lock() { // use rvalue as Locked has no copy constructor return std::move(Locked(*this)); } private: friend class Locked; Mutex mLock; T mTreasure; // disable copy constructors Mutexed(const Mutexed<T>&) = delete; void operator=(const Mutexed<T>&) = delete; }; template<typename T> inline Mutexed<T>::Locked::Locked(Mutexed<T> &mParent) : mLock(mParent.mLock), mTreasure(mParent.mTreasure), mLocked(true) { mLock.lock(); } template<typename T> inline Mutexed<T>::Locked::~Locked() { if (mLocked) { mLock.unlock(); } } template<typename T> inline void Mutexed<T>::Locked::unlock() { if (mLocked) { mLocked = false; mLock.unlock(); } } template<typename T> inline void Mutexed<T>::Locked::lock() { if (!mLocked) { mLock.lock(); mLocked = true; } } } // namespace android #endif Loading
include/media/stagefright/foundation/Mutexed.h 0 → 100644 +195 −0 Original line number Diff line number Diff line /* * Copyright 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. */ #ifndef STAGEFRIGHT_FOUNDATION_MUTEXED_H_ #define STAGEFRIGHT_FOUNDATION_MUTEXED_H_ #include <utils/Mutex.h> #include <utils/Condition.h> namespace android { /* * Wrapper class to programmatically protect a structure using a mutex. * * Mutexed<> objects contain a built-in mutex. Protection is enforced because the structure can * only be accessed by locking the mutex first. * * Usage: * * struct DataToProtect { * State(int var1) : mVar1(var1), mVar2(0) { } * int mVar1; * int mVar2; * Condition mCondition1; * }; * * Mutexed<DataToProtect> mProtectedData; * * // members are inaccessible via mProtectedData directly * * void someFunction() { * Mutexed<DataToProtect>::Locked data(mProtectedData); // access the protected data * * // the mutex is locked here, so accessing the data is safe * * if (data->mVar1 < 5) { * ++data->mVar2; * } * * // if you need to temporarily unlock the mutex, you can use unlock/relock mutex locally * // using the accessor object. * * data.unlock(); * * // data is inaccessible here * * doSomeLongOperation(); * * data.lock(); * * // data is now accessible again. Note: it may have changed since unlock(). * * // you can use the integral mutex to wait for a condition * * data.waitForCondition(data->mCondition1); * * helper(&data); * } * * void trigger() { * Mutexed<DataToProtect>::Locked data(mProtectedData); * data->mCondition1.signal(); * } * * void helper(const Mutexed<DataToProtect>::Locked &data) { * data->mVar1 = 3; * } * */ template<typename T> class Mutexed { public: /* * Accessor-guard of the mutex-protected structure. This can be dereferenced to * access the structure (using -> or * operators). * * Upon creation, the mutex is locked. You can use lock()/unlock() methods to * temporarily lock/unlock the mutex. Using any references to the underlying * structure or its members defeats the protection of this class, so don't do * it. * * Note: The accessor-guard itself is not thread-safe. E.g. you should not call * unlock() or lock() from different threads; they must be called from the thread * that locked the original wrapper. * * Also note: Recursive locking/unlocking is not supported by the accessor. This * is as intended, as it allows lenient locking/unlocking via multiple code paths. */ class Locked { public: inline Locked(Mutexed<T> &mParent); inline ~Locked(); // dereference the protected structure. This returns nullptr if the // mutex is not locked by this accessor-guard. inline T* operator->() const { return mLocked ? &mTreasure : nullptr; } inline T& operator*() const { return mLocked ? mTreasure : *(T*)nullptr; } // Wait on the condition variable using lock. Must be locked. inline status_t waitForCondition(Condition &cond) { return cond.wait(mLock); } // same with relative timeout inline status_t waitForConditionRelative(Condition &cond, nsecs_t reltime) { return cond.waitRelative(mLock, reltime); } // unlocks the integral mutex. No-op if the mutex was already unlocked. inline void unlock(); // locks the integral mutex. No-op if the mutex was already locked. inline void lock(); private: Mutex &mLock; T &mTreasure; bool mLocked; // disable copy constructors Locked(const Locked&) = delete; void operator=(const Locked&) = delete; }; // Wrap all constructors of the underlying structure template<typename ...Args> Mutexed(Args... args) : mTreasure(args...) { } ~Mutexed() { } // Lock the mutex, and create an accessor-guard (a Locked object) to access the underlying // structure. This returns an object that dereferences to the wrapped structure when the mutex // is locked by it, or otherwise to "null". inline Locked&& lock() { // use rvalue as Locked has no copy constructor return std::move(Locked(*this)); } private: friend class Locked; Mutex mLock; T mTreasure; // disable copy constructors Mutexed(const Mutexed<T>&) = delete; void operator=(const Mutexed<T>&) = delete; }; template<typename T> inline Mutexed<T>::Locked::Locked(Mutexed<T> &mParent) : mLock(mParent.mLock), mTreasure(mParent.mTreasure), mLocked(true) { mLock.lock(); } template<typename T> inline Mutexed<T>::Locked::~Locked() { if (mLocked) { mLock.unlock(); } } template<typename T> inline void Mutexed<T>::Locked::unlock() { if (mLocked) { mLocked = false; mLock.unlock(); } } template<typename T> inline void Mutexed<T>::Locked::lock() { if (!mLocked) { mLock.lock(); mLocked = true; } } } // namespace android #endif