summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/include/comus/procs.h12
-rw-r--r--kernel/procs.c67
-rw-r--r--kernel/syscall.c35
3 files changed, 62 insertions, 52 deletions
diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h
index cf3f90d..7b1a70a 100644
--- a/kernel/include/comus/procs.h
+++ b/kernel/include/comus/procs.h
@@ -12,6 +12,7 @@
#include <comus/cpu.h>
#include <comus/limits.h>
#include <comus/memory.h>
+#include <comus/syscalls.h>
#include <lib.h>
#include <elf.h>
@@ -34,11 +35,8 @@ enum proc_state {
PROC_STATE_READY,
PROC_STATE_RUNNING,
// runnable, but waiting for some event
- PROC_STATE_SLEEPING,
PROC_STATE_BLOCKED,
- PROC_STATE_WAITING,
// no longer runnalbe
- PROC_STATE_KILLED,
PROC_STATE_ZOMBIE,
// sentinel
N_PROC_STATES,
@@ -70,6 +68,7 @@ struct pcb {
struct pcb *next; // next PDB in queue
// process state information
+ uint64_t syscall;
uint64_t wakeup;
uint8_t exit_status;
};
@@ -89,10 +88,9 @@ typedef struct pcb_queue_s *pcb_queue_t;
/// public facing pcb queues
extern pcb_queue_t pcb_freelist;
-extern pcb_queue_t ready;
-extern pcb_queue_t waiting;
-extern pcb_queue_t sleeping;
-extern pcb_queue_t zombie;
+extern pcb_queue_t ready_queue;
+extern pcb_queue_t zombie_queue;
+extern pcb_queue_t syscall_queue[N_SYSCALLS];
/// pointer to the currently-running process
extern struct pcb *current_pcb;
diff --git a/kernel/procs.c b/kernel/procs.c
index 1668bef..9bf7508 100644
--- a/kernel/procs.c
+++ b/kernel/procs.c
@@ -1,4 +1,5 @@
#include <comus/drivers/pit.h>
+#include <comus/syscalls.h>
#include <comus/memory.h>
#include <comus/procs.h>
#include <comus/error.h>
@@ -14,18 +15,16 @@ struct pcb_queue_s {
};
// collection of queues
-static struct pcb_queue_s pcb_freelist_queue;
-static struct pcb_queue_s ready_queue;
-static struct pcb_queue_s waiting_queue;
-static struct pcb_queue_s sleeping_queue;
-static struct pcb_queue_s zombie_queue;
+static struct pcb_queue_s _pcb_freelist;
+static struct pcb_queue_s _ready_queue;
+static struct pcb_queue_s _zombie_queue;
+static struct pcb_queue_s _syscall_queue[N_SYSCALLS];
// public facing queue handels
pcb_queue_t pcb_freelist;
-pcb_queue_t ready;
-pcb_queue_t waiting;
-pcb_queue_t sleeping;
-pcb_queue_t zombie;
+pcb_queue_t ready_queue;
+pcb_queue_t zombie_queue;
+pcb_queue_t syscall_queue[N_SYSCALLS];
/// pointer to the currently-running process
struct pcb *current_pcb = NULL;
@@ -86,7 +85,7 @@ static struct pcb *find_prev_pid(pcb_queue_t queue, struct pcb *pcb)
// a macro to simplify queue setup
#define QINIT(q, s) \
- q = &q##_queue; \
+ q = &_##q; \
if (pcb_queue_reset(q, s) != SUCCESS) { \
panic("pcb_init can't reset " #q); \
}
@@ -98,10 +97,11 @@ void pcb_init(void)
// set up the external links to the queues
QINIT(pcb_freelist, O_PCB_FIFO);
- QINIT(ready, O_PCB_PRIO);
- QINIT(waiting, O_PCB_PID);
- QINIT(sleeping, O_PCB_WAKEUP);
- QINIT(zombie, O_PCB_PID);
+ QINIT(ready_queue, O_PCB_PRIO);
+ QINIT(zombie_queue, O_PCB_PID);
+ for (size_t i = 0; i < N_SYSCALLS; i++) {
+ QINIT(syscall_queue[i], O_PCB_PID);
+ }
// setup pcb linked list (free list)
// this can be done by calling pcb_free :)
@@ -122,6 +122,7 @@ int pcb_alloc(struct pcb **pcb)
return E_NO_PCBS;
tmp->pid = next_pid++;
+ tmp->state = PROC_STATE_NEW;
*pcb = tmp;
return SUCCESS;
}
@@ -180,13 +181,14 @@ void pcb_zombify(struct pcb *victim)
}
// schedule init if zombie child found
- if (zchild != NULL && init_pcb->state == PROC_STATE_WAITING) {
+ if (zchild != NULL && init_pcb->syscall == SYS_waitpid) {
pid_t pid;
int *status;
- assert(pcb_queue_remove(zombie, zchild) == SUCCESS,
+ assert(pcb_queue_remove(zombie_queue, zchild) == SUCCESS,
"pcb_zombify: cannot remove zombie process from queue");
- assert(pcb_queue_remove(waiting, init_pcb) == SUCCESS,
+ assert(pcb_queue_remove(syscall_queue[SYS_waitpid], init_pcb) ==
+ SUCCESS,
"pcb_zombify: cannot remove waiting process from queue");
pid = (pid_t)PCB_ARG1(init_pcb);
@@ -208,7 +210,7 @@ void pcb_zombify(struct pcb *victim)
// if the parent is waiting, wake it up and clean the victim,
// otherwise the victim will become a zombie
- if (parent->state == PROC_STATE_WAITING) {
+ if (parent->syscall == SYS_waitpid) {
pid_t pid;
int *status;
@@ -217,6 +219,11 @@ void pcb_zombify(struct pcb *victim)
if (pid == 0 || pid == victim->pid) {
PCB_RET(parent) = zchild->pid;
+
+ assert(
+ pcb_queue_remove(syscall_queue[SYS_waitpid], parent) == SUCCESS,
+ "pcb_zombify: cannot remove parent process from waitpid queue");
+
if (status != NULL) {
mem_ctx_switch(parent->memctx);
*status = victim->exit_status;
@@ -229,7 +236,7 @@ void pcb_zombify(struct pcb *victim)
}
victim->state = PROC_STATE_ZOMBIE;
- assert(pcb_queue_insert(zombie, victim) == SUCCESS,
+ assert(pcb_queue_insert(zombie_queue, victim) == SUCCESS,
"cannot insert victim process into zombie queue");
}
@@ -456,13 +463,15 @@ struct pcb *pcb_queue_peek(const pcb_queue_t queue)
void schedule(struct pcb *pcb)
{
assert(pcb != NULL, "schedule: pcb is null");
-
- if (pcb->state == PROC_STATE_KILLED)
- panic("attempted to schedule killed process %d", pcb->pid);
+ assert(pcb->state != PROC_STATE_UNUSED,
+ "attempted to schedule invalid process %d", pcb->pid);
+ assert(pcb->state != PROC_STATE_ZOMBIE,
+ "attempted to schedule killed process %d", pcb->pid);
pcb->state = PROC_STATE_READY;
+ pcb->syscall = 0;
- if (pcb_queue_insert(ready, pcb) != SUCCESS)
+ if (pcb_queue_insert(ready_queue, pcb) != SUCCESS)
panic("schedule insert fail");
}
@@ -474,9 +483,10 @@ __attribute__((noreturn)) void dispatch(void)
// wait for a process to schedule
do {
- status = pcb_queue_pop(ready, &current_pcb);
- if (status == SUCCESS)
+ status = pcb_queue_pop(ready_queue, &current_pcb);
+ if (status == SUCCESS) {
break;
+ }
int_wait();
} while (1);
@@ -484,6 +494,7 @@ __attribute__((noreturn)) void dispatch(void)
current_pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(current_pcb->memctx);
current_pcb->state = PROC_STATE_RUNNING;
current_pcb->ticks = 3; // ticks per process
+ current_pcb->syscall = 0;
syscall_return();
}
@@ -498,16 +509,16 @@ void pcb_on_tick(void)
do {
struct pcb *pcb;
- if (pcb_queue_empty(sleeping))
+ if (pcb_queue_empty(syscall_queue[SYS_sleep]))
break;
- pcb = pcb_queue_peek(sleeping);
+ pcb = pcb_queue_peek(syscall_queue[SYS_sleep]);
assert(pcb != NULL, "sleeping queue should not be empty");
if (pcb->wakeup >= ticks)
break;
- if (pcb_queue_remove(sleeping, pcb))
+ if (pcb_queue_remove(syscall_queue[SYS_sleep], pcb))
panic("failed to wake sleeping process: %d", pcb->pid);
schedule(pcb);
diff --git a/kernel/syscall.c b/kernel/syscall.c
index 403b3bd..96d2fcf 100644
--- a/kernel/syscall.c
+++ b/kernel/syscall.c
@@ -7,6 +7,7 @@
#include <comus/memory.h>
#include <comus/procs.h>
#include <comus/time.h>
+#include <comus/error.h>
#include <lib.h>
#include <stddef.h>
@@ -37,8 +38,9 @@ static int sys_waitpid(void)
{
// arguments are read later
// by procs.c
- pcb->state = PROC_STATE_WAITING;
- pcb_queue_insert(waiting, pcb);
+ pcb->state = PROC_STATE_BLOCKED;
+ assert(pcb_queue_insert(syscall_queue[SYS_waitpid], pcb) == SUCCESS,
+ "sys_waitpid: could not add process to waitpid queue");
// call next process
dispatch();
@@ -149,17 +151,22 @@ static int sys_kill(void)
return 1;
switch (victim->state) {
- case PROC_STATE_KILLED:
case PROC_STATE_ZOMBIE:
// you can't kill it if it's already dead
return 0;
case PROC_STATE_READY:
- case PROC_STATE_SLEEPING:
+ // remove from ready queue
+ victim->exit_status = 1;
+ pcb_queue_remove(ready_queue, victim);
+ pcb_zombify(victim);
+ return 0;
+
case PROC_STATE_BLOCKED:
- // here, the process is on a queue somewhere; mark
- // it as "killed", and let the scheduler deal with it
- victim->state = PROC_STATE_KILLED;
+ // remove from syscall queue
+ victim->exit_status = 1;
+ pcb_queue_remove(syscall_queue[victim->syscall], victim);
+ pcb_zombify(victim);
return 0;
case PROC_STATE_RUNNING:
@@ -170,14 +177,6 @@ static int sys_kill(void)
dispatch();
break;
- case PROC_STATE_WAITING:
- // similar to the 'running' state, but we don't need
- // to dispatch a new process
- victim->exit_status = 1;
- pcb_queue_remove(waiting, pcb);
- pcb_zombify(victim);
- break;
-
default:
// cannot kill a previable process
return 1;
@@ -198,11 +197,11 @@ static int sys_sleep(void)
}
pcb->wakeup = ticks + ms;
- if (pcb_queue_insert(sleeping, pcb)) {
+ if (pcb_queue_insert(syscall_queue[SYS_sleep], pcb)) {
WARN("sleep pcb insert failed");
return 1;
}
- pcb->state = PROC_STATE_SLEEPING;
+ pcb->state = PROC_STATE_BLOCKED;
// calling pcb is in sleeping queue,
// we must call a new one
@@ -348,6 +347,7 @@ void syscall_handler(void)
pcb = current_pcb;
num = pcb->regs.rax;
pcb->regs.rax = 0;
+ pcb->syscall = num;
current_pcb = NULL;
// check for invalid syscall
@@ -369,5 +369,6 @@ void syscall_handler(void)
pcb->regs.rax = ret;
// return to current pcb
+ pcb->syscall = 0;
current_pcb = pcb;
}