diff options
| author | Jake Mannens <jake72360@gmail.com> | 2018-07-30 02:09:12 +1000 |
|---|---|---|
| committer | Jake Mannens <jake72360@gmail.com> | 2018-07-30 02:09:12 +1000 |
| commit | 902abebefe10e5e8bc9d80b73e46bcb1635f0be8 (patch) | |
| tree | 303aaed0f6f274e37ee069c120e5e6bec3b5c9c9 | |
| parent | 4a91e12af177dc50a2427d335fd522658d821194 (diff) | |
Fixed a bug where the tick_handler() and sigret() functions did not pass
a pointer to the saved state information to check_signals(). This bug
would have only manifested itself if multiple signals were to be
processed (sigret) or if a signal had been set during the handling of a
timer interrupt (tick_handler) and *ONLY* if switching to the user's own
handler since the state information is not needed to invoke the kernel's
default signal handler.
Implemented alarms for userspace processes. This required significant
modification of the scheduler algorithm. When idling waiting for a
process that can run, the scheduler now continually checks the alarms
and signals of each process and updates their state accordingly.
Implemented the sys_alarm system call to set the new 'alarm' field for
the calling process.
Created the sys_pause system call which changes the state of the calling
process to TSTATE_INTERRUPTIBLE, effectively removing it from the
scheduler's run queue, putting it to sleep until a signal arrives.
| -rw-r--r-- | include/kernel/sched.h | 2 | ||||
| -rw-r--r-- | include/kernel/sys.h | 6 | ||||
| -rw-r--r-- | include/time.h | 2 | ||||
| -rw-r--r-- | include/unistd.h | 4 | ||||
| -rw-r--r-- | kernel/sched.c | 23 | ||||
| -rw-r--r-- | kernel/sys.c | 16 | ||||
| -rw-r--r-- | kernel/timer.s | 4 | ||||
| -rw-r--r-- | kernel/traps.s | 8 | ||||
| -rw-r--r-- | lib/pause.c | 3 | ||||
| -rw-r--r-- | lib/time.c | 2 | ||||
| -rw-r--r-- | usrbin/main.c | 28 |
11 files changed, 85 insertions, 13 deletions
diff --git a/include/kernel/sched.h b/include/kernel/sched.h index 3d6699c..6b0488e 100644 --- a/include/kernel/sched.h +++ b/include/kernel/sched.h @@ -50,6 +50,7 @@ struct task_struct { pid_t pid; int state; uint32_t signal; + unsigned int alarm; void *sig_handlers[NRSIG]; struct tss_struct tss; } __attribute__((packed)); @@ -58,5 +59,6 @@ extern struct task_struct *ctask; extern uint32_t ticks; void sched_init(void); +void reschedule(void); #endif diff --git a/include/kernel/sys.h b/include/kernel/sys.h index 2ec4490..ba2dc0c 100644 --- a/include/kernel/sys.h +++ b/include/kernel/sys.h @@ -6,6 +6,8 @@ extern int sys_getpid(void); extern int sys_getpdir(void); extern int sys_signal(void); extern int sys_rsputs(void); +extern int sys_alarm(void); +extern int sys_pause(void); extern int sys_dummy(void); syscall_t call_table[256] = { @@ -15,8 +17,8 @@ syscall_t call_table[256] = { [3] = &sys_getpdir, [4] = &sys_signal, [5] = &sys_rsputs, - [6] = &sys_dummy, - [7] = &sys_dummy, + [6] = &sys_alarm, + [7] = &sys_pause, [8] = &sys_dummy, [9] = &sys_dummy, [10] = &sys_dummy, diff --git a/include/time.h b/include/time.h index 732d33f..feb2225 100644 --- a/include/time.h +++ b/include/time.h @@ -10,6 +10,8 @@ typedef int32_t time_t; time_t time(void); +int alarm(unsigned int seconds); + void sleep(time_t); #endif diff --git a/include/unistd.h b/include/unistd.h index a784e22..30d41c6 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -11,6 +11,8 @@ typedef uint16_t pid_t; #define __SYS_getpdir 3 #define __SYS_signal 4 #define __SYS_rsputs 5 +#define __SYS_alarm 6 +#define __SYS_pause 7 #define _syscall0(type, name) \ type name(void) { \ @@ -37,4 +39,6 @@ typedef uint16_t pid_t; pid_t getpid(void); void *getpdir(void); +int pause(void); + #endif diff --git a/kernel/sched.c b/kernel/sched.c index 529db61..9f955d2 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -199,12 +199,25 @@ void reschedule(void) { n = ctaskn; while(1) { - n = (n + 1) % NRTASKS; - if(tasks[n].pid && tasks[n].state == TSTATE_RUNNING) - break; - } + /* check alarms and signals */ + for(i = 0; i < NRTASKS; i++) { + if(tasks[i].alarm && tasks[i].alarm < ticks) { + tasks[i].alarm = 0; + tasks[i].signal |= 1 << (SIGALRM - 1); + } + if(tasks[i].signal && tasks[i].state == TSTATE_INTERRUPTIBLE) + tasks[i].state = TSTATE_RUNNING; + } - switch_to(n, &tasks[n]); + /* check if a process is ready to run */ + for(i = 0; i < NRTASKS; i++) { + n = (n + 1) % NRTASKS; + if(tasks[n].pid && tasks[n].state == TSTATE_RUNNING) { + switch_to(n, &tasks[n]); + return; + } + } + } } void sched_tick(void) { diff --git a/kernel/sys.c b/kernel/sys.c index 20494de..c2256c1 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -36,12 +36,26 @@ void *sys_signal(int sig, void (*func)(int)) { if(sig == SIGKILL || sig == SIGSTOP) return NULL; - printk("Task %x registered new signal handler 0x%08x for signal %01x\n", ctask->pid, (uint32_t) func, sig); ctask->sig_handlers[sig] = func; return func; } +int sys_alarm(unsigned int seconds) { + if(!seconds) { + ctask->alarm = 0; + return 0; + } + + ctask->alarm = ticks + (seconds * 100); +} + +int sys_pause(void) { + ctask->state = TSTATE_INTERRUPTIBLE; + reschedule(); + return -1; +} + int sys_dummy(void) { return -ENOSYS; } diff --git a/kernel/timer.s b/kernel/timer.s index b96e1f1..6d95281 100644 --- a/kernel/timer.s +++ b/kernel/timer.s @@ -19,6 +19,8 @@ tick_handler: mov es, ax mov fs, ax mov gs, ax + ; save a pointer to the state information + mov ebx, esp ; handle the timer tick mov dword [ticked], 1 inc dword [ticks] @@ -31,7 +33,9 @@ tick_handler: ; if it isn't, call the scheduler call sched_tick ; handle any pending signals before returning to normal execution + push ebx call check_signals + add esp, 4 .end: ; restore the data segment selectors pop ax diff --git a/kernel/traps.s b/kernel/traps.s index 36b3423..0a0d202 100644 --- a/kernel/traps.s +++ b/kernel/traps.s @@ -21,8 +21,8 @@ extern ticked ; too. %define ts_signal 6 -%define ts_sig_handlers 10 -%define ts_tss_esp0 142 +%define ts_sig_handlers 14 +%define ts_tss_esp0 146 %macro SAVE 0 pusha @@ -323,6 +323,7 @@ check_signals: shl ebx, cl xor ebx, 0xFFFFFFFF and dword [eax+ts_signal], ebx + inc ecx mov ebx, ecx ; calculate offset to the handler function shl ecx, 2 @@ -374,7 +375,10 @@ check_signals: ret sigret: + mov ebx, esp + push ebx call check_signals + add esp, 4 ; restore our original stack frame and reset the TSS's ESP0 mov esp, [eax+ts_tss_esp0] mov dword [eax+ts_tss_esp0], 0xFFFFFFFF diff --git a/lib/pause.c b/lib/pause.c new file mode 100644 index 0000000..1e316df --- /dev/null +++ b/lib/pause.c @@ -0,0 +1,3 @@ +#include <unistd.h> + +_syscall0(int, pause); @@ -3,6 +3,8 @@ _syscall0(time_t, time); +_syscall1(int, alarm, unsigned int, seconds); + void sleep(time_t t) { time_t start = time(); diff --git a/usrbin/main.c b/usrbin/main.c index 2afcf0e..8c8d2dc 100644 --- a/usrbin/main.c +++ b/usrbin/main.c @@ -1,15 +1,37 @@ +#include <signal.h> #include <stdint.h> #include <stdio.h> #include <time.h> #include <unistd.h> -void main(void) { - int x = 0; +void sighandler(int sig) { + printf("Caught SIGALRM!\n"); +} - printf("We did it ma!\n"); +void pid1(void) { + signal(SIGALRM, &sighandler); + alarm(2); + pause(); + printf("Alarm expired!\n"); + pause(); + + while(1) + printf("It's didn't work!\n"); +} + +void pid2(void) { + int x = 0; while(1) { sleep(1); printf("0x%04x:0x%08x: 0x%08x, 0x%08x\n", getpid(), (uint32_t) getpdir(), time(), x++); } } + +void main(void) { + printf("We did it ma!\n"); + + if(getpid() == 1) + pid1(); + pid2(); +} |
