1 /* 2 * Copyright (c) 2021, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file defines the Task Runner that executes tasks on the mainloop. 32 */ 33 34 #ifndef OTBR_COMMON_TASK_RUNNER_HPP_ 35 #define OTBR_COMMON_TASK_RUNNER_HPP_ 36 37 #include <openthread-br/config.h> 38 39 #include <chrono> 40 #include <functional> 41 #include <future> 42 #include <mutex> 43 #include <queue> 44 #include <set> 45 46 #include "common/code_utils.hpp" 47 #include "common/mainloop.hpp" 48 #include "common/time.hpp" 49 50 namespace otbr { 51 52 /** 53 * This class implements the Task Runner that executes 54 * tasks on the mainloop. 55 * 56 */ 57 class TaskRunner : public MainloopProcessor, private NonCopyable 58 { 59 public: 60 /** 61 * This type represents the generic executable task. 62 * 63 */ 64 template <class T> using Task = std::function<T(void)>; 65 66 /** 67 * This type represents a unique task ID to an delayed task. 68 * 69 * Note: A valid task ID is never zero. 70 * 71 */ 72 typedef uint64_t TaskId; 73 74 /** 75 * This constructor initializes the Task Runner instance. 76 * 77 */ 78 TaskRunner(void); 79 80 /** 81 * This destructor destroys the Task Runner instance. 82 * 83 */ 84 ~TaskRunner(void) override; 85 86 /** 87 * This method posts a task to the task runner and returns immediately. 88 * 89 * Tasks are executed sequentially and follow the First-Come-First-Serve rule. 90 * It is safe to call this method in different threads concurrently. 91 * 92 * @param[in] aTask The task to be executed. 93 * 94 */ 95 void Post(Task<void> aTask); 96 97 /** 98 * This method posts a task to the task runner and returns immediately. 99 * 100 * The task will be executed on the mainloop after `aDelay` milliseconds from now. 101 * It is safe to call this method in different threads concurrently. 102 * 103 * @param[in] aDelay The delay before executing the task (in milliseconds). 104 * @param[in] aTask The task to be executed. 105 * 106 * @returns The unique task ID of the delayed task. 107 * 108 */ 109 TaskId Post(Milliseconds aDelay, Task<void> aTask); 110 111 /** 112 * This method cancels a delayed task from the task runner. 113 * It is safe to call this method in different threads concurrently. 114 * 115 * @param[in] aTaskId The unique task ID of the delayed task to cancel. 116 * 117 */ 118 void Cancel(TaskId aTaskId); 119 120 /** 121 * This method posts a task and waits for the completion of the task. 122 * 123 * Tasks are executed sequentially and follow the First-Come-First-Serve rule. 124 * This method must be called in a thread other than the mainloop thread. Otherwise, 125 * the caller will be blocked forever. 126 * 127 * @returns The result returned by the task @p aTask. 128 * 129 */ PostAndWait(const Task<T> & aTask)130 template <class T> T PostAndWait(const Task<T> &aTask) 131 { 132 std::promise<T> pro; 133 134 Post([&pro, &aTask]() { pro.set_value(aTask()); }); 135 136 return pro.get_future().get(); 137 } 138 139 void Update(MainloopContext &aMainloop) override; 140 void Process(const MainloopContext &aMainloop) override; 141 142 private: 143 enum 144 { 145 kRead = 0, 146 kWrite = 1, 147 }; 148 149 struct DelayedTask 150 { 151 friend class Comparator; 152 153 struct Comparator 154 { operator ()otbr::TaskRunner::DelayedTask::Comparator155 bool operator()(const DelayedTask &aLhs, const DelayedTask &aRhs) const { return aRhs < aLhs; } 156 }; 157 DelayedTaskotbr::TaskRunner::DelayedTask158 DelayedTask(TaskId aTaskId, Milliseconds aDelay, Task<void> aTask) 159 : mTaskId(aTaskId) 160 , mDeadline(Clock::now() + aDelay) 161 , mTask(std::move(aTask)) 162 { 163 } 164 operator <otbr::TaskRunner::DelayedTask165 bool operator<(const DelayedTask &aOther) const 166 { 167 return mDeadline <= aOther.mDeadline || (mDeadline == aOther.mDeadline && mTaskId < aOther.mTaskId); 168 } 169 GetTimeExecuteotbr::TaskRunner::DelayedTask170 Timepoint GetTimeExecute(void) const { return mDeadline; } 171 172 TaskId mTaskId; 173 Timepoint mDeadline; 174 Task<void> mTask; 175 }; 176 177 TaskId PushTask(Milliseconds aDelay, Task<void> aTask); 178 void PopTasks(void); 179 180 // The event fds which are used to wakeup the mainloop 181 // when there are pending tasks in the task queue. 182 int mEventFd[2]; 183 184 std::priority_queue<DelayedTask, std::vector<DelayedTask>, DelayedTask::Comparator> mTaskQueue; 185 186 std::set<TaskId> mActiveTaskIds; 187 TaskId mNextTaskId = 1; 188 189 // The mutex which protects the `mTaskQueue` from being 190 // simultaneously accessed by multiple threads. 191 std::mutex mTaskQueueMutex; 192 }; 193 194 } // namespace otbr 195 196 #endif // OTBR_COMMON_TASK_RUNNER_HPP_ 197