diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-03-02 23:30:16 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-03-03 00:07:27 +0100 |
commit | bb1a5fc74769301c0a792cb83d3fa0bda8a780cb (patch) | |
tree | 14b406cc83798524e12d24ab211c4580d1c52f1f | |
parent | 0d47724c5f6201fdc7679327ad4a132c708b8042 (diff) | |
download | kogata-bb1a5fc74769301c0a792cb83d3fa0bda8a780cb.tar.gz kogata-bb1a5fc74769301c0a792cb83d3fa0bda8a780cb.zip |
Add prototypes for process management...
-rw-r--r-- | README.md | 13 | ||||
-rw-r--r-- | src/common/include/proc.h | 18 | ||||
-rw-r--r-- | src/common/include/syscallproto.h | 18 | ||||
-rw-r--r-- | src/kernel/include/process.h | 31 | ||||
-rw-r--r-- | src/kernel/include/thread.h | 5 | ||||
-rw-r--r-- | src/kernel/user/process.c | 39 | ||||
-rw-r--r-- | src/kernel/user/syscall.c | 5 | ||||
-rw-r--r-- | src/lib/include/syscall.h | 3 | ||||
-rw-r--r-- | src/lib/libkogata/syscall.c | 7 |
9 files changed, 99 insertions, 40 deletions
@@ -104,8 +104,13 @@ running the tests): ### Plans for soon +* Complete process management (implement process exiting, process deletion, waiting, ...) * Implement missing syscalls -* Write device drivers : VGA, keyboard, ATA, FAT, VESA +* Write device drivers : VGA, keyboard, FAT (or EXT2 ?), VESA +* Work on userland +* Define a format for "packages", ie readonly filesystem images used for adding system + components or apps to the OS ; make sure to implement it in a way that does not waste + memory ### Things to design @@ -121,7 +126,6 @@ running the tests): we can always reload them from the disk. - An on-disk file with a page cache must be aware of all the places where the page is mapped, so that it can unmap it when reclaiming pages. - - Simpler model : cached pages cannot be freed while the file is open with `FM_MMAP` * Reclaiming physical memory : - Freeing some cached stuff, ie swapping pages from mmap regions - Swapping pages from processes non-mmap regions (ie real data regions) @@ -132,6 +136,8 @@ running the tests): have the possibility of crashing the system * How does a process transmit information (such as environment, arguments, file descriptors) to its children ? +* How do we do stream-like IO on files ? (ie how do we implement the append acces mode + and non-position-dependant read/write calls & seek call) ### Things not sure @@ -147,5 +153,6 @@ running the tests): None of the source files have a licence header because it's cumbersome. All the code and associated documentation found in this repository is released under -the ISC licence as detailed in the `COPYING` file. +the ISC licence as detailed in the `COPYING` file. Some parts of the code are very +directly inspired from examples found on the OSDev wiki, thank you all! diff --git a/src/common/include/proc.h b/src/common/include/proc.h new file mode 100644 index 0000000..01a6722 --- /dev/null +++ b/src/common/include/proc.h @@ -0,0 +1,18 @@ +#pragma once + +#include <stddef.h> +#include <stdint.h> + +#define PS_LOADING 1 +#define PS_RUNNING 2 +#define PS_DONE 3 +#define PS_FAILURE 4 // exception or segfault or stuff +#define PS_KILLED 5 + +typedef struct { + int pid; + int state; // one of PS_* + int return_code; // an error code if state == PS_FAILURE +} proc_status_t; + +/* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/common/include/syscallproto.h b/src/common/include/syscallproto.h index 7b85a49..518cdb4 100644 --- a/src/common/include/syscallproto.h +++ b/src/common/include/syscallproto.h @@ -1,5 +1,6 @@ #pragma once +#include <proc.h> #define SC_MAX 128 // maximum number of syscalls @@ -40,8 +41,9 @@ #define SC_PROC_EXEC 55 // args: pid, exec_name, exec_name_strlen -- execute binary in process #define SC_PROC_STATUS 56 // args: pid, proc_status_t* #define SC_PROC_KILL 57 // args: pid, proc_status_t* -- inconditionnally kill child process -#define SC_PROC_WAIT 58 // args: pid, proc_status_t* -#define SC_PROC_WAIT_ANY 59 // args: proc_status_t* +#define SC_PROC_WAIT 58 // args: pid?, block?, proc_status_t* + +#define INVALID_PID 0 // do a wait with this PID to wayt for any child typedef struct { const char* driver; @@ -71,16 +73,4 @@ typedef struct { int bind_to_pid; // used only for SC_BIND_SUBFS } sc_subfs_args_t; -#define PS_LOADING 1 -#define PS_RUNNING 2 -#define PS_DONE 3 -#define PS_FAILURE 4 // exception or segfault or stuff -#define PS_KILLED 5 -typedef struct { - int pid; - int state; // one of PS_* - int return_code; // an error code if state == PS_FAILURE -} proc_status_t; - - /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h index 6e287e1..82f1b4d 100644 --- a/src/kernel/include/process.h +++ b/src/kernel/include/process.h @@ -18,8 +18,10 @@ #include <mmap.h> +#include <proc.h> // common header defining process statuses + #define USERSTACK_ADDR 0xB8000000 -#define USERSTACK_SIZE 0x00020000 // 32 KB +#define USERSTACK_SIZE 0x00020000 // 32 KB - it is allocated on demand so no worries typedef struct process process_t; @@ -46,21 +48,40 @@ typedef struct process { hashtbl_t *files; int next_fd; - thread_t *thread; + thread_t *threads; uint64_t last_ran; int pid; struct process *parent; + struct process *next_child; + struct process *children; } process_t; typedef void* proc_entry_t; +// ---- Process creation, deletion, waiting, etc. +// Simple semantics : when a process exits, all its ressources are freed immediately +// except for the process_t that remains attached to the parent process until it does +// a wait() and acknowleges the process' ending +// When a process exits, all the children are orphaned and nobody can wait on them anymore, +// which is a bad thing : a user process must always wait for all its children ! + process_t *current_process(); process_t *new_process(process_t *parent); -// void delete_process(process_t *p); // TODO define semantics for freeing stuff bool start_process(process_t *p, proc_entry_t entry); // maps a region for user stack +void process_exit(process_t *p, int status, int exit_code); // exit current process + +bool process_new_thread(process_t *p, proc_entry_t entry, void* sp); +void process_thread_exited(thread_t *t); // called by threading code when a thread exits + +process_t *process_find_child(process_t *p, int pid); +void process_get_status(process_t *p, proc_status_t *st); +void process_wait(process_t *p, proc_status_t *st, bool block); // waits for exit and frees process_t structure +void process_wait_any_child(process_t *p, bool block); + +// ---- Process FS namespace & FD set bool proc_add_fs(process_t *p, fs_t *fs, const char* name); fs_t *proc_find_fs(process_t *p, const char* name); @@ -69,12 +90,14 @@ int proc_add_fd(process_t *p, fs_handle_t *f); // on error returns 0, nonzero o fs_handle_t *proc_read_fd(process_t *p, int fd); void proc_close_fd(process_t *p, int fd); +// ---- Process virtual memory space + bool mmap(process_t *proc, void* addr, size_t size, int mode); // create empty zone bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_t size, int mode); bool mchmap(process_t *proc, void* addr, int mode); bool munmap(process_t *proc, void* addr); -// for syscalls : check that process is authorized to do that +// for syscalls : check that process is authorized to read/write given addresses // (if not, process exits with a segfault) void probe_for_read(const void* addr, size_t len); void probe_for_write(const void* addr, size_t len); diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h index 127b0d7..163045d 100644 --- a/src/kernel/include/thread.h +++ b/src/kernel/include/thread.h @@ -30,9 +30,10 @@ typedef struct thread { region_info_t *stack_region; process_t *proc; - isr_handler_t user_ex_handler; // page fault in kernel memory accessed by user code (violation) + isr_handler_t user_ex_handler; // exception in user code struct thread *next_in_queue; + struct thread *next_in_proc; } thread_t; typedef void (*entry_t)(void*); @@ -48,7 +49,7 @@ void exit(); void usleep(int usecs); bool resume_thread(thread_t *thread); -void kill_thread(thread_t *thread); +void kill_thread(thread_t *thread); // cannot be called for current thread // Kernel critical sections #define CL_EXCL 3 // No interruptions accepted, context switching not allowed diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index 3f8da08..649c801 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -17,6 +17,11 @@ process_t *current_process() { return 0; } +typedef struct { + proc_entry_t entry; + void *sp; +} setup_data_t; + // ============================== // // CREATING AND RUNNING PROCESSES // // ============================== // @@ -39,7 +44,7 @@ process_t *new_process(process_t *parent) { proc->last_ran = 0; proc->regions = 0; - proc->thread = 0; + proc->threads = 0; proc->pid = (next_pid++); proc->parent = parent; proc->next_fd = 1; @@ -54,13 +59,17 @@ error: return 0; } -static void run_user_code(void* entry) { +static void run_user_code(void* param) { + setup_data_t *d = (setup_data_t*)param; + process_t *proc = current_thread->proc; ASSERT(proc != 0); switch_pagedir(proc->pd); - void* esp = (void*)USERSTACK_ADDR + USERSTACK_SIZE; + void* esp = d->sp; + proc_entry_t entry = d->entry; + free(d); asm volatile(" \ cli; \ @@ -86,14 +95,34 @@ bool start_process(process_t *p, void* entry) { bool stack_ok = mmap(p, (void*)USERSTACK_ADDR, USERSTACK_SIZE, MM_READ | MM_WRITE); if (!stack_ok) return false; - thread_t *th = new_thread(run_user_code, entry); - if (th == 0) { + bool ok = process_new_thread(p, entry, (void*)USERSTACK_ADDR + USERSTACK_SIZE); + if (!ok) { munmap(p, (void*)USERSTACK_ADDR); return false; } + return true; +} + +bool process_new_thread(process_t *p, proc_entry_t entry, void* sp) { + setup_data_t *d = (setup_data_t*)malloc(sizeof(setup_data_t)); + d->entry = entry; + d->sp = sp; + + thread_t *th = new_thread(run_user_code, d); + if (th == 0) { + return false; + } + th->proc = p; th->user_ex_handler = proc_user_exception; + + { int st = enter_critical(CL_NOINT); // it's a bit complicated to use mutexes on process_t (TODO: think) + + th->next_in_proc = p->threads; + p->threads = th; + + exit_critical(st); } resume_thread(th); diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c index 3041c6d..009903c 100644 --- a/src/kernel/user/syscall.c +++ b/src/kernel/user/syscall.c @@ -319,10 +319,6 @@ static uint32_t proc_wait_sc(sc_args_t args) { return -1; //TODO } -static uint32_t proc_wait_any_sc(sc_args_t args) { - return -1; //TODO -} - // ====================== // // SYSCALLS SETUP ROUTINE // // ====================== // @@ -365,7 +361,6 @@ void setup_syscall_table() { sc_handlers[SC_PROC_STATUS] = proc_status_sc; sc_handlers[SC_PROC_KILL] = proc_kill_sc; sc_handlers[SC_PROC_WAIT] = proc_wait_sc; - sc_handlers[SC_PROC_WAIT_ANY] = proc_wait_any_sc; } void syscall_handler(registers_t *regs) { diff --git a/src/lib/include/syscall.h b/src/lib/include/syscall.h index c26a805..ddc0e18 100644 --- a/src/lib/include/syscall.h +++ b/src/lib/include/syscall.h @@ -49,7 +49,6 @@ bool bind_fd(pid_t pid, fd_t new_fd, fd_t fd); bool proc_exec(pid_t pid, const char* file); bool proc_status(pid_t pid, proc_status_t *s); bool proc_kill(pid_t pid, proc_status_t *s); -void proc_wait(pid_t pid, proc_status_t *s); -void proc_wait_any(proc_status_t *s); +void proc_wait(pid_t pid, bool wait, proc_status_t *s); /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/lib/libkogata/syscall.c b/src/lib/libkogata/syscall.c index 6f37c47..4b31ab3 100644 --- a/src/lib/libkogata/syscall.c +++ b/src/lib/libkogata/syscall.c @@ -153,11 +153,8 @@ bool proc_status(pid_t pid, proc_status_t *s) { bool proc_kill(pid_t pid, proc_status_t *s) { return call(SC_PROC_KILL, pid, (uint32_t)s, 0, 0, 0); } -void proc_wait(pid_t pid, proc_status_t *s) { - call(SC_PROC_WAIT, pid, (uint32_t)s, 0, 0, 0); -} -void proc_wait_any(proc_status_t *s) { - call(SC_PROC_WAIT_ANY, (uint32_t)s, 0, 0, 0, 0); +void proc_wait(pid_t pid, bool block, proc_status_t *s) { + call(SC_PROC_WAIT, pid, block, (uint32_t)s, 0, 0); } |