From 620a2ee90a60979955c318cc1b37741184137bd6 Mon Sep 17 00:00:00 2001 From: Minep Date: Tue, 21 Jun 2022 12:23:54 +0100 Subject: [PATCH] feat: support for SIGALRM feat: alarm(2) syscall refactor: better sleep(3). chore: rename the process state for compactness. --- lunaix-os/includes/lunaix/ds/llist.h | 2 +- lunaix-os/includes/lunaix/lunistd.h | 2 + lunaix-os/includes/lunaix/process.h | 24 ++++--- lunaix-os/includes/lunaix/syscall.h | 1 + lunaix-os/kernel/asm/x86/pfault.c | 2 +- lunaix-os/kernel/asm/x86/syscall.S | 1 + lunaix-os/kernel/k_init.c | 2 +- lunaix-os/kernel/lxinit.c | 10 +++ lunaix-os/kernel/sched.c | 104 ++++++++++++++++++--------- lunaix-os/kernel/signal.c | 3 +- 10 files changed, 105 insertions(+), 46 deletions(-) diff --git a/lunaix-os/includes/lunaix/ds/llist.h b/lunaix-os/includes/lunaix/ds/llist.h index 1a6ec9b..5afc36a 100644 --- a/lunaix-os/includes/lunaix/ds/llist.h +++ b/lunaix-os/includes/lunaix/ds/llist.h @@ -64,7 +64,7 @@ llist_delete(struct llist_header* elem) static inline int llist_empty(struct llist_header* elem) { - return elem->next == elem; + return elem->next == elem && elem->prev == elem; } /** diff --git a/lunaix-os/includes/lunaix/lunistd.h b/lunaix-os/includes/lunaix/lunistd.h index 67f3174..c16f2b0 100644 --- a/lunaix-os/includes/lunaix/lunistd.h +++ b/lunaix-os/includes/lunaix/lunistd.h @@ -22,4 +22,6 @@ __LXSYSCALL(int, pause) __LXSYSCALL2(int, kill, pid_t, pid, int, signum) +__LXSYSCALL1(unsigned int, alarm, unsigned int, seconds) + #endif /* __LUNAIX_UNISTD_H */ diff --git a/lunaix-os/includes/lunaix/process.h b/lunaix-os/includes/lunaix/process.h index 589bfaa..d35bfe7 100644 --- a/lunaix-os/includes/lunaix/process.h +++ b/lunaix-os/includes/lunaix/process.h @@ -12,17 +12,16 @@ // 虽然内核不是进程,但为了区分,这里使用Pid=-1来指代内核。这主要是方便物理页所有权检查。 #define KERNEL_PID -1 -#define PROC_STOPPED 0 -#define PROC_RUNNING 1 -#define PROC_TERMNAT 2 -#define PROC_DESTROY 4 -#define PROC_BLOCKED 8 -#define PROC_CREATED 16 +#define PS_STOPPED 0 +#define PS_RUNNING 1 +#define PS_TERMNAT 2 +#define PS_DESTROY 4 +#define PS_BLOCKED 8 +#define PS_CREATED 16 -#define PROC_TERMMASK 0x6 +#define PROC_TERMINATED(state) (state & 0x6) #define PROC_FINPAUSE 1 -#define PROC_FALRMSET (1 << 1) struct proc_mm { @@ -60,6 +59,14 @@ struct proc_info struct llist_header siblings; struct llist_header children; struct llist_header grp_member; + + struct + { + struct llist_header sleepers; + time_t wakeup_time; + time_t alarm_time; + } sleep; + struct proc_mm mm; time_t created; uint8_t state; @@ -71,7 +78,6 @@ struct proc_info int flags; void* sig_handler[_SIG_NUM]; pid_t pgid; - struct lx_timer* timer; }; extern volatile struct proc_info* __current; diff --git a/lunaix-os/includes/lunaix/syscall.h b/lunaix-os/includes/lunaix/syscall.h index e1d3403..b7b0d57 100644 --- a/lunaix-os/includes/lunaix/syscall.h +++ b/lunaix-os/includes/lunaix/syscall.h @@ -18,6 +18,7 @@ #define __SYSCALL_signal 13 #define __SYSCALL_pause 14 #define __SYSCALL_kill 15 +#define __SYSCALL_alarm 16 #define __SYSCALL_MAX 0x100 diff --git a/lunaix-os/kernel/asm/x86/pfault.c b/lunaix-os/kernel/asm/x86/pfault.c index 9e12444..fcf3739 100644 --- a/lunaix-os/kernel/asm/x86/pfault.c +++ b/lunaix-os/kernel/asm/x86/pfault.c @@ -93,7 +93,7 @@ segv_term: ptr, param->cs, param->eip); - signal_send(__current->pid, _SIGSEGV); + __SIGSET(__current->sig_pending, _SIGSEGV); schedule(); // should not reach while (1) diff --git a/lunaix-os/kernel/asm/x86/syscall.S b/lunaix-os/kernel/asm/x86/syscall.S index b323640..d69dd74 100644 --- a/lunaix-os/kernel/asm/x86/syscall.S +++ b/lunaix-os/kernel/asm/x86/syscall.S @@ -23,6 +23,7 @@ .long __lxsys_signal .long __lxsys_pause .long __lxsys_kill /* 15 */ + .long __lxsys_alarm 2: .rept __SYSCALL_MAX - (2b - 1b)/4 .long 0 diff --git a/lunaix-os/kernel/k_init.c b/lunaix-os/kernel/k_init.c index 447bff7..c173ad9 100644 --- a/lunaix-os/kernel/k_init.c +++ b/lunaix-os/kernel/k_init.c @@ -162,7 +162,7 @@ spawn_proc0() commit_process(proc0); // 由于时钟中断与APIC未就绪,我们需要手动进行第一次调度。这里也会同时隐式地恢复我们的eflags.IF位 - proc0->state = PROC_RUNNING; + proc0->state = PS_RUNNING; asm volatile("pushl %0\n" "jmp switch_to\n" ::"r"(proc0)); diff --git a/lunaix-os/kernel/lxinit.c b/lunaix-os/kernel/lxinit.c index fa5ce38..91a4e50 100644 --- a/lunaix-os/kernel/lxinit.c +++ b/lunaix-os/kernel/lxinit.c @@ -33,6 +33,13 @@ sigsegv_handler(int signum) _exit(signum); } +void __USER__ +sigalrm_handler(int signum) +{ + pid_t pid = getpid(); + kprintf(KWARN "I, pid %d, have received an alarm!\n", pid); +} + void __USER__ _lxinit_main() { @@ -48,6 +55,9 @@ _lxinit_main() signal(_SIGCHLD, sigchild_handler); signal(_SIGSEGV, sigsegv_handler); + signal(_SIGALRM, sigalrm_handler); + + alarm(5); int status; #ifdef WAIT_DEMO diff --git a/lunaix-os/kernel/sched.c b/lunaix-os/kernel/sched.c index f2ce4a2..12deb17 100644 --- a/lunaix-os/kernel/sched.c +++ b/lunaix-os/kernel/sched.c @@ -44,7 +44,7 @@ sched_init() void run(struct proc_info* proc) { - proc->state = PROC_RUNNING; + proc->state = PS_RUNNING; /* 将tss.esp0设置为上次调度前的esp值。 @@ -65,11 +65,7 @@ run(struct proc_info* proc) int can_schedule(struct proc_info* proc) { - if (__SIGTEST(proc->sig_pending, _SIGKILL)) { - // 如果进程受到SIGKILL,则直接终止,该进程不给予调度。 - terminate_proc(PEXITNUM(PEXITSIG, _SIGKILL)); - return 0; - } else if (__SIGTEST(proc->sig_pending, _SIGCONT)) { + if (__SIGTEST(proc->sig_pending, _SIGCONT)) { __SIGCLEAR(proc->sig_pending, _SIGSTOP); } else if (__SIGTEST(proc->sig_pending, _SIGSTOP)) { // 如果进程受到SIGSTOP,则该进程不给予调度。 @@ -79,6 +75,38 @@ can_schedule(struct proc_info* proc) return 1; } +void +check_sleepers() +{ + struct proc_info* leader = &sched_ctx._procs[0]; + struct proc_info *pos, *n; + time_t now = clock_systime(); + llist_for_each(pos, n, &leader->sleep.sleepers, sleep.sleepers) + { + if (PROC_TERMINATED(pos->state)) { + goto del; + } + + time_t wtime = pos->sleep.wakeup_time; + time_t atime = pos->sleep.alarm_time; + + if (wtime && now >= wtime) { + pos->sleep.wakeup_time = 0; + pos->state = PS_STOPPED; + } + + if (atime && now >= atime) { + pos->sleep.alarm_time = 0; + __SIGSET(pos->sig_pending, _SIGALRM); + } + + if (!wtime && !atime) { + del: + llist_delete(&pos->sleep.sleepers); + } + } +} + void schedule() { @@ -92,16 +120,18 @@ schedule() int prev_ptr = sched_ctx.procs_index; int ptr = prev_ptr; - if (!(__current->state & ~PROC_RUNNING)) { - __current->state = PROC_STOPPED; + if (!(__current->state & ~PS_RUNNING)) { + __current->state = PS_STOPPED; } + check_sleepers(); + // round-robin scheduler redo: do { ptr = (ptr + 1) % sched_ctx.ptable_len; next = &sched_ctx._procs[ptr]; - } while (next->state != PROC_STOPPED && ptr != prev_ptr); + } while (next->state != PS_STOPPED && ptr != prev_ptr); sched_ctx.procs_index = ptr; @@ -113,32 +143,40 @@ redo: run(next); } -static void -proc_timer_callback(struct proc_info* proc) -{ - proc->timer = NULL; - proc->state = PROC_STOPPED; -} - __DEFINE_LXSYSCALL1(unsigned int, sleep, unsigned int, seconds) { - // FIXME: sleep的实现或许需要改一下。专门绑一个计时器好像没有必要…… if (!seconds) { return 0; } - if (__current->timer) { - return __current->timer->counter / timer_context()->running_frequency; + if (__current->sleep.wakeup_time) { + return (__current->sleep.wakeup_time - clock_systime()) / 1000U; } - struct lx_timer* timer = - timer_run_second(seconds, proc_timer_callback, __current, 0); - __current->timer = timer; + __current->sleep.wakeup_time = clock_systime() + seconds * 1000; + llist_append(&sched_ctx._procs[0].sleep.sleepers, + &__current->sleep.sleepers); + __current->intr_ctx.registers.eax = seconds; - __current->state = PROC_BLOCKED; + __current->state = PS_BLOCKED; schedule(); } +__DEFINE_LXSYSCALL1(unsigned int, alarm, unsigned int, seconds) +{ + time_t prev_ddl = __current->sleep.alarm_time; + time_t now = clock_systime(); + + __current->sleep.alarm_time = seconds ? now + seconds * 1000 : 0; + + if (llist_empty(&__current->sleep.sleepers)) { + llist_append(&sched_ctx._procs[0].sleep.sleepers, + &__current->sleep.sleepers); + } + + return prev_ddl ? (prev_ddl - now) / 1000 : 0; +} + __DEFINE_LXSYSCALL1(void, exit, int, status) { terminate_proc(status); @@ -179,11 +217,11 @@ repeat: llist_for_each(proc, n, &__current->children, siblings) { if (!~wpid || proc->pid == wpid || proc->pgid == -wpid) { - if (proc->state == PROC_TERMNAT && !options) { + if (proc->state == PS_TERMNAT && !options) { status_flags |= PEXITTERM; goto done; } - if (proc->state == PROC_STOPPED && (options & WUNTRACED)) { + if (proc->state == PS_STOPPED && (options & WUNTRACED)) { status_flags |= PEXITSTOP; goto done; } @@ -207,8 +245,7 @@ struct proc_info* alloc_process() { pid_t i = 0; - for (; - i < sched_ctx.ptable_len && sched_ctx._procs[i].state != PROC_DESTROY; + for (; i < sched_ctx.ptable_len && sched_ctx._procs[i].state != PS_DESTROY; i++) ; @@ -223,7 +260,7 @@ alloc_process() struct proc_info* proc = &sched_ctx._procs[i]; memset(proc, 0, sizeof(*proc)); - proc->state = PROC_CREATED; + proc->state = PS_CREATED; proc->pid = i; proc->created = clock_systime(); proc->pgid = proc->pid; @@ -231,6 +268,7 @@ alloc_process() llist_init_head(&proc->mm.regions); llist_init_head(&proc->children); llist_init_head(&proc->grp_member); + llist_init_head(&proc->sleep.sleepers); return proc; } @@ -240,7 +278,7 @@ commit_process(struct proc_info* process) { assert(process == &sched_ctx._procs[process->pid]); - if (process->state != PROC_CREATED) { + if (process->state != PS_CREATED) { __current->k_status = LXINVL; return; } @@ -252,7 +290,7 @@ commit_process(struct proc_info* process) llist_append(&process->parent->children, &process->siblings); - process->state = PROC_STOPPED; + process->state = PS_STOPPED; } // from @@ -268,7 +306,7 @@ destroy_process(pid_t pid) return; } struct proc_info* proc = &sched_ctx._procs[index]; - proc->state = PROC_DESTROY; + proc->state = PS_DESTROY; llist_delete(&proc->siblings); struct mm_region *pos, *n; @@ -289,7 +327,7 @@ destroy_process(pid_t pid) void terminate_proc(int exit_code) { - __current->state = PROC_TERMNAT; + __current->state = PS_TERMNAT; __current->exit_code = exit_code; __SIGSET(__current->parent->sig_pending, _SIGCHLD); @@ -317,5 +355,5 @@ orphaned_proc(pid_t pid) // 如果其父进程的状态是terminated 或 destroy中的一种 // 或者其父进程是在该进程之后创建的,那么该进程为孤儿进程 - return (parent->state & PROC_TERMMASK) || parent->created > proc->created; + return PROC_TERMINATED(parent->state) || parent->created > proc->created; } \ No newline at end of file diff --git a/lunaix-os/kernel/signal.c b/lunaix-os/kernel/signal.c index c3a6c07..19deff2 100644 --- a/lunaix-os/kernel/signal.c +++ b/lunaix-os/kernel/signal.c @@ -19,6 +19,7 @@ void* default_handlers[_SIG_NUM] = { // TODO: 添加默认handler [_SIGINT] = default_sighandler_term, [_SIGTERM] = default_sighandler_term, + [_SIGKILL] = default_sighandler_term, }; // Referenced in kernel/asm/x86/interrupt.S @@ -105,7 +106,7 @@ send_grp: return 0; send_single: - if ((proc->state & PROC_TERMMASK)) { + if (PROC_TERMINATED(proc->state)) { __current->k_status = LXINVL; return -1; } -- 2.27.0