Skip to content

Commit 9ca3f90

Browse files
committed
Refactor dequeue/enqueue logic for O(1) scheduler
This commit refactors sched_enqueue_task() and sched_dequeue_task() to use the per-priority ready queues and the embedded rq_node stored in tcb_t, instead of relying only on task state inspection. Tasks are now explicitly added to and removed from the appropriate ready queue, and queue_counts, rr_cursors, and the ready_bitmap are updated accordingly.
1 parent 5d75ddf commit 9ca3f90

File tree

1 file changed

+71
-25
lines changed

1 file changed

+71
-25
lines changed

kernel/task.c

Lines changed: 71 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ static const uint8_t priority_timeslices[TASK_PRIORITY_LEVELS] = {
7676
TASK_TIMESLICE_IDLE /* Priority 7: Idle */
7777
};
7878

79-
/* Mark task as ready (state-based) */
79+
/* Enqueue task into ready queue */
8080
static void sched_enqueue_task(tcb_t *task);
8181

8282
/* Utility and Validation Functions */
@@ -343,29 +343,67 @@ void _yield(void) __attribute__((weak, alias("yield")));
343343
* practical performance with strong guarantees for fairness and reliability.
344344
*/
345345

346-
/* Add task to ready state - simple state-based approach */
346+
/* Enqueue task into ready queue */
347347
static void sched_enqueue_task(tcb_t *task)
348348
{
349349
if (unlikely(!task))
350350
return;
351351

352+
uint8_t prio_level = task->prio_level;
353+
352354
/* Ensure task has appropriate time slice for its priority */
353-
task->time_slice = get_priority_timeslice(task->prio_level);
355+
task->time_slice = get_priority_timeslice(prio_level);
354356
task->state = TASK_READY;
355357

356-
/* Task selection is handled directly through the master task list */
358+
list_t **rq = &kcb->ready_queues[prio_level];
359+
list_node_t **cursor = &kcb->rr_cursors[prio_level];
360+
361+
if (!*rq)
362+
*rq = list_create();
363+
364+
list_pushback_node(*rq, &task->rq_node);
365+
366+
/* Update task count in ready queue */
367+
kcb->queue_counts[prio_level]++;
368+
369+
/* Setup first rr_cursor */
370+
if (!*cursor)
371+
*cursor = &task->rq_node;
372+
373+
/* Advance cursor when cursor same as running task */
374+
if (*cursor == kcb->task_current)
375+
*cursor = &task->rq_node;
376+
377+
BITMAP_SET(task->prio_level);
378+
return;
357379
}
358380

359-
/* Remove task from ready queues - state-based approach for compatibility */
360-
void sched_dequeue_task(tcb_t *task)
381+
/* Remove task from ready queue; return removed ready queue node */
382+
static __attribute__((unused)) void sched_dequeue_task(tcb_t *task)
361383
{
362-
if (unlikely(!task))
384+
if (unlikely(!task || !(&task->rq_node)))
363385
return;
364386

365-
/* For tasks that need to be removed from ready state (suspended/cancelled),
366-
* we rely on the state change. The scheduler will skip non-ready tasks
367-
* when it encounters them during the round-robin traversal.
368-
*/
387+
uint8_t prio_level = task->prio_level;
388+
389+
/* For task that need to be removed from ready/running state, it need be
390+
* removed from corresponding ready queue. */
391+
list_t *rq = kcb->ready_queues[prio_level];
392+
list_node_t **cursor = &kcb->rr_cursors[prio_level];
393+
394+
/* Safely move cursor to next task node. */
395+
if (&task->rq_node == *cursor)
396+
*cursor = list_cnext(rq, *cursor);
397+
398+
/* Remove ready queue node */
399+
list_remove_node(rq, &task->rq_node);
400+
401+
/* Update task count in ready queue */
402+
if (!--kcb->queue_counts[prio_level]) {
403+
*cursor = NULL;
404+
BITMAP_CLEAN(task->prio_level);
405+
}
406+
return;
369407
}
370408

371409
/* Handle time slice expiration for current task */
@@ -386,20 +424,15 @@ void sched_tick_current_task(void)
386424
}
387425
}
388426

389-
/* Task wakeup - simple state transition approach */
427+
/* Task wakeup and enqueue into ready queue */
390428
void sched_wakeup_task(tcb_t *task)
391429
{
392430
if (unlikely(!task))
393431
return;
394432

395-
/* Mark task as ready - scheduler will find it during round-robin traversal
396-
*/
397-
if (task->state != TASK_READY) {
398-
task->state = TASK_READY;
399-
/* Ensure task has time slice */
400-
if (task->time_slice == 0)
401-
task->time_slice = get_priority_timeslice(task->prio_level);
402-
}
433+
/* Enqueue task into ready queue */
434+
if (task->state != TASK_READY && task->state != TASK_RUNNING)
435+
sched_enqueue_task(task);
403436
}
404437

405438
/* Efficient Round-Robin Task Selection with O(n) Complexity
@@ -673,6 +706,10 @@ int32_t mo_task_cancel(uint16_t id)
673706
}
674707
}
675708

709+
/* Remove from ready queue */
710+
if (tcb->state == TASK_READY)
711+
sched_dequeue_task(tcb);
712+
676713
CRITICAL_LEAVE();
677714

678715
/* Free memory outside critical section */
@@ -703,7 +740,9 @@ void mo_task_delay(uint16_t ticks)
703740

704741
tcb_t *self = kcb->task_current->data;
705742

706-
/* Set delay and blocked state - scheduler will skip blocked tasks */
743+
/* Set delay and blocked state, dequeue from ready queue */
744+
sched_dequeue_task(self);
745+
707746
self->delay = ticks;
708747
self->state = TASK_BLOCKED;
709748
NOSCHED_LEAVE();
@@ -730,8 +769,13 @@ int32_t mo_task_suspend(uint16_t id)
730769
return ERR_TASK_CANT_SUSPEND;
731770
}
732771

772+
/* Remove task node from ready queue if task is in ready queue
773+
* (TASK_RUNNING/TASK_READY).*/
774+
if (task->state == TASK_READY || task->state == TASK_RUNNING)
775+
sched_dequeue_task(task);
776+
733777
task->state = TASK_SUSPENDED;
734-
bool is_current = (kcb->task_current == node);
778+
bool is_current = (kcb->task_current->data == task);
735779

736780
CRITICAL_LEAVE();
737781

@@ -758,9 +802,8 @@ int32_t mo_task_resume(uint16_t id)
758802
CRITICAL_LEAVE();
759803
return ERR_TASK_CANT_RESUME;
760804
}
761-
762-
/* mark as ready - scheduler will find it */
763-
task->state = TASK_READY;
805+
/* Enqueue resumed task into ready queue */
806+
sched_enqueue_task(task);
764807

765808
CRITICAL_LEAVE();
766809
return ERR_OK;
@@ -874,6 +917,9 @@ void _sched_block(queue_t *wait_q)
874917

875918
tcb_t *self = kcb->task_current->data;
876919

920+
/* Remove node from ready queue */
921+
sched_dequeue_task(self);
922+
877923
if (queue_enqueue(wait_q, self) != 0)
878924
panic(ERR_SEM_OPERATION);
879925

0 commit comments

Comments
 (0)