Thu, 07 Dec 2023 16:39:54 +0100
8 files changed,
171 insertions(+),
5 deletions(-)
A
kernel/alarm.c
@@ -0,0 +1,65 @@
+#include "memory.h" +#include "alarm.h" +#include "core.h" +#include "sched/sched.h" + +struct alarm *first = NULL; +int alarm_id_next = 1000; + +int alarm_add(int ticks, PROCESS_ID pid, alarm_mode m) { + struct alarm *next = malloc(sizeof(struct alarm)); + + next->alarm_id = alarm_id_next++; + next->ticks_remaining = ticks; + next->pid = pid; + next->m = m; + + // add to list + next->next = first; + first = next; + + return next->alarm_id; +} + +void alarm_tick(void) { + struct alarm **next = &first; + + while (*next) { + if ((*next)->ticks_remaining-- <= 0) { + // send signal to process + switch((*next)->m) { + case ALARM_WAKEUP: + sched_unblock((*next)->pid); + break; + case ALARM_KILL: + sched_kill((*next)->pid); + break; + default: + printk("Unknown alarm mode: %i\n", (int)((*next)->m)); + break; + } + + // remove alarm + *next = (*next)->next; + } else { + next = &((*next)->next); + } + } +} + +int alarm_cancel(int alarm_id) { + struct alarm **next = &first; + + while (*next) { + if ((*next)->alarm_id == alarm_id) { + // remove alarm + *next = (*next)->next; + return 0; + } else { + next = &((*next)->next); + } + } + + // alarm was not found + return -1; +}
A
kernel/alarm.h
@@ -0,0 +1,48 @@
+#ifndef ALARM_H +#define ALARM_H + +#include "sched/process.h" + +typedef enum { + ALARM_UNDEF = 0, + ALARM_WAKEUP = 1, + ALARM_KILL = 2 +} alarm_mode; + +struct alarm { + int alarm_id; + int ticks_remaining; + PROCESS_ID pid; + alarm_mode m; + + struct alarm *next; +}; + +/** + * @brief Decrease all alarm counters and act on finished alarms. + * + * This function is called by sched_interrupt_c. + */ +void alarm_tick(void); + +/** + * @brief Add a new alarm. + * + * @param ticks Number of ticks to count down. + * @param pid Process ID of the process targeted by the alarm. + * @param m Alarm mode. Defines which action to take once the timer has run out. + * + * @return ID of the created alarm. + */ +int alarm_add(int ticks, PROCESS_ID pid, alarm_mode m); + +/** + * @brief Cancel an existing alarm. + * + * @param alarm_id ID of the alarm to be cancelled. + * + * @return 0 on success, -1 if the alarm was not found. + */ +int alarm_cancel(int alarm_id); + +#endif
M
kernel/sched/sched.c
→
kernel/sched/sched.c
@@ -14,6 +14,7 @@ #include "pit.h"
#include "pic.h" #include "elf.h" #include "file.h" +#include "alarm.h" #include "assembly.h" #include "assert.h"@@ -90,7 +91,12 @@ }
// TODO: implement with malloc strcpy(p->name_buf, name); - strcpy(p->args_buf, args); + + if (args == 0) { + p->args_buf[0] = 0; + } else { + strcpy(p->args_buf, args); + } p->name = (const char*)&(p->name_buf); p->args = (const char*)&(p->args_buf);@@ -129,6 +135,8 @@
void sched_interrupt_c(SCHED_FRAME * volatile frame, uint32_t volatile ebp) { PROCESS* current = get_process(current_pid); + alarm_tick(); + if (current_pid != 0) { current->esp = (VIRT_ADDR)(frame); current->ebp = (VIRT_ADDR)(ebp);@@ -214,6 +222,29 @@ INT(0x20);
crit_restore(csc); crit_exit(); +} + +void sched_sleep(int ticks) { + // block the process. unblocking is done by the alarm. + PROCESS *process = get_process(current_pid); + process->state = PSTATE_BLOCKED; + + // create a wakeup-alarm to unblock the process. + alarm_add(ticks, current_pid, ALARM_WAKEUP); + + sched_yield(); + + // if this happens, it means the scheduler chose + // a blocked process as next process, which should + // never happen. + if (process->state == PSTATE_BLOCKED) { + kpanic("ERROR!"); + } +} + +void sched_unblock(int pid) { + PROCESS *process = get_process(pid); + process->state = PSTATE_READY; } int sched_kill(PROCESS_ID pid) {
M
kernel/sched/sched.h
→
kernel/sched/sched.h
@@ -64,6 +64,20 @@ * process for one unit of time.
*/ void sched_yield(void); +/** + * @brief Blocks the current process for the given number of ticks. + * + * @param ticks Number of ticks. + */ +void sched_sleep(int ticks); + +/** + * @brief Unblocks the process given by \p pid immediately. + * + * @param pid ID of the process to be unblocked. + */ +void sched_unblock(int pid); + /*! * Kills the process with the specified ID. * \param pid Process ID of the process to be killed.
M
kernel/syscall.c
→
kernel/syscall.c
@@ -25,7 +25,8 @@ file_lseek,
file_tell, time_get_ticks, mem_usage, - sched_kill + sched_kill, + sched_sleep }; extern void syscall_interrupt(void);
M
libcedos/cedos.c
→
libcedos/cedos.c
@@ -100,3 +100,8 @@ void process_kill(int pid) {
volatile uint32_t res = 0; interrupt(0x30, res, 14, pid, 0, 0); } + +void sleep(int ticks) { + volatile uint32_t res = 0; + interrupt(0x30, res, 15, ticks, 0, 0); +}
M
libcedos/cedos.h
→
libcedos/cedos.h
@@ -7,6 +7,7 @@ #include <stdint.h>
int sysprint(const char *fmt, int arg1, int arg2); int yield(); +void sleep(int ticks); int get_pid(); int process_spawn(const char *fname, const char *args); int process_spawn_pipe(const char *fname, const char *args, int stdin, int stdout);
M
shell/ticks.c
→
shell/ticks.c
@@ -8,7 +8,7 @@
#include "cedos.h" void main(char *args) { - if (strlen(args) == 0) { + if (args == NULL || strlen(args) == 0) { int ticks = sc_time_get_ticks(); printf("%i\n", ticks); } else {@@ -20,6 +20,7 @@ return;
} int pid = get_pid(); + int color = 40 + (pid % 8); int superticks = 0;@@ -27,11 +28,11 @@ while (1) {
int ticks = sc_time_get_ticks(); if (ticks / interval != superticks) { - printf("[%i] %i ticks\n", pid, ticks); + printf("\e[%im\e[0K[%i] %i ticks\e[0m\n", color, pid, ticks); superticks = ticks / interval; } - yield(); + sleep(interval); } } }