summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Mannens <jake72360@gmail.com>2018-08-20 12:44:01 +1000
committerJake Mannens <jake72360@gmail.com>2018-08-20 12:44:01 +1000
commit228de16e2976abb9a15edb41c9b10dbfd309481f (patch)
tree35b7b347d49be2bdb99e534220f3fb152f5c855f
parent55c31434991a9c7cb20f7df06e4039fdd8f7152b (diff)
Defined macros cli() and sti() in asm/interrupt.h to disable and enable
interrupts respectively. Added the scheduling primatives sleep_on() and interruptible_sleep_on() to sched.c. sleep_on() adds the current task to the specified wait queue then puts it into an uninterruptible sleep. Wait queues are formed by having each waiting task holding a pointer to the waiting task that preceeded it, then placing a pointer to it's own task struct into the queue's head pointer. When the first task in the queue is awoken, it wakes the preceeding task prior to returning from sleep_on(). The function interruptible_sleep_on() works in a similar manner, however when a task is awoken from interruptible_sleep_on(), it wakes up the first task in it's wait queue, then puts itself back to sleep. The purpose of this, is to automatically dissolve and reform the wait queue. As each task in the queue is a awakened, tasks that need to handle signals will do so whilst tasks that have no pending signals and are still waiting will place themselves back into the wait queue by calling interruptible_sleep_on() again. Whilst this method isn't the most effiecient due to waking every task in a wait queue because one received a signal, it does avoid the mess and complications involved in maintaining the queue as an array or linked list. Added prototypes for the scheduling primatives wake_up(), sleep_on() and interruptible_sleep_on() to kernel/sched.h so that these functions may be used throughout the kernel. Added code to temporaily re-enable interrupts in reschedule() so that the idle loop may continue to function even if interrupts were disabled prior to calling the function.
-rw-r--r--include/asm/interrupt.h6
-rw-r--r--include/kernel/sched.h4
-rw-r--r--kernel/sched.c49
-rw-r--r--kernel/serial.c15
-rw-r--r--usrbin/main.c9
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)