1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <android-base/thread_annotations.h> 20 #include <any> 21 #include <functional> 22 #include <mutex> 23 #include <vector> 24 25 namespace android::audio_utils { 26 27 /** 28 * The DeferredExecutor class accumulates objects to dispose 29 * and functors to execute. 30 * 31 * The class is used in a worker thread loop to allow objects 32 * and functors to be accumulated under a mutex, 33 * where such object dtors or functors might cause 34 * deadlocks or order inversion issues when executed. 35 * The process() method is then called outside of the mutex 36 * to dispose any objects and execute any functors accumulated. 37 */ 38 39 class DeferredExecutor { 40 public: 41 42 /** 43 * \param processInDtor if true calls process in the dtor. 44 * 45 * processInDtor defaults to false to prevent use after free. 46 */ 47 explicit DeferredExecutor(bool processInDtor = false) mProcessInDtor(processInDtor)48 : mProcessInDtor(processInDtor) 49 {} 50 51 /** 52 * If processInDtor is set true in the ctor, then 53 * deferred functors are executed. Then any 54 * deferred functors and garbage are deallocated. 55 */ ~DeferredExecutor()56 ~DeferredExecutor() { 57 if (mProcessInDtor) process(true /* recursive */); 58 } 59 60 /** 61 * Delays destruction of an object to the 62 * invocation of process() (generally outside of lock). 63 * 64 * Example Usage: 65 * 66 * std::vector<std::vector<sp<IFoo>>> interfaces; 67 * ... 68 * executor.dispose(std::move(interfaces)); 69 */ 70 template<typename T> dispose(T && object)71 void dispose(T&& object) { 72 std::lock_guard lg(mMutex); 73 mGarbage.emplace_back(std::forward<T>(object)); 74 } 75 76 /** 77 * Defers execution of a functor to the invocation 78 * of process() (generally outside of lock). 79 * 80 * Example Usage: 81 * 82 * executor.defer([]{ foo(); }); 83 */ 84 template<typename F> defer(F && functor)85 void defer(F&& functor) { 86 std::lock_guard lg(mMutex); 87 mDeferred.emplace_back(std::forward<F>(functor)); 88 } 89 90 /** 91 * Runs deferred functors (in order of adding) 92 * and then dellocates the functors and empties the garbage 93 * (in reverse order of adding). 94 * 95 * \param recursive if set to true, will loop the process 96 * to ensure no garbage or deferred objects remain. 97 */ 98 void process(bool recursive = false) { 99 do { 100 // Note the declaration order of garbage and deferred. 101 std::vector <std::any> garbage; 102 std::vector <std::function<void()>> deferred; 103 { 104 std::lock_guard lg(mMutex); 105 if (mGarbage.empty() && mDeferred.empty()) return; 106 std::swap(garbage, mGarbage); 107 std::swap(deferred, mDeferred); 108 } 109 // execution in order of adding. 110 // destruction in reverse order of adding. 111 for (const auto& f: deferred) { 112 f(); 113 } 114 } while (recursive); 115 } 116 117 /** 118 * Skips running any deferred functors and dellocates the functors 119 * and empties the garbage (in reverse order of adding). 120 */ clear()121 void clear() { 122 // Note the declaration order of garbage and deferred. 123 std::vector<std::any> garbage; 124 std::vector<std::function<void()>> deferred; 125 { 126 std::lock_guard lg(mMutex); 127 std::swap(garbage, mGarbage); 128 std::swap(deferred, mDeferred); 129 } 130 } 131 132 /** 133 * Returns true if there is no garbage and no deferred methods. 134 */ empty()135 bool empty() const { 136 std::lock_guard lg(mMutex); 137 return mGarbage.empty() && mDeferred.empty(); 138 } 139 140 private: 141 const bool mProcessInDtor; 142 mutable std::mutex mMutex; 143 std::vector<std::any> mGarbage GUARDED_BY(mMutex); 144 std::vector<std::function<void()>> mDeferred GUARDED_BY(mMutex); 145 }; 146 147 } // namespace android::audio_utils 148