aboutsummaryrefslogtreecommitdiff
path: root/pk/file.c
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2013-07-13 21:43:57 -0700
committerAndrew Waterman <waterman@cs.berkeley.edu>2013-07-13 21:44:16 -0700
commitcc72987e655578b0529b6c3c8084e810cf40b358 (patch)
treea7a99a9406dfef2d4103e85bc0976cb8d039d7e7 /pk/file.c
parent0bdb8c84092bf7c5eb4c981c620997a5893bfb70 (diff)
downloadpk-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.c108
1 files changed, 57 insertions, 51 deletions
diff --git a/pk/file.c b/pk/file.c
index 195bcdc..ecc5f28 100644
--- a/pk/file.c
+++ b/pk/file.c
@@ -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);
}