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