1235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar/* 2235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Copyright 2016, The Android Open Source Project 3235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 4235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Licensed under the Apache License, Version 2.0 (the "License"); 5235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * you may not use this file except in compliance with the License. 6235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * You may obtain a copy of the License at 7235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 8235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * http://www.apache.org/licenses/LICENSE-2.0 9235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 10235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Unless required by applicable law or agreed to in writing, software 11235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * distributed under the License is distributed on an "AS IS" BASIS, 12235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * See the License for the specific language governing permissions and 14235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * limitations under the License. 15235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar */ 16235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 17235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar#ifndef STAGEFRIGHT_FOUNDATION_MUTEXED_H_ 18235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar#define STAGEFRIGHT_FOUNDATION_MUTEXED_H_ 19235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 20235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar#include <utils/Mutex.h> 21235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar#include <utils/Condition.h> 22235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 23235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarnamespace android { 24235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 25235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar/* 26235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Wrapper class to programmatically protect a structure using a mutex. 27235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 28235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Mutexed<> objects contain a built-in mutex. Protection is enforced because the structure can 29235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * only be accessed by locking the mutex first. 30235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 31235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Usage: 32235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 33235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * struct DataToProtect { 34235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * State(int var1) : mVar1(var1), mVar2(0) { } 35235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * int mVar1; 36235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * int mVar2; 37235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Condition mCondition1; 38235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * }; 39235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 40235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Mutexed<DataToProtect> mProtectedData; 41235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 42235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // members are inaccessible via mProtectedData directly 43235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 44235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * void someFunction() { 45235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Mutexed<DataToProtect>::Locked data(mProtectedData); // access the protected data 46235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 47235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // the mutex is locked here, so accessing the data is safe 48235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 49235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * if (data->mVar1 < 5) { 50235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * ++data->mVar2; 51235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * } 52235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 53235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // if you need to temporarily unlock the mutex, you can use unlock/relock mutex locally 54235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // using the accessor object. 55235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 56235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * data.unlock(); 57235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 58235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // data is inaccessible here 59235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 60235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * doSomeLongOperation(); 61235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 62235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * data.lock(); 63235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 64235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // data is now accessible again. Note: it may have changed since unlock(). 65235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 66235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * // you can use the integral mutex to wait for a condition 67235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 68235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * data.waitForCondition(data->mCondition1); 69235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 70235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * helper(&data); 71235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * } 72235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 73235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * void trigger() { 74235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Mutexed<DataToProtect>::Locked data(mProtectedData); 75235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * data->mCondition1.signal(); 76235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * } 77235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 78235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * void helper(const Mutexed<DataToProtect>::Locked &data) { 79235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * data->mVar1 = 3; 80235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * } 81235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 82235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar */ 83235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 84235303640aa98663bda58c923380e0fd5b0229aeLajos Molnartemplate<typename T> 85235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarclass Mutexed { 86235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarpublic: 87235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar /* 88235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Accessor-guard of the mutex-protected structure. This can be dereferenced to 89235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * access the structure (using -> or * operators). 90235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 91235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Upon creation, the mutex is locked. You can use lock()/unlock() methods to 92235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * temporarily lock/unlock the mutex. Using any references to the underlying 93235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * structure or its members defeats the protection of this class, so don't do 94235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * it. 95235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 96235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Note: The accessor-guard itself is not thread-safe. E.g. you should not call 97235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * unlock() or lock() from different threads; they must be called from the thread 98235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * that locked the original wrapper. 99235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * 100235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * Also note: Recursive locking/unlocking is not supported by the accessor. This 101235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar * is as intended, as it allows lenient locking/unlocking via multiple code paths. 102235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar */ 103235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar class Locked { 104235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar public: 105235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline Locked(Mutexed<T> &mParent); 1069f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar inline Locked(Locked &&from) : 1079f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar mLock(from.mLock), 1089f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar mTreasure(from.mTreasure), 1099f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar mLocked(from.mLocked) {} 110235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline ~Locked(); 111235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 112235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // dereference the protected structure. This returns nullptr if the 113235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // mutex is not locked by this accessor-guard. 114235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline T* operator->() const { return mLocked ? &mTreasure : nullptr; } 115235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline T& operator*() const { return mLocked ? mTreasure : *(T*)nullptr; } 116235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 117ee0eba046f666303741a5a5f70afad17030cc8b1Lajos Molnar // same as * 118ee0eba046f666303741a5a5f70afad17030cc8b1Lajos Molnar inline T& get() const { return mLocked ? mTreasure : *(T*)nullptr; } 119ee0eba046f666303741a5a5f70afad17030cc8b1Lajos Molnar // sets structure. this will abort if mLocked is false. 120ee0eba046f666303741a5a5f70afad17030cc8b1Lajos Molnar inline void set(T& o) const { get() = o; } 121ee0eba046f666303741a5a5f70afad17030cc8b1Lajos Molnar 122235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // Wait on the condition variable using lock. Must be locked. 123235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline status_t waitForCondition(Condition &cond) { return cond.wait(mLock); } 124235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 125235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // same with relative timeout 126235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline status_t waitForConditionRelative(Condition &cond, nsecs_t reltime) { 127235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar return cond.waitRelative(mLock, reltime); 128235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar } 129235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 130235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // unlocks the integral mutex. No-op if the mutex was already unlocked. 131235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline void unlock(); 132235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 133235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // locks the integral mutex. No-op if the mutex was already locked. 134235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar inline void lock(); 135235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 136235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar private: 137235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar Mutex &mLock; 138235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar T &mTreasure; 139235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar bool mLocked; 140235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 141235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // disable copy constructors 142235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar Locked(const Locked&) = delete; 143235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar void operator=(const Locked&) = delete; 144235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar }; 145235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 146235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // Wrap all constructors of the underlying structure 147235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar template<typename ...Args> 148235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar Mutexed(Args... args) : mTreasure(args...) { } 149235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 150235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar ~Mutexed() { } 151235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 152235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // Lock the mutex, and create an accessor-guard (a Locked object) to access the underlying 153235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // structure. This returns an object that dereferences to the wrapped structure when the mutex 154235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // is locked by it, or otherwise to "null". 1559f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar // This is just a shorthand for Locked() constructor to avoid specifying the template type. 1569f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar inline Locked lock() { 1579f8bb269e312c882f00db5ca20c650dea7260718Lajos Molnar return Locked(*this); 158235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar } 159235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 160235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarprivate: 161235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar friend class Locked; 162235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar Mutex mLock; 163235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar T mTreasure; 164235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 165235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar // disable copy constructors 166235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar Mutexed(const Mutexed<T>&) = delete; 167235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar void operator=(const Mutexed<T>&) = delete; 168235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar}; 169235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 170235303640aa98663bda58c923380e0fd5b0229aeLajos Molnartemplate<typename T> 171235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarinline Mutexed<T>::Locked::Locked(Mutexed<T> &mParent) 172235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar : mLock(mParent.mLock), 173235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mTreasure(mParent.mTreasure), 174235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLocked(true) { 175235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLock.lock(); 176235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar} 177235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 178235303640aa98663bda58c923380e0fd5b0229aeLajos Molnartemplate<typename T> 179235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarinline Mutexed<T>::Locked::~Locked() { 180235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar if (mLocked) { 181235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLock.unlock(); 182235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar } 183235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar} 184235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 185235303640aa98663bda58c923380e0fd5b0229aeLajos Molnartemplate<typename T> 186235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarinline void Mutexed<T>::Locked::unlock() { 187235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar if (mLocked) { 188235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLocked = false; 189235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLock.unlock(); 190235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar } 191235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar} 192235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 193235303640aa98663bda58c923380e0fd5b0229aeLajos Molnartemplate<typename T> 194235303640aa98663bda58c923380e0fd5b0229aeLajos Molnarinline void Mutexed<T>::Locked::lock() { 195235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar if (!mLocked) { 196235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLock.lock(); 197235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar mLocked = true; 198235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar } 199235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar} 200235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 201235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar} // namespace android 202235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar 203235303640aa98663bda58c923380e0fd5b0229aeLajos Molnar#endif 204