Skip to content

Commit 901ecbf

Browse files
committed
Implement task selection in O(1) time complexity
New tasks created by `mo_task_spawn()` are enqueued into their priority ready queue. The very first task is special-cased: it becomes `task_current` and its state is set to `TASK_RUNNING` (not enqueued). `sched_select_next_task()` first returns the running task to its ready queue, then finds the highest non-empty priority by scanning the `ready_bitmap`, pops one node from that queue, and assigns it to `task_current`. The corresponding priority bit position in bitmap will be cleared when the queue becomes empty. This reduces selection from O(n) to O(1) and remains existing function calls.
1 parent df1c5c1 commit 901ecbf

File tree

2 files changed

+54
-28
lines changed

2 files changed

+54
-28
lines changed

include/sys/task.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ typedef struct {
128128
volatile uint32_t ticks; /* Global system tick, incremented by timer */
129129

130130
/* per-hart scheduler management */
131-
sched_t scheduler;
131+
sched_t *harts;
132132
} kcb_t;
133133

134134
/* Global pointer to the singleton Kernel Control Block */

kernel/task.c

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,18 @@
1515
static int32_t noop_rtsched(void);
1616
void _timer_tick_handler(void);
1717

18+
/* hart 0 scheduler */
19+
static sched_t hart0_sched = {
20+
.ready_bitmap = 0,
21+
.ready_queues = {NULL},
22+
.rr_cursors = {NULL},
23+
.quantum_cycles = {0},
24+
.last_selected_prio = 0,
25+
.local_switches = 0,
26+
.current_task = NULL,
27+
.hart_id = 0,
28+
};
29+
1830
/* Kernel-wide control block (KCB) */
1931
static kcb_t kernel_state = {
2032
.tasks = NULL,
@@ -25,6 +37,7 @@ static kcb_t kernel_state = {
2537
.task_count = 0,
2638
.ticks = 0,
2739
.preemptive = true, /* Default to preemptive mode */
40+
.harts = &hart0_sched,
2841
};
2942
kcb_t *kcb = &kernel_state;
3043

@@ -344,7 +357,6 @@ static void sched_enqueue_task(tcb_t *task)
344357
/* Ensure task has appropriate time slice for its priority */
345358
task->time_slice = get_priority_timeslice(task->prio_level);
346359
task->state = TASK_READY;
347-
348360
/* Task selection is handled directly through the master task list */
349361
}
350362

@@ -418,34 +430,32 @@ uint16_t sched_select_next_task(void)
418430

419431
/* Mark current task as ready if it was running */
420432
if (current_task->state == TASK_RUNNING)
433+
{
421434
current_task->state = TASK_READY;
435+
list_pushback(kcb->harts->ready_queues[current_task->prio_level], current_task);
436+
kcb->harts->ready_bitmap |= (1U << current_task->prio_level);
437+
}
422438

423439
/* Round-robin search: find next ready task in the master task list */
424-
list_node_t *start_node = kcb->task_current;
425-
list_node_t *node = start_node;
426-
int iterations = 0; /* Safety counter to prevent infinite loops */
427-
428-
do {
429-
/* Move to next task (circular) */
430-
node = list_cnext(kcb->tasks, node);
431-
if (!node || !node->data)
432-
continue;
433-
434-
tcb_t *task = node->data;
435-
436-
/* Skip non-ready tasks */
437-
if (task->state != TASK_READY)
438-
continue;
439-
440-
/* Found a ready task */
441-
kcb->task_current = node;
442-
task->state = TASK_RUNNING;
443-
task->time_slice = get_priority_timeslice(task->prio_level);
444-
445-
return task->id;
446-
447-
} while (node != start_node && ++iterations < SCHED_IMAX);
448440

441+
/* Find highest priority task queue */
442+
uint32_t bitmap = kcb->harts->ready_bitmap;
443+
int highest_prio_level = 0;
444+
for (;!(bitmap & 1U); highest_prio_level++, bitmap >>= 1);
445+
446+
/* Pop out from corresponding queue and mark it as TASK_RUNNING */
447+
list_node_t *node = kcb->harts->ready_queues[highest_prio_level]->head->next;
448+
list_pop(kcb->harts->ready_queues[highest_prio_level]);
449+
((tcb_t *)node->data)->state = TASK_RUNNING;
450+
kcb->task_current = node;
451+
452+
/* Check popped queue is empty or not */
453+
if (kcb->harts->ready_queues[highest_prio_level]->length == 0)
454+
kcb->harts->ready_bitmap &= ~(1U << highest_prio_level);
455+
456+
if (node)
457+
return 1;
458+
449459
/* No ready tasks found - this should not happen in normal operation */
450460
panic(ERR_NO_TASKS);
451461
return 0;
@@ -603,6 +613,12 @@ int32_t mo_task_spawn(void *task_entry, uint16_t stack_size_req)
603613
}
604614
}
605615

616+
/* Create corresponding ready queue */
617+
if (!kcb->harts->ready_queues[tcb->prio_level]) {
618+
kcb->harts->ready_queues[tcb->prio_level] = list_create();
619+
kcb->tasks = list_create();
620+
}
621+
606622
list_node_t *node = list_pushback(kcb->tasks, tcb);
607623
if (!node) {
608624
CRITICAL_LEAVE();
@@ -615,8 +631,16 @@ int32_t mo_task_spawn(void *task_entry, uint16_t stack_size_req)
615631
tcb->id = kcb->next_tid++;
616632
kcb->task_count++; /* Cached count of active tasks for quick access */
617633

618-
if (!kcb->task_current)
634+
/* If tcb is the first task, turn it into TASK_RUNNING state and does not put into ready queue */
635+
if (!kcb->task_current) {
619636
kcb->task_current = node;
637+
tcb->state = TASK_RUNNING;
638+
}
639+
else {
640+
/* Setup bitmap and put into corresponding ready queue */
641+
kcb->harts->ready_bitmap |= (1U << tcb->prio_level);
642+
list_pushback(kcb->harts->ready_queues[tcb->prio_level], tcb);
643+
}
620644

621645
CRITICAL_LEAVE();
622646

@@ -630,8 +654,10 @@ int32_t mo_task_spawn(void *task_entry, uint16_t stack_size_req)
630654

631655
/* Add to cache and mark ready */
632656
cache_task(tcb->id, tcb);
633-
sched_enqueue_task(tcb);
634657

658+
/* Active task from TASK_STOPPED state */
659+
if (tcb->state == TASK_STOPPED)
660+
sched_enqueue_task(tcb);
635661
return tcb->id;
636662
}
637663

0 commit comments

Comments
 (0)