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