diff options
author | Alex Auvolat <alex.auvolat@ens.fr> | 2015-03-08 19:07:48 +0100 |
---|---|---|
committer | Alex Auvolat <alex.auvolat@ens.fr> | 2015-03-08 19:07:48 +0100 |
commit | 6dd488b87fdc47fb377ba648a6cd598bdab87f59 (patch) | |
tree | 2e69225353054eb43a9869af4ca9766a0f39c828 /src/kernel/user | |
parent | bcee004478c6448541ce583e75c706e185190800 (diff) | |
download | kogata-6dd488b87fdc47fb377ba648a6cd598bdab87f59.tar.gz kogata-6dd488b87fdc47fb377ba648a6cd598bdab87f59.zip |
Implement select ; add two tests for channels.
Diffstat (limited to 'src/kernel/user')
-rw-r--r-- | src/kernel/user/ipc.c | 22 | ||||
-rw-r--r-- | src/kernel/user/nullfs.c | 2 | ||||
-rw-r--r-- | src/kernel/user/syscall.c | 54 | ||||
-rw-r--r-- | src/kernel/user/vfs.c | 9 |
4 files changed, 86 insertions, 1 deletions
diff --git a/src/kernel/user/ipc.c b/src/kernel/user/ipc.c index 648fdf2..dce1847 100644 --- a/src/kernel/user/ipc.c +++ b/src/kernel/user/ipc.c @@ -11,6 +11,7 @@ static size_t channel_read(fs_handle_t *c, size_t offset, size_t len, char* buf); static size_t channel_write(fs_handle_t *c, size_t offset, size_t len, const char* buf); +static int channel_poll(fs_handle_t *c, void** out_wait_obj); static bool channel_stat(fs_node_ptr c, stat_t *st); static void channel_close(fs_handle_t *c); @@ -18,6 +19,7 @@ static fs_node_ops_t channel_ops = { .read = channel_read, .write = channel_write, .close = channel_close, + .poll = channel_poll, .open = 0, .readdir = 0, .ioctl = 0, @@ -157,6 +159,20 @@ size_t channel_write(fs_handle_t *h, size_t offset, size_t req_len, const char* return ret; } +int channel_poll(fs_handle_t *h, void** out_wait_obj) { + channel_t *c = (channel_t*)h->data; + + int ret = 0; + + if (c->other_side == 0) ret |= SEL_ERROR; + if (c->other_side && c->other_side->buf_used < CHANNEL_BUFFER_SIZE) ret |= SEL_WRITE; + if (c->buf_used > 0) ret |= SEL_READ; + + if (out_wait_obj) *out_wait_obj = c; + + return ret; +} + bool channel_stat(fs_node_ptr ch, stat_t *st) { channel_t *c = (channel_t*)ch; @@ -176,7 +192,11 @@ void channel_close(fs_handle_t *ch) { mutex_lock(&c->lock); - c->other_side->other_side = 0; + if (c->other_side) { + resume_on(c->other_side); + c->other_side->other_side = 0; + } + free(c); } diff --git a/src/kernel/user/nullfs.c b/src/kernel/user/nullfs.c index 60872ab..0dc1b22 100644 --- a/src/kernel/user/nullfs.c +++ b/src/kernel/user/nullfs.c @@ -53,6 +53,7 @@ static fs_node_ops_t nullfs_d_ops = { .read = 0, .write = 0, .ioctl = 0, + .poll = 0, }; static fs_node_ops_t nullfs_f_ops = { @@ -68,6 +69,7 @@ static fs_node_ops_t nullfs_f_ops = { .close = nullfs_f_close, .readdir = 0, .ioctl =0, + .poll = 0, }; diff --git a/src/kernel/user/syscall.c b/src/kernel/user/syscall.c index c352ff4..67ed317 100644 --- a/src/kernel/user/syscall.c +++ b/src/kernel/user/syscall.c @@ -6,6 +6,7 @@ #include <ipc.h> #include <sct.h> +#include <worker.h> typedef struct { uint32_t sc_id, a, b, c, d, e; // a: ebx, b: ecx, c: edx, d: esi, e: edi @@ -282,6 +283,58 @@ static uint32_t get_mode_sc(sc_args_t args) { return file_get_mode(h); } +static uint32_t select_sc(sc_args_t args) { + sel_fd_t *fds = (sel_fd_t*)args.a; + size_t n = args.b; + int timeout = args.c; + + probe_for_write(fds, n * sizeof(sel_fd_t)); + + uint64_t select_begin_time = get_kernel_time(); + + void** wait_objs = (void**)malloc((n+1) * sizeof(void*)); + if (!wait_objs) return false; + + bool ret = false; + + int st = enter_critical(CL_NOSWITCH); + + while (true) { + // ---- Poll FDs, if any is ok then return it + size_t n_wait_objs = 0; + if (timeout > 0) wait_objs[n_wait_objs++] = current_thread; + for (size_t i = 0; i < n; i++) { + fs_handle_t *h = proc_read_fd(current_process(), fds[i].fd); + if (h) { + fds[i].got_flags = file_poll(h, &wait_objs[n_wait_objs]); + if (wait_objs[n_wait_objs]) n_wait_objs++; + if (fds[i].got_flags & fds[i].req_flags) ret = true; + } + } + + uint64_t time = get_kernel_time(); + + // ---- If none of the handles given is a valid handle, return false + if (n_wait_objs == 0) break; + // ---- If any is ok, return true + if (ret) break; + // ---- If the timeout is over, return false + if (timeout >= 0 && time - select_begin_time >= (uint64_t)timeout) break; + + // ---- Do a wait, if interrupted (killed or whatever) return false + void resume_on_v(void*x) { + resume_on(x); + } + if (timeout > 0) worker_push_in(time - select_begin_time - timeout, resume_on_v, current_thread); + if (!wait_on_many(wait_objs, n_wait_objs)) break; + } + + exit_critical(st); + + free(wait_objs); + return ret; +} + // ---- IPC static uint32_t make_channel_sc(sc_args_t args) { @@ -642,6 +695,7 @@ void setup_syscall_table() { sc_handlers[SC_STAT_OPEN] = stat_open_sc; sc_handlers[SC_IOCTL] = ioctl_sc; sc_handlers[SC_GET_MODE] = get_mode_sc; + sc_handlers[SC_SELECT] = select_sc; sc_handlers[SC_MK_CHANNEL] = make_channel_sc; sc_handlers[SC_GEN_TOKEN] = gen_token_sc; diff --git a/src/kernel/user/vfs.c b/src/kernel/user/vfs.c index 4e8cf53..05b4a2c 100644 --- a/src/kernel/user/vfs.c +++ b/src/kernel/user/vfs.c @@ -494,4 +494,13 @@ bool file_readdir(fs_handle_t *f, size_t ent_no, dirent_t *d) { return f->ops->readdir && f->ops->readdir(f, ent_no, d); } +int file_poll(fs_handle_t *f, void** out_wait_obj) { + if (!f->ops->poll) { + if (out_wait_obj) *out_wait_obj = 0; + return 0; + } + + return f->ops->poll(f, out_wait_obj); +} + /* vim: set ts=4 sw=4 tw=0 noet :*/ |