1 // Copyright (C) 2015 The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #include "aemu/base/Compiler.h" 18 #include "aemu/base/async/Looper.h" 19 #include "aemu/base/threads/internal/ParallelTaskBase.h" 20 #include "aemu/base/threads/Types.h" 21 22 #include <functional> 23 #include <memory> 24 #include <utility> 25 26 namespace android { 27 namespace base { 28 29 // A ParallelTask<Result> is an object that allows you to run a task in a 30 // separate thread, and take follow up action back on the current thread's event 31 // loop. Additionally, the |taskDoneFunction| function is called with a result 32 // of type |Result| returned from the launched thread. 33 // 34 // An example of a thread returning the typical int exitStatus: 35 // 36 // class LifeUniverseAndEverythingInParallel { 37 // public: 38 // LifeUniverseAndEverythingInParallel(Looper* looper) : 39 // mEarth(looper, 40 // std::bind(&LifeUniverseAndEverythingInParallel::compute, 41 // this, std::placeholders::_1), 42 // std::bind( 43 // &LifeUniverseAndEverythingInParallel::printAnswer, 44 // this, std::placeholders::_1) {} 45 // 46 // // This is the entry point of computation. 47 // bool startOfTime() { 48 // return mEarth.start(); 49 // } 50 // // Called by the parallel task. 51 // void compute(int* outResult) { 52 // *outResult = 42; 53 // } 54 // 55 // void printAnswer(const int& outResult) { 56 // std::cout << "The mice say it's " << outResult << std::endl; 57 // } 58 // 59 // private: 60 // ParallelTask<int> mEarth; 61 // }; 62 // 63 // int main() { 64 // LifeUniverseAndEverythingInParallel whatsTheAnswer; 65 // whatsTheAnswer.startOfTime(); 66 // android::base::ThreadLooper::get()->runWithDeadline( 67 // // 10 million years); 68 // // ... Do other stuff while the mice run inside contraptions ... 69 // } 70 // 71 // If you just want to run a free function to compute something in parallel 72 // and then take follow up action using another free function, a templatized 73 // helper function is provided as well: 74 // 75 // void computeStandalone(int* outResult) { 76 // *outResult = 42; 77 // } 78 // 79 // void printAnswer(const int& outResult) { 80 // std::cout << "The mice say it's " << outResult << std::endl; 81 // } 82 // 83 // runParallelTask<int>( 84 // android::base::ThreadLooper::get(), 85 // &computeStandalone, 86 // &printAnswer); 87 // 88 template <class ResultType> 89 class ParallelTask final : public internal::ParallelTaskBase { 90 public: 91 using TaskFunction = std::function<void(ResultType*)>; 92 using TaskDoneFunction = std::function<void(const ResultType&)>; 93 94 // Args: 95 // looper: A running looper for the current thread. 96 // taskFunction: The function you want to be called on a separate thread 97 // to perform the task. 98 // taskDoneFunction: The function you want to be called on the event 99 // loop in the current thread once the task is completed. 100 // checkTimeoutMs: The time in milliseconds between consecutive checks 101 // for thread termination. A bigger value possibly delayes the 102 // call to |taskDoneFunction|, but leads to fewer checks. 103 // Default: 1 second. 104 // flags: See android::base::Thread. 105 ParallelTask(android::base::Looper* looper, 106 TaskFunction taskFunction, 107 TaskDoneFunction taskDoneFunction, 108 android::base::Looper::Duration checkTimeoutMs = 1 * 1000, 109 ThreadFlags flags = ThreadFlags::MaskSignals) ParallelTaskBase(looper,checkTimeoutMs,flags)110 : ParallelTaskBase(looper, checkTimeoutMs, flags), 111 mTaskFunction(taskFunction), mTaskDoneFunction(taskDoneFunction) {} 112 113 // Start the thread instance. Returns true on success, false otherwise. 114 // (e.g. if the thread was already started or terminated). start()115 bool start() { return ParallelTaskBase::start(); } 116 117 // Returns true if the task has been |start|'ed, but the call to 118 // |taskDone| hasn't finished yet. 119 // This function should be called from the same thread that called |start|. inFlight()120 bool inFlight() const { return ParallelTaskBase::inFlight(); } 121 122 protected: taskImpl()123 void taskImpl() override final { mTaskFunction(&mResultBuffer); } 124 taskDoneImpl()125 void taskDoneImpl() override final { mTaskDoneFunction(mResultBuffer); } 126 127 private: 128 ResultType mResultBuffer; 129 TaskFunction mTaskFunction; 130 TaskDoneFunction mTaskDoneFunction; 131 132 DISALLOW_COPY_AND_ASSIGN(ParallelTask); 133 }; 134 135 namespace internal { 136 137 template <class ResultType> 138 class SelfDeletingParallelTask { 139 public: 140 using TaskFunction = typename ParallelTask<ResultType>::TaskFunction; 141 using TaskDoneFunction = 142 typename ParallelTask<ResultType>::TaskDoneFunction; 143 SelfDeletingParallelTask(android::base::Looper * looper,TaskFunction taskFunction,TaskDoneFunction taskDoneFunction,android::base::Looper::Duration checkTimeoutMs)144 SelfDeletingParallelTask(android::base::Looper* looper, 145 TaskFunction taskFunction, 146 TaskDoneFunction taskDoneFunction, 147 android::base::Looper::Duration checkTimeoutMs) 148 : mTaskDoneFunction(taskDoneFunction), 149 mParallelTask(looper, 150 taskFunction, 151 std::bind(&SelfDeletingParallelTask::taskDoneFunction, 152 this, 153 std::placeholders::_1), 154 checkTimeoutMs) {} 155 start()156 bool start() { return mParallelTask.start(); }; 157 taskDoneFunction(const ResultType & result)158 void taskDoneFunction(const ResultType& result) { 159 mTaskDoneFunction(result); 160 delete this; 161 } 162 163 private: 164 TaskDoneFunction mTaskDoneFunction; 165 ParallelTask<ResultType> mParallelTask; 166 167 DISALLOW_COPY_AND_ASSIGN(SelfDeletingParallelTask); 168 }; 169 170 } // namespace internal 171 172 template<class ResultType> 173 bool runParallelTask(android::base::Looper* looper, 174 std::function<void(ResultType*)> taskFunction, 175 std::function<void(const ResultType&)> taskDoneFunction, 176 android::base::Looper::Duration checkTimeoutMs = 1 * 1000) { 177 auto flyaway = new internal::SelfDeletingParallelTask<ResultType>( 178 looper, taskFunction, taskDoneFunction, checkTimeoutMs); 179 return flyaway->start(); 180 181 } 182 183 } // namespace base 184 } // namespace android 185