[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:
Abtin Keshavarzian
2019-11-09 01:17:01 +01:00
committed by Jonathan Hui
parent 8b4f3fff31
commit 335b305ba8
2 changed files with 54 additions and 65 deletions
+38 -50
View File
@@ -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
View File
@@ -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
};
/**