Skip to content

Commit

Permalink
feat(ex_13_1): update task create & add os_schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
ludics committed Oct 23, 2023
1 parent d94a8e4 commit 6dda145
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 25 deletions.
2 changes: 1 addition & 1 deletion code/exercises/ex_13_1/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ debug: all
@echo "Press Ctrl-C and then input 'quit' to exit GDB and QEMU"
@echo "-------------------------------------------------------"
@${QEMU} ${QFLAGS} -kernel os.elf -s -S &
@${GDB} os.elf -q -x ../gdbinit
@${GDB} os.elf -q -x ./gdbinit

.PHONY : code
code: all
Expand Down
23 changes: 23 additions & 0 deletions code/exercises/ex_13_1/gdbinit
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
display/z $mscratch
display/z $mepc
display/z $mie
display/z $mstatus
display/z $mcause
display/z $a0
display/z $a1
display/z $pc
display/z $t5
display/z $t6

set disassemble-next-line on

b _start
b sched_init
b os_main
b trap_vector
b trap_handler
b schedule
b switch_to

target remote : 1234
c
11 changes: 11 additions & 0 deletions code/exercises/ex_13_1/kernel.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ extern void trap_init(void);
extern void plic_init(void);
extern void timer_init(void);

void os_schedule(void) {
// 内核调度
while (1) {
uart_puts("os_schedule: Activate next task\n");
int id = r_mhartid();
*(uint32_t*)CLINT_MSIP(id) = 1;
uart_puts("os_schedule: Back to OS\n");
task_delay(10000);
}
}

void start_kernel(void)
{
uart_init();
Expand Down
4 changes: 3 additions & 1 deletion code/exercises/ex_13_1/os.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,11 @@ struct context {
reg_t pc; // offset: 31 *4 = 124
};

extern int task_create(void (*task)(void));
extern int task_create(void (*task)(void* param), void* param, uint8_t priority, uint32_t timeslice);
extern void task_delay(volatile int count);
extern void task_yield();
extern void task_exit();
extern void back_to_os();

/* plic */
extern int plic_claim(void);
Expand Down
7 changes: 7 additions & 0 deletions code/exercises/ex_13_1/riscv.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ static inline void w_mscratch(reg_t x)
asm volatile("csrw mscratch, %0" : : "r" (x));
}

static inline reg_t r_mscratch()
{
reg_t x;
asm volatile("csrr %0, mscratch" : "=r" (x));
return x;
}

