mirror of
https://github.com/espressif/openthread.git
synced 2026-08-09 04:07:47 +00:00
[tasklet] use circular linked list (#4309)
This commit contains the following changes: - Changes `TaskletScheduler` to use a circular linked list. - Adds `Tasklet::IsPosted()` which indicates whether a tasklet is posted or not (by checking `mNext` pointer against NULL). - Simplifies processing of tasklets from `ProcessQueuedTasklets()` by creating a copy of current list and clearing the main list (this way, a newly posted tasklet would automatically trigger a call to `otTaskletsSignalPending()`).
This commit is contained in:
committed by
Jonathan Hui
parent
8b4f3fff31
commit
335b305ba8
+38
-50
@@ -50,78 +50,66 @@ Tasklet::Tasklet(Instance &aInstance, Handler aHandler, void *aOwner)
|
||||
}
|
||||
|
||||
otError Tasklet::Post(void)
|
||||
{
|
||||
return Get<TaskletScheduler>().Post(*this);
|
||||
}
|
||||
|
||||
TaskletScheduler::TaskletScheduler(void)
|
||||
: mHead(NULL)
|
||||
, mTail(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
otError TaskletScheduler::Post(Tasklet &aTasklet)
|
||||
{
|
||||
otError error = OT_ERROR_NONE;
|
||||
|
||||
VerifyOrExit(mTail != &aTasklet && aTasklet.mNext == NULL, error = OT_ERROR_ALREADY);
|
||||
|
||||
VerifyOrExit(&aTasklet.Get<TaskletScheduler>() == this);
|
||||
|
||||
if (mTail == NULL)
|
||||
{
|
||||
mHead = &aTasklet;
|
||||
mTail = &aTasklet;
|
||||
otTaskletsSignalPending(&aTasklet.GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
mTail->mNext = &aTasklet;
|
||||
mTail = &aTasklet;
|
||||
}
|
||||
VerifyOrExit(!IsPosted(), error = OT_ERROR_ALREADY);
|
||||
Get<TaskletScheduler>().PostTasklet(*this);
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
Tasklet *TaskletScheduler::PopTasklet(void)
|
||||
TaskletScheduler::TaskletScheduler(void)
|
||||
: mTail(NULL)
|
||||
{
|
||||
Tasklet *task = mHead;
|
||||
}
|
||||
|
||||
if (task != NULL)
|
||||
void TaskletScheduler::PostTasklet(Tasklet &aTasklet)
|
||||
{
|
||||
// Tasklets are saved in a circular singly linked list.
|
||||
|
||||
if (mTail == NULL)
|
||||
{
|
||||
mHead = mHead->mNext;
|
||||
|
||||
if (mHead == NULL)
|
||||
{
|
||||
mTail = NULL;
|
||||
}
|
||||
|
||||
task->mNext = NULL;
|
||||
mTail = &aTasklet;
|
||||
mTail->mNext = mTail;
|
||||
otTaskletsSignalPending(&aTasklet.GetInstance());
|
||||
}
|
||||
else
|
||||
{
|
||||
aTasklet.mNext = mTail->mNext;
|
||||
mTail->mNext = &aTasklet;
|
||||
mTail = &aTasklet;
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
void TaskletScheduler::ProcessQueuedTasklets(void)
|
||||
{
|
||||
Tasklet *tail = mTail;
|
||||
Tasklet *cur;
|
||||
|
||||
while ((cur = PopTasklet()) != NULL)
|
||||
// This method processes all tasklets queued when this is called. We
|
||||
// keep a copy the current list and then clear the main list by
|
||||
// setting `mTail` to NULL. A newly posted tasklet while processing
|
||||
// the currently queued tasklets will then trigger a call to
|
||||
// `otTaskletsSignalPending()`.
|
||||
|
||||
mTail = NULL;
|
||||
|
||||
while (tail != NULL)
|
||||
{
|
||||
cur->RunTask();
|
||||
Tasklet *tasklet = tail->mNext;
|
||||
|
||||
// only process tasklets that were queued at the time this method was called
|
||||
if (cur == tail)
|
||||
if (tasklet == tail)
|
||||
{
|
||||
if (mHead != NULL)
|
||||
{
|
||||
otTaskletsSignalPending(&mHead->GetInstance());
|
||||
}
|
||||
|
||||
break;
|
||||
tail = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
tail->mNext = tasklet->mNext;
|
||||
}
|
||||
|
||||
tasklet->mNext = NULL;
|
||||
tasklet->RunTask();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-15
@@ -84,11 +84,20 @@ public:
|
||||
Tasklet(Instance &aInstance, Handler aHandler, void *aOwner);
|
||||
|
||||
/**
|
||||
* This method puts the tasklet on the run queue.
|
||||
* This method puts the tasklet on the tasklet scheduler run queue.
|
||||
*
|
||||
*/
|
||||
otError Post(void);
|
||||
|
||||
/**
|
||||
* This method indicates whether the tasklet is posted or not.
|
||||
*
|
||||
* @retval TRUE The tasklet is posted.
|
||||
* @retval FALSE The tasklet is not posted.
|
||||
*
|
||||
*/
|
||||
bool IsPosted(void) const { return (mNext != NULL); }
|
||||
|
||||
private:
|
||||
void RunTask(void) { mHandler(*this); }
|
||||
|
||||
@@ -140,6 +149,8 @@ private:
|
||||
*/
|
||||
class TaskletScheduler
|
||||
{
|
||||
friend class Tasklet;
|
||||
|
||||
public:
|
||||
/**
|
||||
* This constructor initializes the object.
|
||||
@@ -147,16 +158,6 @@ public:
|
||||
*/
|
||||
TaskletScheduler(void);
|
||||
|
||||
/**
|
||||
* This method enqueues a tasklet into the run queue.
|
||||
*
|
||||
* @param[in] aTasklet A reference to the tasklet to enqueue.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully enqueued the tasklet.
|
||||
* @retval OT_ERROR_ALREADY The tasklet was already enqueued.
|
||||
*/
|
||||
otError Post(Tasklet &aTasklet);
|
||||
|
||||
/**
|
||||
* This method indicates whether or not there are tasklets pending.
|
||||
*
|
||||
@@ -164,7 +165,7 @@ public:
|
||||
* @retval FALSE If there are no tasklets pending.
|
||||
*
|
||||
*/
|
||||
bool AreTaskletsPending(void) const { return mHead != NULL; }
|
||||
bool AreTaskletsPending(void) const { return mTail != NULL; }
|
||||
|
||||
/**
|
||||
* This method processes all tasklets queued when this is called.
|
||||
@@ -173,9 +174,9 @@ public:
|
||||
void ProcessQueuedTasklets(void);
|
||||
|
||||
private:
|
||||
Tasklet *PopTasklet(void);
|
||||
Tasklet *mHead;
|
||||
Tasklet *mTail;
|
||||
void PostTasklet(Tasklet &aTasklet);
|
||||
|
||||
Tasklet *mTail; // A circular singly linked-list
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user