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 class TaskRunner : public MainloopProcessor, private NonCopyable 57 { 58 public: 59 /** 60 * This type represents the generic executable task. 61 */ 62 template <class T> using Task = std::function<T(void)>; 63 64 /** 65 * This type represents a unique task ID to an delayed task. 66 * 67 * Note: A valid task ID is never zero. 68 */ 69 typedef uint64_t TaskId; 70 71 /** 72 * This constructor initializes the Task Runner instance. 73 */ 74 TaskRunner(void); 75 76 /** 77 * This destructor destroys the Task Runner instance. 78 */ 79 ~TaskRunner(void) override; 80 81 /** 82 * This method posts a task to the task runner and returns immediately. 83 * 84 * Tasks are executed sequentially and follow the First-Come-First-Serve rule. 85 * It is safe to call this method in different threads concurrently. 86 * 87 * @param[in] aTask The task to be executed. 88 */ 89 void Post(Task<void> aTask); 90 91 /** 92 * This method posts a task to the task runner and returns immediately. 93 * 94 * The task will be executed on the mainloop after `aDelay` milliseconds from now. 95 * It is safe to call this method in different threads concurrently. 96 * 97 * @param[in] aDelay The delay before executing the task (in milliseconds). 98 * @param[in] aTask The task to be executed. 99 * 100 * @returns The unique task ID of the delayed task. 101 */ 102 TaskId Post(Milliseconds aDelay, Task<void> aTask); 103 104 /** 105 * This method cancels a delayed task from the task runner. 106 * It is safe to call this method in different threads concurrently. 107 * 108 * @param[in] aTaskId The unique task ID of the delayed task to cancel. 109 */ 110 void Cancel(TaskId aTaskId); 111 112 /** 113 * This method posts a task and waits for the completion of the task. 114 * 115 * Tasks are executed sequentially and follow the First-Come-First-Serve rule. 116 * This method must be called in a thread other than the mainloop thread. Otherwise, 117 * the caller will be blocked forever. 118 * 119 * @returns The result returned by the task @p aTask. 120 */ PostAndWait(const Task<T> & aTask)121 template <class T> T PostAndWait(const Task<T> &aTask) 122 { 123 std::promise<T> pro; 124 125 Post([&pro, &aTask]() { pro.set_value(aTask()); }); 126 127 return pro.get_future().get(); 128 } 129 130 void Update(MainloopContext &aMainloop) override; 131 void Process(const MainloopContext &aMainloop) override; 132 133 private: 134 enum 135 { 136 kRead = 0, 137 kWrite = 1, 138 }; 139 140 struct DelayedTask 141 { 142 friend class Comparator; 143 144 struct Comparator 145 { operator ()otbr::TaskRunner::DelayedTask::Comparator146 bool operator()(const DelayedTask &aLhs, const DelayedTask &aRhs) const { return aRhs < aLhs; } 147 }; 148 DelayedTaskotbr::TaskRunner::DelayedTask149 DelayedTask(TaskId aTaskId, Milliseconds aDelay, Task<void> aTask) 150 : mTaskId(aTaskId) 151 , mDeadline(Clock::now() + aDelay) 152 , mTask(std::move(aTask)) 153 { 154 } 155 operator <otbr::TaskRunner::DelayedTask156 bool operator<(const DelayedTask &aOther) const 157 { 158 return mDeadline <= aOther.mDeadline || (mDeadline == aOther.mDeadline && mTaskId < aOther.mTaskId); 159 } 160 GetTimeExecuteotbr::TaskRunner::DelayedTask161 Timepoint GetTimeExecute(void) const { return mDeadline; } 162 163 TaskId mTaskId; 164 Timepoint mDeadline; 165 Task<void> mTask; 166 }; 167 168 TaskId PushTask(Milliseconds aDelay, Task<void> aTask); 169 void PopTasks(void); 170 171 // The event fds which are used to wakeup the mainloop 172 // when there are pending tasks in the task queue. 173 int mEventFd[2]; 174 175 std::priority_queue<DelayedTask, std::vector<DelayedTask>, DelayedTask::Comparator> mTaskQueue; 176 177 std::set<TaskId> mActiveTaskIds; 178 TaskId mNextTaskId = 1; 179 180 // The mutex which protects the `mTaskQueue` from being 181 // simultaneously accessed by multiple threads. 182 std::mutex mTaskQueueMutex; 183 }; 184 185 } // namespace otbr 186 187 #endif // OTBR_COMMON_TASK_RUNNER_HPP_ 188