diff options
author | Andrew Waterman <waterman@cs.berkeley.edu> | 2013-07-13 21:43:57 -0700 |
---|---|---|
committer | Andrew Waterman <waterman@cs.berkeley.edu> | 2013-07-13 21:44:16 -0700 |
commit | cc72987e655578b0529b6c3c8084e810cf40b358 (patch) | |
tree | a7a99a9406dfef2d4103e85bc0976cb8d039d7e7 /pk/file.c | |
parent | 0bdb8c84092bf7c5eb4c981c620997a5893bfb70 (diff) | |
download | pk-cc72987e655578b0529b6c3c8084e810cf40b358.zip pk-cc72987e655578b0529b6c3c8084e810cf40b358.tar.gz pk-cc72987e655578b0529b6c3c8084e810cf40b358.tar.bz2 |
Support Linux ABI and (optionally) virtual memory
Diffstat (limited to 'pk/file.c')
-rw-r--r-- | pk/file.c | 108 |
1 files changed, 57 insertions, 51 deletions
@@ -6,66 +6,52 @@ #include "pk.h" #include "frontend.h" #include "pcr.h" +#include "vm.h" #define MAX_FDS 32 -file_t* fds[MAX_FDS]; +static file_t* fds[MAX_FDS]; #define MAX_FILES 32 -file_t files[MAX_FILES] = {[0 ... MAX_FILES-1] = {-1,{0}}}; +static file_t files[MAX_FILES] = {[0 ... MAX_FILES-1] = {-1,{0}}}; file_t *stdout, *stdin, *stderr; -static void file_incref(file_t* f) +void file_incref(file_t* f) { - atomic_add(&f->refcnt,1); + atomic_add(&f->refcnt, 1); } void file_decref(file_t* f) { - if(atomic_add(&f->refcnt,-1) == 2) + if (atomic_add(&f->refcnt, -1) == 2) { - if(f->kfd != -1) - { - frontend_syscall(SYS_close,f->kfd,0,0,0); - f->kfd = -1; - } - atomic_add(&f->refcnt,-1); // I think this could just be atomic_set(..,0) + int kfd = f->kfd; + mb(); + atomic_set(&f->refcnt, 0); + + frontend_syscall(SYS_close, kfd, 0, 0, 0); } } static file_t* file_get_free() { - for(int i = 0; i < MAX_FILES; i++) - { - if(atomic_read(&files[i].refcnt) == 0) - { - if(atomic_add(&files[i].refcnt,1) == 0) - { - atomic_add(&files[i].refcnt,1); - return &files[i]; - } - file_decref(&files[i]); - } - } + for (file_t* f = files; f < files + MAX_FILES; f++) + if (atomic_read(&f->refcnt) == 0 && atomic_cas(&f->refcnt, 0, 2) == 0) + return f; return NULL; } -static int fd_get_free() +int file_dup(file_t* f) { - for(int i = 0; i < MAX_FDS; i++) - if(fds[i] == NULL) + for (int i = 0; i < MAX_FDS; i++) + { + if (fds[i] == NULL && __sync_bool_compare_and_swap(&fds[i], 0, f)) + { + file_incref(f); return i; + } + } return -1; } -int file_dup(file_t* f) -{ - int fd = fd_get_free(); - if(fd == -1) - return -1; - file_incref(f); - fds[fd] = f; - return fd; -} - void file_init() { stdin = file_get_free(); @@ -84,16 +70,28 @@ void file_init() file_t* file_get(int fd) { - return fd < 0 || fd >= MAX_FDS ? NULL : fds[fd]; + file_t* f; + if (fd < 0 || fd >= MAX_FDS || (f = fds[fd]) == NULL) + return 0; + + long old_cnt; + do { + old_cnt = atomic_read(&f->refcnt); + if (old_cnt == 0) + return 0; + } while (atomic_cas(&f->refcnt, old_cnt, old_cnt+1) != old_cnt); + + return f; } -sysret_t file_open(const char* fn, size_t len, int flags, int mode) +sysret_t file_open(const char* fn, int flags, int mode) { file_t* f = file_get_free(); if(!f) return (sysret_t){-1,ENOMEM}; - sysret_t ret = frontend_syscall(SYS_open,(long)fn,len,flags,mode); + size_t fn_size = strlen(fn)+1; + sysret_t ret = frontend_syscall(SYS_open, (long)fn, fn_size, flags, mode); if(ret.result != -1) { f->kfd = ret.result; @@ -108,39 +106,47 @@ sysret_t file_open(const char* fn, size_t len, int flags, int mode) int fd_close(int fd) { file_t* f = file_get(fd); - if(!f) + if (!f) + return -1; + int success = __sync_bool_compare_and_swap(&fds[fd], f, 0); + file_decref(f); + if (!success) return -1; - fds[fd] = NULL; file_decref(f); return 0; } -sysret_t file_read(file_t* f, char* buf, size_t size) +sysret_t file_read(file_t* f, void* buf, size_t size) { - return frontend_syscall(SYS_read,f->kfd,(long)buf,size,0); + populate_mapping(buf, size, PROT_WRITE); + return frontend_syscall(SYS_read, f->kfd, (uintptr_t)buf, size, 0); } -sysret_t file_pread(file_t* f, char* buf, size_t size, off_t offset) +sysret_t file_pread(file_t* f, void* buf, size_t size, off_t offset) { - return frontend_syscall(SYS_pread,f->kfd,(long)buf,size,offset); + populate_mapping(buf, size, PROT_WRITE); + return frontend_syscall(SYS_pread, f->kfd, (uintptr_t)buf, size, offset); } -sysret_t file_write(file_t* f, const char* buf, size_t size) +sysret_t file_write(file_t* f, const void* buf, size_t size) { - return frontend_syscall(SYS_write,f->kfd,(long)buf,size,0); + populate_mapping(buf, size, PROT_READ); + return frontend_syscall(SYS_write, f->kfd, (uintptr_t)buf, size, 0); } -sysret_t file_pwrite(file_t* f, const char* buf, size_t size, off_t offset) +sysret_t file_pwrite(file_t* f, const void* buf, size_t size, off_t offset) { - return frontend_syscall(SYS_pwrite,f->kfd,(long)buf,size,offset); + populate_mapping(buf, size, PROT_READ); + return frontend_syscall(SYS_pwrite, f->kfd, (uintptr_t)buf, size, offset); } sysret_t file_stat(file_t* f, struct stat* s) { - return frontend_syscall(SYS_fstat,f->kfd,(long)s,0,0); + populate_mapping(s, sizeof(*s), PROT_WRITE); + return frontend_syscall(SYS_fstat, f->kfd, (uintptr_t)s, 0, 0); } sysret_t file_lseek(file_t* f, size_t ptr, int dir) { - return frontend_syscall(SYS_lseek,f->kfd,ptr,dir,0); + return frontend_syscall(SYS_lseek, f->kfd, ptr, dir, 0); } |