/* Machine-mode interrupt vector */
static inline void w_mtvec(reg_t x)
{
Expand Down
110 changes: 95 additions & 15 deletions code/exercises/ex_13_1/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,88 @@ extern void switch_to(struct context *next);
uint8_t __attribute__((aligned(16))) task_stack[MAX_TASKS][STACK_SIZE];
struct context ctx_tasks[MAX_TASKS];

uint8_t __attribute__((aligned(16))) stack_os[STACK_SIZE];
struct context ctx_os;

uint8_t task_priorities[MAX_TASKS];
uint8_t task_status[MAX_TASKS];

#define TASK_EMPTY 0
#define TASK_READY 1
#define TASK_RUNNING 2
#define TASK_BLOCKED 3
#define TASK_EXITED 4

#define task_schedulable(i) (task_status[i] == TASK_READY || task_status[i] == TASK_RUNNING)

uint32_t task_timeslice[MAX_TASKS];

/*
* _top is used to mark the max available position of ctx_tasks
* _current is used to point to the context of current task
*/
static int _top = 0;
static int _current = -1;

extern void os_schedule();

void sched_init()
{
w_mscratch(0);
/* init ctx_os */
ctx_os.sp = (reg_t) &stack_os[STACK_SIZE];
ctx_os.pc = (reg_t) os_schedule;

w_mscratch((reg_t)&ctx_os);

/* enable machine-mode software interrupts. */
w_mie(r_mie() | MIE_MSIE);

// init task status & priority
for (int i = 0; i < MAX_TASKS; i++) {
task_status[i] = TASK_EMPTY;
task_priorities[i] = 0xff;
task_timeslice[i] = 0;
}
}

/*
* implment a simple cycle FIFO schedular
*/
void schedule()
{
if (_top <= 0) {
panic("Num of task should be greater than zero!");
return;
// 先扫描获取最高优先级
int highest_priority = 0xff;
for (int i = 0; i < MAX_TASKS; i++) {
if (task_schedulable(i) && task_priorities[i] < highest_priority) {
highest_priority = task_priorities[i];
}
}

_current = (_current + 1) % _top;
// 扫描获取最高优先级的任务
int next_task_id = -1;
for (int i = 0; i < MAX_TASKS; i++) {
if (task_schedulable(i) && task_priorities[i] == highest_priority) {
if (i > _current) {
next_task_id = i;
break;
}
}
}
// 如果没有找到,从头开始找
if (next_task_id == -1) {
for (int i = 0; i < MAX_TASKS; i++) {
if (task_schedulable(i) && task_priorities[i] == highest_priority) {
next_task_id = i;
break;
}
}
}
if (next_task_id == -1) {
// 没有可调度的任务
printf("no schedulable task!\n");
switch_to(&ctx_os);
}
// 切换到下一个任务
_current = next_task_id;
struct context *next = &(ctx_tasks[_current]);
task_status[_current] = TASK_RUNNING;
switch_to(next);
}

Expand All @@ -50,16 +105,28 @@ void schedule()
* 0: success
* -1: if error occured
*/
int task_create(void (*start_routin)(void))
int task_create(void (*start_routin)(void* param), void* param,
uint8_t priority, uint32_t timeslice)
{
if (_top < MAX_TASKS) {
ctx_tasks[_top].sp = (reg_t) &task_stack[_top][STACK_SIZE];
ctx_tasks[_top].pc = (reg_t) start_routin;
_top++;
return 0;
} else {
int task_id = -1;
for (int i = 0; i < MAX_TASKS; i++) {
if (task_status[i] == TASK_EMPTY || task_status[i] == TASK_EXITED) {
task_id = i;
break;
}
}
if (task_id == -1) {
return -1;
}
task_status[task_id] = TASK_READY;
task_priorities[task_id] = priority;
task_timeslice[task_id] = timeslice;
// init stack
ctx_tasks[task_id].sp = (reg_t) &task_stack[task_id][STACK_SIZE];
ctx_tasks[task_id].pc = (reg_t) start_routin;
// init context
ctx_tasks[task_id].a0 = (reg_t) param;
return 0;
}

/*
Expand All @@ -69,6 +136,19 @@ int task_create(void (*start_routin)(void))
*/
void task_yield()
{
task_status[_current] = TASK_READY;
/* trigger a machine-level software interrupt */
int id = r_mhartid();
*(uint32_t*)CLINT_MSIP(id) = 1;
}

/*
* DESCRIPTION
* task_exit() causes the calling task to exit.
*/
void task_exit()
{
task_status[_current] = TASK_EXITED;
/* trigger a machine-level software interrupt */
int id = r_mhartid();
*(uint32_t*)CLINT_MSIP(id) = 1;
Expand Down
5 changes: 3 additions & 2 deletions code/exercises/ex_13_1/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ extern void schedule(void);

/* interval ~= 1s */
#define TIMER_INTERVAL CLINT_TIMEBASE_FREQ
#define TIMER_INTERVAL_MS (TIMER_INTERVAL / 1000)

static uint32_t _tick = 0;

Expand All @@ -22,7 +23,7 @@ void timer_init()
* On reset, mtime is cleared to zero, but the mtimecmp registers
* are not reset. So we have to init the mtimecmp manually.
*/
timer_load(TIMER_INTERVAL);
timer_load(TIMER_INTERVAL_MS * 500);

/* enable machine-mode timer interrupts. */
w_mie(r_mie() | MIE_MTIE);
Expand All @@ -33,7 +34,7 @@ void timer_handler()
_tick++;
printf("tick: %d\n", _tick);

timer_load(TIMER_INTERVAL);
timer_load(TIMER_INTERVAL_MS * 1000);

schedule();
}
4 changes: 2 additions & 2 deletions code/exercises/ex_13_1/trap.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ reg_t trap_handler(reg_t epc, reg_t cause)
uart_puts("software interruption!\n");
/*
* acknowledge the software interrupt by clearing
* the MSIP bit in mip.
* the MSIP bit in mip.
*/
int id = r_mhartid();
*(uint32_t*)CLINT_MSIP(id) = 0;
*(uint32_t*)CLINT_MSIP(id) = 0;

schedule();

Expand Down
32 changes: 28 additions & 4 deletions code/exercises/ex_13_1/user.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#define DELAY 1000

void user_task0(void)
void user_task0(void* param)
{
uart_puts("Task 0: Created!\n");

Expand All @@ -14,7 +14,7 @@ void user_task0(void)
}
}

void user_task1(void)
void user_task1(void* param)
{
uart_puts("Task 1: Created!\n");
while (1) {
Expand All @@ -23,10 +23,34 @@ void user_task1(void)
}
}

void user_task(void* param)
{
int id = (int) param;
printf("Task %d: Created!\n", id);
int iter_cnt = id / 1000 + 5;
while (1) {
printf("Task %d: Running...\n", id);
task_delay(DELAY);
if (iter_cnt-- == 0) {
break;
}
}
printf("Task %d: Finished!\n", id);
task_exit();
}

/* NOTICE: DON'T LOOP INFINITELY IN main() */
void os_main(void)
{
task_create(user_task0);
task_create(user_task1);
// task_create(user_task0, NULL, 255, 0);
// task_create(user_task1, NULL, 255, 0);
task_create(user_task, (void *)3000, 0, 0);
task_create(user_task, (void *)8003, 3, 0);
task_create(user_task, (void *)2005, 5, 0);
task_create(user_task, (void *)5000, 0, 0);
task_create(user_task, (void *)9004, 4, 0);
task_create(user_task, (void *)6001, 1, 0);
task_create(user_task, (void *)7002, 2, 0);
task_create(user_task, (void *)4000, 0, 0);
}

0 comments on commit 6dda145

Please sign in to comment.