aboutsummaryrefslogtreecommitdiff
path: root/src/kernel/user
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-03-08 19:07:48 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-03-08 19:07:48 +0100
commit6dd488b87fdc47fb377ba648a6cd598bdab87f59 (patch)
tree2e69225353054eb43a9869af4ca9766a0f39c828 /src/kernel/user
parentbcee004478c6448541ce583e75c706e185190800 (diff)
downloadkogata-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.c22
-rw-r--r--src/kernel/user/nullfs.c2
-rw-r--r--src/kernel/user/syscall.c54
-rw-r--r--src/kernel/user/vfs.c9
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 :*/