From f89aa9dc4e49149eb98998169cdc559306c37286 Mon Sep 17 00:00:00 2001 From: fef Date: Wed, 4 Aug 2021 03:25:04 +0200 Subject: [PATCH] sched: add idle task --- arch/at91sam3x8e/sched.c | 29 ++++++++++++++++++-- arch/at91sam3x8e/serial.c | 12 ++++++++ include/arch-generic/sched.h | 6 ++-- kernel/sched.c | 53 +++++++++++++++++++++--------------- 4 files changed, 74 insertions(+), 26 deletions(-) diff --git a/arch/at91sam3x8e/sched.c b/arch/at91sam3x8e/sched.c index 757b308..005d79b 100644 --- a/arch/at91sam3x8e/sched.c +++ b/arch/at91sam3x8e/sched.c @@ -5,15 +5,17 @@ #include #include +#include #include +#include #include void handle_sys_tick(void) { /* * fire a PendSV exception and do the actual context switching there - * because it is faster that way (according to the docs, at least) + * because the docs say you're supposed to do it that way */ if (!is_atomic_context()) arch_irq_invoke(IRQNO_PEND_SV); @@ -55,7 +57,7 @@ int arch_sched_hwtimer_init(unsigned int freq) return 0; } -void arch_sched_task_init(struct task *task, void (*entry)(void)) +void arch_task_init(struct task *task, void (*entry)(void)) { struct reg_snapshot *regs = task->stack_bottom - sizeof(*regs); task->sp = regs; @@ -73,6 +75,29 @@ void yield(enum task_state state) arch_irq_invoke(IRQNO_PEND_SV); } +__naked __noreturn static void idle_task_entry(void) +{ + __asm__ volatile( +"1: b 1b \n" + ::: + ); +} + +int arch_idle_task_init(struct task *task) +{ + void *sp = malloc(sizeof(struct reg_snapshot)); + if (sp == NULL) + return -ENOMEM; + + task->stack_bottom = sp + sizeof(struct reg_snapshot); + arch_task_init(task, idle_task_entry); + task->lastexec = 0; + task->sleep_usecs = 0; + task->state = TASK_READY; + task->pid = -1; + return 0; +} + /* * This file is part of Ardix. * Copyright (c) 2020, 2021 Felix Kopp . diff --git a/arch/at91sam3x8e/serial.c b/arch/at91sam3x8e/serial.c index f3c7e2f..aa3f0a6 100644 --- a/arch/at91sam3x8e/serial.c +++ b/arch/at91sam3x8e/serial.c @@ -133,6 +133,12 @@ void irq_uart(void) if (state & REG_UART_SR_RXRDY_MASK) { tmp = REG_UART_RHR; ringbuf_write(arch_serial_default_device.device.rx, &tmp, sizeof(tmp)); + + /* TODO: we need some error handling mechanism for event creation */ + struct device_kevent *event = device_kevent_create(&serial_default_device->device, + DEVICE_CHANNEL_IN); + if (event != NULL) + kevent_dispatch(&event->event); } /* REG_UART_PDC_TCR has reached zero */ @@ -146,6 +152,12 @@ void irq_uart(void) if (arch_serial_default_device.tx_current == NULL) REG_UART_IDR = REG_UART_IDR_ENDTX_MASK; + + /* TODO: we need some error handling mechanism for event creation */ + struct device_kevent *event = device_kevent_create(&serial_default_device->device, + DEVICE_CHANNEL_OUT); + if (event != NULL) + kevent_dispatch(&event->event); } /* check for error conditions */ diff --git a/include/arch-generic/sched.h b/include/arch-generic/sched.h index e4ad01d..ea6985c 100644 --- a/include/arch-generic/sched.h +++ b/include/arch-generic/sched.h @@ -6,7 +6,7 @@ #include -struct process; /* see include/ardix/sched.h */ +struct task; /* see include/ardix/sched.h */ /** * Initialize a hardware timer for schduling. @@ -23,7 +23,9 @@ int arch_sched_hwtimer_init(unsigned int freq); * @param process: The process. * @param entry: The process entry point. */ -void arch_sched_process_init(struct process *process, void (*entry)(void)); +void arch_task_init(struct task *task, void (*entry)(void)); + +int arch_idle_task_init(struct task *task); /* * This file is part of Ardix. diff --git a/kernel/sched.c b/kernel/sched.c index c401e1e..f9a2f18 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -18,6 +18,8 @@ extern uint32_t _estack; static struct task *tasktab[CONFIG_SCHED_MAXTASK]; struct task *current; +static struct task idle_task; + static void task_destroy(struct kent *kent) { struct task *task = container_of(kent, struct task, kent); @@ -36,27 +38,35 @@ int sched_init(void) current->kent.parent = kent_root; current->kent.destroy = task_destroy; i = kent_init(¤t->kent); - if (i == 0) { - current->sp = &_sstack; - current->stack_bottom = &_estack; - current->pid = 0; - current->state = TASK_READY; - tasktab[0] = current; + if (i != 0) + goto out; - for (i = 1; i < CONFIG_SCHED_MAXTASK; i++) - tasktab[i] = NULL; + current->sp = &_sstack; + current->stack_bottom = &_estack; + current->pid = 0; + current->state = TASK_READY; + tasktab[0] = current; - i = arch_watchdog_init(); + for (i = 1; i < CONFIG_SCHED_MAXTASK; i++) + tasktab[i] = NULL; - if (i == 0) - i = arch_sched_hwtimer_init(CONFIG_SCHED_FREQ); - } + i = arch_watchdog_init(); + if (i != 0) + goto out; + + i = arch_sched_hwtimer_init(CONFIG_SCHED_FREQ); + if (i != 0) + goto out; + + i = arch_idle_task_init(&idle_task); + if (i != 0) + goto out; /* * we don't really need to deallocate resources on error because we * are going to panic anyways if the scheduler fails to initialize. */ - +out: return i; } @@ -66,37 +76,36 @@ int sched_init(void) * @param task: the task * @returns whether `task` could be run next */ -static inline bool sched_task_should_run(const struct task *task) +static inline bool can_run(const struct task *task) { enum task_state state = task->state; - - if (state == TASK_QUEUE || state == TASK_READY || state == TASK_IOWAIT) - return true; - - return false; + return state == TASK_QUEUE || state == TASK_READY; } void *sched_process_switch(void *curr_sp) { struct task *tmp; + int i; pid_t nextpid = current->pid; current->sp = curr_sp; if (current->state != TASK_SLEEP && current->state != TASK_IOWAIT) current->state = TASK_QUEUE; - while (1) { + for (i = 0; i < CONFIG_SCHED_MAXTASK; i++) { nextpid++; nextpid %= CONFIG_SCHED_MAXTASK; tmp = tasktab[nextpid]; - if (tmp != NULL && sched_task_should_run(tmp)) { + if (tmp != NULL && can_run(tmp)) { current = tmp; break; } - /* TODO: Add idle thread */ } + if (i == CONFIG_SCHED_MAXTASK) + current = &idle_task; + current->state = TASK_READY; return current->sp; }