xref: /aosp_15_r20/external/ot-br-posix/src/common/task_runner.cpp (revision 4a64e381480ef79f0532b2421e44e6ee336b8e0d)
1*4a64e381SAndroid Build Coastguard Worker /*
2*4a64e381SAndroid Build Coastguard Worker  *    Copyright (c) 2021, The OpenThread Authors.
3*4a64e381SAndroid Build Coastguard Worker  *    All rights reserved.
4*4a64e381SAndroid Build Coastguard Worker  *
5*4a64e381SAndroid Build Coastguard Worker  *    Redistribution and use in source and binary forms, with or without
6*4a64e381SAndroid Build Coastguard Worker  *    modification, are permitted provided that the following conditions are met:
7*4a64e381SAndroid Build Coastguard Worker  *    1. Redistributions of source code must retain the above copyright
8*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer.
9*4a64e381SAndroid Build Coastguard Worker  *    2. Redistributions in binary form must reproduce the above copyright
10*4a64e381SAndroid Build Coastguard Worker  *       notice, this list of conditions and the following disclaimer in the
11*4a64e381SAndroid Build Coastguard Worker  *       documentation and/or other materials provided with the distribution.
12*4a64e381SAndroid Build Coastguard Worker  *    3. Neither the name of the copyright holder nor the
13*4a64e381SAndroid Build Coastguard Worker  *       names of its contributors may be used to endorse or promote products
14*4a64e381SAndroid Build Coastguard Worker  *       derived from this software without specific prior written permission.
15*4a64e381SAndroid Build Coastguard Worker  *
16*4a64e381SAndroid Build Coastguard Worker  *    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17*4a64e381SAndroid Build Coastguard Worker  *    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18*4a64e381SAndroid Build Coastguard Worker  *    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19*4a64e381SAndroid Build Coastguard Worker  *    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20*4a64e381SAndroid Build Coastguard Worker  *    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21*4a64e381SAndroid Build Coastguard Worker  *    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22*4a64e381SAndroid Build Coastguard Worker  *    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23*4a64e381SAndroid Build Coastguard Worker  *    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24*4a64e381SAndroid Build Coastguard Worker  *    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25*4a64e381SAndroid Build Coastguard Worker  *    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26*4a64e381SAndroid Build Coastguard Worker  *    POSSIBILITY OF SUCH DAMAGE.
27*4a64e381SAndroid Build Coastguard Worker  */
28*4a64e381SAndroid Build Coastguard Worker 
29*4a64e381SAndroid Build Coastguard Worker /**
30*4a64e381SAndroid Build Coastguard Worker  * @file
31*4a64e381SAndroid Build Coastguard Worker  * This file implements the Task Runner that executes tasks on the mainloop.
32*4a64e381SAndroid Build Coastguard Worker  */
33*4a64e381SAndroid Build Coastguard Worker 
34*4a64e381SAndroid Build Coastguard Worker #include "common/task_runner.hpp"
35*4a64e381SAndroid Build Coastguard Worker 
36*4a64e381SAndroid Build Coastguard Worker #include <algorithm>
37*4a64e381SAndroid Build Coastguard Worker 
38*4a64e381SAndroid Build Coastguard Worker #include <fcntl.h>
39*4a64e381SAndroid Build Coastguard Worker #include <unistd.h>
40*4a64e381SAndroid Build Coastguard Worker 
41*4a64e381SAndroid Build Coastguard Worker #include "common/code_utils.hpp"
42*4a64e381SAndroid Build Coastguard Worker 
43*4a64e381SAndroid Build Coastguard Worker namespace otbr {
44*4a64e381SAndroid Build Coastguard Worker 
TaskRunner(void)45*4a64e381SAndroid Build Coastguard Worker TaskRunner::TaskRunner(void)
46*4a64e381SAndroid Build Coastguard Worker     : mTaskQueue(DelayedTask::Comparator{})
47*4a64e381SAndroid Build Coastguard Worker {
48*4a64e381SAndroid Build Coastguard Worker     int flags;
49*4a64e381SAndroid Build Coastguard Worker 
50*4a64e381SAndroid Build Coastguard Worker     // We do not handle failures when creating a pipe, simply die.
51*4a64e381SAndroid Build Coastguard Worker     VerifyOrDie(pipe(mEventFd) != -1, strerror(errno));
52*4a64e381SAndroid Build Coastguard Worker 
53*4a64e381SAndroid Build Coastguard Worker     flags = fcntl(mEventFd[kRead], F_GETFL, 0);
54*4a64e381SAndroid Build Coastguard Worker     VerifyOrDie(fcntl(mEventFd[kRead], F_SETFL, flags | O_NONBLOCK) != -1, strerror(errno));
55*4a64e381SAndroid Build Coastguard Worker     flags = fcntl(mEventFd[kWrite], F_GETFL, 0);
56*4a64e381SAndroid Build Coastguard Worker     VerifyOrDie(fcntl(mEventFd[kWrite], F_SETFL, flags | O_NONBLOCK) != -1, strerror(errno));
57*4a64e381SAndroid Build Coastguard Worker }
58*4a64e381SAndroid Build Coastguard Worker 
~TaskRunner(void)59*4a64e381SAndroid Build Coastguard Worker TaskRunner::~TaskRunner(void)
60*4a64e381SAndroid Build Coastguard Worker {
61*4a64e381SAndroid Build Coastguard Worker     if (mEventFd[kRead] != -1)
62*4a64e381SAndroid Build Coastguard Worker     {
63*4a64e381SAndroid Build Coastguard Worker         close(mEventFd[kRead]);
64*4a64e381SAndroid Build Coastguard Worker         mEventFd[kRead] = -1;
65*4a64e381SAndroid Build Coastguard Worker     }
66*4a64e381SAndroid Build Coastguard Worker     if (mEventFd[kWrite] != -1)
67*4a64e381SAndroid Build Coastguard Worker     {
68*4a64e381SAndroid Build Coastguard Worker         close(mEventFd[kWrite]);
69*4a64e381SAndroid Build Coastguard Worker         mEventFd[kWrite] = -1;
70*4a64e381SAndroid Build Coastguard Worker     }
71*4a64e381SAndroid Build Coastguard Worker }
72*4a64e381SAndroid Build Coastguard Worker 
Post(Task<void> aTask)73*4a64e381SAndroid Build Coastguard Worker void TaskRunner::Post(Task<void> aTask)
74*4a64e381SAndroid Build Coastguard Worker {
75*4a64e381SAndroid Build Coastguard Worker     Post(Milliseconds::zero(), std::move(aTask));
76*4a64e381SAndroid Build Coastguard Worker }
77*4a64e381SAndroid Build Coastguard Worker 
Post(Milliseconds aDelay,Task<void> aTask)78*4a64e381SAndroid Build Coastguard Worker TaskRunner::TaskId TaskRunner::Post(Milliseconds aDelay, Task<void> aTask)
79*4a64e381SAndroid Build Coastguard Worker {
80*4a64e381SAndroid Build Coastguard Worker     return PushTask(aDelay, std::move(aTask));
81*4a64e381SAndroid Build Coastguard Worker }
82*4a64e381SAndroid Build Coastguard Worker 
Update(MainloopContext & aMainloop)83*4a64e381SAndroid Build Coastguard Worker void TaskRunner::Update(MainloopContext &aMainloop)
84*4a64e381SAndroid Build Coastguard Worker {
85*4a64e381SAndroid Build Coastguard Worker     aMainloop.AddFdToReadSet(mEventFd[kRead]);
86*4a64e381SAndroid Build Coastguard Worker 
87*4a64e381SAndroid Build Coastguard Worker     {
88*4a64e381SAndroid Build Coastguard Worker         std::lock_guard<std::mutex> _(mTaskQueueMutex);
89*4a64e381SAndroid Build Coastguard Worker 
90*4a64e381SAndroid Build Coastguard Worker         if (!mTaskQueue.empty())
91*4a64e381SAndroid Build Coastguard Worker         {
92*4a64e381SAndroid Build Coastguard Worker             auto  now     = Clock::now();
93*4a64e381SAndroid Build Coastguard Worker             auto &task    = mTaskQueue.top();
94*4a64e381SAndroid Build Coastguard Worker             auto  delay   = std::chrono::duration_cast<Microseconds>(task.GetTimeExecute() - now);
95*4a64e381SAndroid Build Coastguard Worker             auto  timeout = FromTimeval<Microseconds>(aMainloop.mTimeout);
96*4a64e381SAndroid Build Coastguard Worker 
97*4a64e381SAndroid Build Coastguard Worker             if (task.GetTimeExecute() < now)
98*4a64e381SAndroid Build Coastguard Worker             {
99*4a64e381SAndroid Build Coastguard Worker                 delay = Microseconds::zero();
100*4a64e381SAndroid Build Coastguard Worker             }
101*4a64e381SAndroid Build Coastguard Worker 
102*4a64e381SAndroid Build Coastguard Worker             if (delay <= timeout)
103*4a64e381SAndroid Build Coastguard Worker             {
104*4a64e381SAndroid Build Coastguard Worker                 aMainloop.mTimeout.tv_sec  = delay.count() / 1000000;
105*4a64e381SAndroid Build Coastguard Worker                 aMainloop.mTimeout.tv_usec = delay.count() % 1000000;
106*4a64e381SAndroid Build Coastguard Worker             }
107*4a64e381SAndroid Build Coastguard Worker         }
108*4a64e381SAndroid Build Coastguard Worker     }
109*4a64e381SAndroid Build Coastguard Worker }
110*4a64e381SAndroid Build Coastguard Worker 
Process(const MainloopContext & aMainloop)111*4a64e381SAndroid Build Coastguard Worker void TaskRunner::Process(const MainloopContext &aMainloop)
112*4a64e381SAndroid Build Coastguard Worker {
113*4a64e381SAndroid Build Coastguard Worker     OTBR_UNUSED_VARIABLE(aMainloop);
114*4a64e381SAndroid Build Coastguard Worker 
115*4a64e381SAndroid Build Coastguard Worker     ssize_t rval;
116*4a64e381SAndroid Build Coastguard Worker 
117*4a64e381SAndroid Build Coastguard Worker     // Read any data in the pipe.
118*4a64e381SAndroid Build Coastguard Worker     do
119*4a64e381SAndroid Build Coastguard Worker     {
120*4a64e381SAndroid Build Coastguard Worker         uint8_t n;
121*4a64e381SAndroid Build Coastguard Worker 
122*4a64e381SAndroid Build Coastguard Worker         rval = read(mEventFd[kRead], &n, sizeof(n));
123*4a64e381SAndroid Build Coastguard Worker     } while (rval > 0 || (rval == -1 && errno == EINTR));
124*4a64e381SAndroid Build Coastguard Worker 
125*4a64e381SAndroid Build Coastguard Worker     // Critical error happens, simply die.
126*4a64e381SAndroid Build Coastguard Worker     VerifyOrDie(errno == EAGAIN || errno == EWOULDBLOCK, strerror(errno));
127*4a64e381SAndroid Build Coastguard Worker 
128*4a64e381SAndroid Build Coastguard Worker     PopTasks();
129*4a64e381SAndroid Build Coastguard Worker }
130*4a64e381SAndroid Build Coastguard Worker 
PushTask(Milliseconds aDelay,Task<void> aTask)131*4a64e381SAndroid Build Coastguard Worker TaskRunner::TaskId TaskRunner::PushTask(Milliseconds aDelay, Task<void> aTask)
132*4a64e381SAndroid Build Coastguard Worker {
133*4a64e381SAndroid Build Coastguard Worker     ssize_t       rval;
134*4a64e381SAndroid Build Coastguard Worker     const uint8_t kOne = 1;
135*4a64e381SAndroid Build Coastguard Worker     TaskId        taskId;
136*4a64e381SAndroid Build Coastguard Worker 
137*4a64e381SAndroid Build Coastguard Worker     {
138*4a64e381SAndroid Build Coastguard Worker         std::lock_guard<std::mutex> _(mTaskQueueMutex);
139*4a64e381SAndroid Build Coastguard Worker 
140*4a64e381SAndroid Build Coastguard Worker         taskId = mNextTaskId++;
141*4a64e381SAndroid Build Coastguard Worker 
142*4a64e381SAndroid Build Coastguard Worker         mActiveTaskIds.insert(taskId);
143*4a64e381SAndroid Build Coastguard Worker         mTaskQueue.emplace(taskId, aDelay, std::move(aTask));
144*4a64e381SAndroid Build Coastguard Worker     }
145*4a64e381SAndroid Build Coastguard Worker 
146*4a64e381SAndroid Build Coastguard Worker     do
147*4a64e381SAndroid Build Coastguard Worker     {
148*4a64e381SAndroid Build Coastguard Worker         rval = write(mEventFd[kWrite], &kOne, sizeof(kOne));
149*4a64e381SAndroid Build Coastguard Worker     } while (rval == -1 && errno == EINTR);
150*4a64e381SAndroid Build Coastguard Worker 
151*4a64e381SAndroid Build Coastguard Worker     VerifyOrExit(rval == -1);
152*4a64e381SAndroid Build Coastguard Worker 
153*4a64e381SAndroid Build Coastguard Worker     // Critical error happens, simply die.
154*4a64e381SAndroid Build Coastguard Worker     VerifyOrDie(errno == EAGAIN || errno == EWOULDBLOCK, strerror(errno));
155*4a64e381SAndroid Build Coastguard Worker 
156*4a64e381SAndroid Build Coastguard Worker     // We are blocked because there are already data (written by other concurrent callers in
157*4a64e381SAndroid Build Coastguard Worker     // different threads) in the pipe, and the mEventFd[kRead] should be readable now.
158*4a64e381SAndroid Build Coastguard Worker     otbrLogWarning("Failed to write fd %d: %s", mEventFd[kWrite], strerror(errno));
159*4a64e381SAndroid Build Coastguard Worker 
160*4a64e381SAndroid Build Coastguard Worker exit:
161*4a64e381SAndroid Build Coastguard Worker     return taskId;
162*4a64e381SAndroid Build Coastguard Worker }
163*4a64e381SAndroid Build Coastguard Worker 
Cancel(TaskRunner::TaskId aTaskId)164*4a64e381SAndroid Build Coastguard Worker void TaskRunner::Cancel(TaskRunner::TaskId aTaskId)
165*4a64e381SAndroid Build Coastguard Worker {
166*4a64e381SAndroid Build Coastguard Worker     std::lock_guard<std::mutex> _(mTaskQueueMutex);
167*4a64e381SAndroid Build Coastguard Worker 
168*4a64e381SAndroid Build Coastguard Worker     mActiveTaskIds.erase(aTaskId);
169*4a64e381SAndroid Build Coastguard Worker }
170*4a64e381SAndroid Build Coastguard Worker 
PopTasks(void)171*4a64e381SAndroid Build Coastguard Worker void TaskRunner::PopTasks(void)
172*4a64e381SAndroid Build Coastguard Worker {
173*4a64e381SAndroid Build Coastguard Worker     while (true)
174*4a64e381SAndroid Build Coastguard Worker     {
175*4a64e381SAndroid Build Coastguard Worker         Task<void> task;
176*4a64e381SAndroid Build Coastguard Worker         bool       canceled;
177*4a64e381SAndroid Build Coastguard Worker 
178*4a64e381SAndroid Build Coastguard Worker         // The braces here are necessary for auto-releasing of the mutex.
179*4a64e381SAndroid Build Coastguard Worker         {
180*4a64e381SAndroid Build Coastguard Worker             std::lock_guard<std::mutex> _(mTaskQueueMutex);
181*4a64e381SAndroid Build Coastguard Worker 
182*4a64e381SAndroid Build Coastguard Worker             if (!mTaskQueue.empty() && mTaskQueue.top().GetTimeExecute() <= Clock::now())
183*4a64e381SAndroid Build Coastguard Worker             {
184*4a64e381SAndroid Build Coastguard Worker                 const DelayedTask &top    = mTaskQueue.top();
185*4a64e381SAndroid Build Coastguard Worker                 TaskId             taskId = top.mTaskId;
186*4a64e381SAndroid Build Coastguard Worker 
187*4a64e381SAndroid Build Coastguard Worker                 task = std::move(top.mTask);
188*4a64e381SAndroid Build Coastguard Worker                 mTaskQueue.pop();
189*4a64e381SAndroid Build Coastguard Worker                 canceled = (mActiveTaskIds.erase(taskId) == 0);
190*4a64e381SAndroid Build Coastguard Worker             }
191*4a64e381SAndroid Build Coastguard Worker             else
192*4a64e381SAndroid Build Coastguard Worker             {
193*4a64e381SAndroid Build Coastguard Worker                 break;
194*4a64e381SAndroid Build Coastguard Worker             }
195*4a64e381SAndroid Build Coastguard Worker         }
196*4a64e381SAndroid Build Coastguard Worker 
197*4a64e381SAndroid Build Coastguard Worker         if (!canceled)
198*4a64e381SAndroid Build Coastguard Worker         {
199*4a64e381SAndroid Build Coastguard Worker             task();
200*4a64e381SAndroid Build Coastguard Worker         }
201*4a64e381SAndroid Build Coastguard Worker     }
202*4a64e381SAndroid Build Coastguard Worker }
203*4a64e381SAndroid Build Coastguard Worker 
204*4a64e381SAndroid Build Coastguard Worker } // namespace otbr
205