From 9ba449a6e5f9db20923fb9802eefe0f090ba5fff Mon Sep 17 00:00:00 2001 From: Alex Auvolat Date: Fri, 20 Feb 2015 15:47:51 +0100 Subject: Change mode of operation for mmap_file (see readme) --- README.md | 17 ++++++++++++++++- src/kernel/core/kmain.c | 12 ++---------- src/kernel/core/thread.c | 4 ++++ src/kernel/include/process.h | 18 +++++++++++++++++- src/kernel/include/thread.h | 5 +++-- src/kernel/include/vfs.h | 13 ++++++++++++- src/kernel/user/nullfs.c | 3 ++- src/kernel/user/process.c | 35 ++++++++++++++++------------------- src/kernel/user/vfs.c | 12 ++++++++++++ 9 files changed, 84 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 282054c..b74eeef 100644 --- a/README.md +++ b/README.md @@ -93,7 +93,22 @@ running the tests): ### Things to design -* Cache architecture +* Cache architecture : + - A RAM file is basically a bunch of pages that contain the data (rather than a segment of + malloc()'ed memory) + - A framebuffer device is basically a bunch of pages at a fixed hardware location, that cannot + grow + - In the two previous cases, the pages are never freed : they are not a cache, they are the + data itself. + - In the case of an on-disk file, the pages are a copy of the file's data that is originally + on-disk, and we might want to free these pages even while a process is using them, because + 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) * IPC * How does a process exit, what does it do, how do processes synchronize ? * Have several threads in a single process diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c index 219bab1..fa5d69c 100644 --- a/src/kernel/core/kmain.c +++ b/src/kernel/core/kmain.c @@ -124,14 +124,6 @@ void kernel_init_stage2(void* data) { // Launch some worker threads start_workers(2); - // test sleep() - dbg_printf("Testing sleep() : "); - for (int i = 0; i < 20; i++) { - usleep(50000); - dbg_printf("."); - } - dbg_printf("\n"); - TEST_PLACEHOLDER_AFTER_TASKING; // Create devfs @@ -167,13 +159,13 @@ void kernel_init_stage2(void* data) { ASSERT(nullfs_add_ram_file(devfs, name, (char*)mods[i].mod_start, - len, false, FM_READ | FM_MMAP)); + len, false, FM_READ)); } TEST_PLACEHOLDER_AFTER_DEVFS; // Launch INIT - fs_handle_t *init_bin = fs_open(devfs, "/mod/init.bin", FM_READ | FM_MMAP); + fs_handle_t *init_bin = fs_open(devfs, "/mod/init.bin", FM_READ); if (init_bin == 0) PANIC("No init.bin module provided!"); if (!is_elf(init_bin)) PANIC("init.bin is not valid ELF32 binary"); diff --git a/src/kernel/core/thread.c b/src/kernel/core/thread.c index 7f9f25e..60dccde 100644 --- a/src/kernel/core/thread.c +++ b/src/kernel/core/thread.c @@ -7,6 +7,7 @@ #include #include #include +#include void save_context_and_enter_scheduler(saved_context_t *ctx); void resume_context(saved_context_t *ctx); @@ -84,6 +85,8 @@ void run_scheduler() { // This function is expected NEVER TO RETURN if (current_thread != 0 && current_thread->state == T_STATE_RUNNING) { + current_thread->last_ran = worker_get_time(); + if (current_thread->proc) current_thread->proc->last_ran = current_thread->last_ran; enqueue_thread(current_thread, true); } @@ -141,6 +144,7 @@ thread_t *new_thread(entry_t entry, void* data) { t->ctx.eip = (void(*)())run_thread; t->state = T_STATE_PAUSED; + t->last_ran = 0; t->current_pd_d = get_kernel_pagedir(); diff --git a/src/kernel/include/process.h b/src/kernel/include/process.h index 07cc14e..6e287e1 100644 --- a/src/kernel/include/process.h +++ b/src/kernel/include/process.h @@ -21,7 +21,22 @@ #define USERSTACK_ADDR 0xB8000000 #define USERSTACK_SIZE 0x00020000 // 32 KB -struct user_region; +typedef struct process process_t; + +typedef struct user_region { + process_t *proc; + + void* addr; + size_t size; + + int mode; + + fs_handle_t *file; // null if not mmaped-file + size_t file_offset; + + struct user_region *next; +} user_region_t; + typedef struct process { pagedir_t *pd; struct user_region *regions; @@ -32,6 +47,7 @@ typedef struct process { int next_fd; thread_t *thread; + uint64_t last_ran; int pid; struct process *parent; diff --git a/src/kernel/include/thread.h b/src/kernel/include/thread.h index 8ffbb3d..fa7dc6f 100644 --- a/src/kernel/include/thread.h +++ b/src/kernel/include/thread.h @@ -18,16 +18,17 @@ typedef struct saved_context { void (*eip)(); } saved_context_t; -struct process; +typedef struct process process_t; typedef struct thread { saved_context_t ctx; pagedir_t *current_pd_d; uint32_t state; + uint64_t last_ran; region_info_t *stack_region; - struct process *proc; + process_t *proc; isr_handler_t user_ex_handler; // page fault in kernel memory accessed by user code (violation) struct thread *next_in_queue; diff --git a/src/kernel/include/vfs.h b/src/kernel/include/vfs.h index cca4952..82b02f4 100644 --- a/src/kernel/include/vfs.h +++ b/src/kernel/include/vfs.h @@ -41,15 +41,21 @@ struct fs; struct fs_node; struct fs_handle; +typedef struct user_region user_region_t; + // ------------------------------------------- // Structure defining a handle to an open file typedef struct { + // Standard read-write architecture size_t (*read)(fs_handle_ptr f, size_t offset, size_t len, char* buf); size_t (*write)(fs_handle_ptr f, size_t offset, size_t len, const char* buf); bool (*readdir)(fs_handle_ptr f, dirent_t *d); int (*ioctl)(fs_handle_ptr f, int command, void* data); void (*close)(fs_handle_ptr f); + // Page cache architecture, must be implemented by all files opened with FM_MMAP + uint32_t (*get_page)(fs_handle_ptr f, size_t offset); + void (*commit_page)(fs_handle_ptr f, size_t offset, uint64_t time); // notifies change } fs_handle_ops_t; typedef struct fs_handle { @@ -165,11 +171,16 @@ bool fs_stat(fs_t *fs, const char* file, stat_t *st); fs_handle_t* fs_open(fs_t *fs, const char* file, int mode); void ref_file(fs_handle_t *file); void unref_file(fs_handle_t *file); + int file_get_mode(fs_handle_t *f); +bool file_stat(fs_handle_t *f, stat_t *st); + size_t file_read(fs_handle_t *f, size_t offset, size_t len, char* buf); size_t file_write(fs_handle_t *f, size_t offset, size_t len, const char* buf); -bool file_stat(fs_handle_t *f, stat_t *st); int file_ioctl(fs_handle_t *f, int command, void* data); bool file_readdir(fs_handle_t *f, dirent_t *d); +uint32_t file_get_page(fs_handle_t *f, size_t offset); +void file_commit_page(fs_handle_t *f, size_t offset, uint64_t time); + /* vim: set ts=4 sw=4 tw=0 noet :*/ diff --git a/src/kernel/user/nullfs.c b/src/kernel/user/nullfs.c index 0ca0073..a925ab5 100644 --- a/src/kernel/user/nullfs.c +++ b/src/kernel/user/nullfs.c @@ -218,7 +218,8 @@ bool nullfs_add_ram_file(fs_t *fs, const char* name, char* data, size_t init_sz, f->data = data; f->own_data = false; } - f->ok_modes = ok_modes; + f->ok_modes = ok_modes & + (FM_TRUNC | FM_READ | FM_WRITE); // no MMAP support f->lock = MUTEX_UNLOCKED; bool add_ok = nullfs_add_node(fs, name, f, &nullfs_f_ops); diff --git a/src/kernel/user/process.c b/src/kernel/user/process.c index 3ee78a7..c2eb413 100644 --- a/src/kernel/user/process.c +++ b/src/kernel/user/process.c @@ -5,17 +5,6 @@ #include #include -typedef struct user_region { - void* addr; - size_t size; - - int mode; - - fs_handle_t *file; // null if not mmaped-file - size_t file_offset; - - struct user_region *next; -} user_region_t; static int next_pid = 1; @@ -47,6 +36,7 @@ process_t *new_process(process_t *parent) { proc->pd = create_pagedir(proc_usermem_pf, proc); if (proc->pd == 0) goto error; + proc->last_ran = 0; proc->regions = 0; proc->thread = 0; proc->pid = (next_pid++); @@ -207,6 +197,7 @@ bool mmap_file(process_t *proc, fs_handle_t *h, size_t offset, void* addr, size_ if (find_user_region(proc, addr) != 0) return false; if ((uint32_t)addr & (~PAGE_MASK)) return false; + if ((uint32_t)offset & (~PAGE_MASK)) return false; int fmode = file_get_mode(h); if (!(fmode & FM_MMAP) || !(fmode & FM_READ)) return false; @@ -247,6 +238,9 @@ bool mchmap(process_t *proc, void* addr, int mode) { if (r == 0) return false; + if (r->file != 0) { + if ((mode & MM_WRITE) && !(file_get_mode(r->file) & FM_WRITE)) return false; + } r->mode = mode; // change mode on already mapped pages @@ -295,10 +289,13 @@ bool munmap(process_t *proc, void* addr) { if (ent & PTE_PRESENT) { if ((ent & PTE_DIRTY) && (r->mode & MM_WRITE) && r->file != 0) { - file_write(r->file, it - r->addr + r->file_offset, PAGE_SIZE, it); + file_commit_page(r->file, it - r->addr + r->file_offset, proc->last_ran); } pd_unmap_page(it); - frame_free(frame, 1); + if (r->file != 0) { + // frame is owned by process + frame_free(frame, 1); + } } } switch_pagedir(save_pd); @@ -342,7 +339,11 @@ static void proc_usermem_pf(void* p, registers_t *regs, void* addr) { uint32_t frame; do { - frame = frame_alloc(1); + if (r->file == 0) { + frame = frame_alloc(1); + } else { + frame = file_get_page(r->file, addr - r->addr + r->file_offset); + } if (frame == 0) { dbg_printf("OOM for process %d ; yielding and waiting for someone to free some RAM.\n", proc->pid); yield(); @@ -354,11 +355,7 @@ static void proc_usermem_pf(void* p, registers_t *regs, void* addr) { yield(); } - memset(addr, 0, PAGE_SIZE); // zero out - - if (r->file != 0) { - file_read(r->file, addr - r->addr + r->file_offset, PAGE_SIZE, addr); - } + if (r->file == 0) memset(addr, 0, PAGE_SIZE); // zero out } void probe_for_read(const void* addr, size_t len) { diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c index a5f03ca..c20caa0 100644 --- a/src/kernel/user/vfs.c +++ b/src/kernel/user/vfs.c @@ -445,4 +445,16 @@ bool file_readdir(fs_handle_t *f, dirent_t *d) { return f->ops->readdir && f->ops->readdir(f->data, d); } +uint32_t file_get_page(fs_handle_t *f, size_t offset) { + if (!(f->mode & FM_MMAP)) return 0; + ASSERT(f->ops->get_page != 0); + return f->ops->get_page(f->data, offset); +} + +void file_commit_page(fs_handle_t *f, size_t offset, uint64_t time) { + if (!(f->mode & FM_MMAP)) return; + ASSERT(f->ops->commit_page != 0); + f->ops->commit_page(f->data, offset, time); +} + /* vim: set ts=4 sw=4 tw=0 noet :*/ -- cgit v1.2.3