• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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