diff options
| -rw-r--r-- | include/asm/interrupt.h | 6 | ||||
| -rw-r--r-- | include/kernel/sched.h | 4 | ||||
| -rw-r--r-- | kernel/sched.c | 49 | ||||
| -rw-r--r-- | kernel/serial.c | 15 | ||||
| -rw-r--r-- | usrbin/main.c | 9 |
5 files changed, 70 insertions, 13 deletions
diff --git a/include/asm/interrupt.h b/include/asm/interrupt.h index 1187fef..c20751d 100644 --- a/include/asm/interrupt.h +++ b/include/asm/interrupt.h @@ -1,5 +1,11 @@ #include <stdint.h> +#define cli() \ + __asm__ volatile ("cli") + +#define sti() \ + __asm__ volatile ("sti") + #define irq_enable(n) \ __asm__ volatile ( \ "inb $0xA1, %%al\n" \ diff --git a/include/kernel/sched.h b/include/kernel/sched.h index 4d2aca0..5429e8b 100644 --- a/include/kernel/sched.h +++ b/include/kernel/sched.h @@ -62,4 +62,8 @@ extern uint32_t ticks; void sched_init(void); void reschedule(void); +void wake_up(struct task_struct**); +void sleep_on(struct task_struct**); +void interruptible_sleep_on(struct task_struct**); + #endif diff --git a/kernel/sched.c b/kernel/sched.c index c502024..da55fa3 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1,3 +1,4 @@ +#include <asm/interrupt.h> #include <asm/system.h> #include <errno.h> #include <kernel/con.h> @@ -241,8 +242,13 @@ void reschedule(void) { } } - /* if not, then halt the machine */ - __asm__ ("hlt"); + /* if not, then halt the machine (temporarily re-enabling interrupts) */ + __asm__ volatile ( + "pushf\n" + "sti\n" + "hlt\n" + "popf\n" + ); } } @@ -258,6 +264,45 @@ void wake_up(struct task_struct **task) { *task = NULL; } +void sleep_on(struct task_struct **waiting) { + struct task_struct *t; + + if(waiting == NULL) + return; + + t = *waiting; + *waiting = ctask; + ctask->state = TSTATE_UNINTERRUPTIBLE; + reschedule(); + + *waiting = t; + if(t) + t->state = TSTATE_RUNNING; +} + +void interruptible_sleep_on(struct task_struct **waiting) { + struct task_struct *t; + + if(waiting == NULL) + return; + + t = *waiting; + *waiting = ctask; + while(1) { + ctask->state = TSTATE_INTERRUPTIBLE; + reschedule(); + + if(*waiting == NULL || *waiting == ctask) + break; + + (*waiting)->state = TSTATE_RUNNING; + } + + *waiting = NULL; + if(t) + t->state = TSTATE_RUNNING; +} + void sighandler_default(uint32_t sig) { switch(sig) { case SIGKILL: diff --git a/kernel/serial.c b/kernel/serial.c index 911f02c..f5610f5 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -97,18 +97,19 @@ ssize_t rsread(void *buf, size_t len) { return 0; while(n--) { - if(rxread == rxwrite) { - /* put the current task to sleep */ - waiting_task = ctask; - ctask->state = TSTATE_INTERRUPTIBLE; - reschedule(); - } + /* check if the buffer's empty and if so, go to sleep */ + cli(); + if(rxread == rxwrite) + interruptible_sleep_on(&waiting_task); + /* check again to see if anything was read, or we were interrupted */ if(rxread == rxwrite) { - waiting_task = NULL; + sti(); return -EINTR; } + sti(); + *b++ = rxbuf[rxread]; rxread = rxread + 1 % sizeof(rxbuf); } diff --git a/usrbin/main.c b/usrbin/main.c index d1e3adc..a545a11 100644 --- a/usrbin/main.c +++ b/usrbin/main.c @@ -11,19 +11,20 @@ void sighandler(int sig) { void pid1(void) { ssize_t in; - char buf[2] = { 0, 0 }; + char buf[2] = { 0, }; printf("We did it ma!\n"); signal(1, &sighandler); while(1) { in = read(buf, 1); - if(in <= 0) { + if(in < 1) { if(in == -EINTR) { printf("Read call interrupted!\n"); - kill(getpid(), SIGKILL); + /* kill(getpid(), SIGKILL); */ } else { - pause(); + printf("Error reading from serial port!\n"); + kill(getpid(), SIGKILL); } } if(in > 0) |
