From 7d47cab8ab292d23e6f05c8d51a155d3575ceb4a Mon Sep 17 00:00:00 2001 From: Kevin Lange Date: Fri, 6 Jan 2017 19:01:22 +0900 Subject: [PATCH] Support fswait in tty --- kernel/ds/ringbuffer.c | 25 +++ kernel/fs/pipe.c | 15 +- kernel/fs/tty.c | 32 ++++ kernel/fs/vfs.c | 10 -- kernel/include/fs.h | 3 - kernel/include/process.h | 2 +- kernel/include/ringbuffer.h | 2 + kernel/sys/process.c | 4 +- modules/packetfs.c | 10 -- userspace/gui/terminal/terminal.c | 246 ++++++++++++++++-------------- 10 files changed, 193 insertions(+), 156 deletions(-) diff --git a/kernel/ds/ringbuffer.c b/kernel/ds/ringbuffer.c index 3abaa4fd..5d8bd48b 100644 --- a/kernel/ds/ringbuffer.c +++ b/kernel/ds/ringbuffer.c @@ -5,6 +5,7 @@ */ #include #include +#include size_t ring_buffer_unread(ring_buffer_t * ring_buffer) { if (ring_buffer->read_ptr == ring_buffer->write_ptr) { @@ -48,6 +49,26 @@ static inline void ring_buffer_increment_write(ring_buffer_t * ring_buffer) { } } +static void ring_buffer_alert_waiters(ring_buffer_t * ring_buffer) { + if (ring_buffer->alert_waiters) { + while (ring_buffer->alert_waiters->head) { + node_t * node = list_dequeue(ring_buffer->alert_waiters); + process_t * p = node->value; + process_alert_node(p, ring_buffer); + free(node); + } + } +} + +void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process) { + if (!ring_buffer->alert_waiters) { + ring_buffer->alert_waiters = list_create(); + } + + list_insert(ring_buffer->alert_waiters, process); + list_insert(((process_t *)process)->node_waits, ring_buffer); +} + size_t ring_buffer_read(ring_buffer_t * ring_buffer, size_t size, uint8_t * buffer) { size_t collected = 0; while (collected == 0) { @@ -83,6 +104,7 @@ size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buf spin_unlock(ring_buffer->lock); wakeup_queue(ring_buffer->wait_queue_readers); + ring_buffer_alert_waiters(ring_buffer); if (written < size) { if (sleep_on(ring_buffer->wait_queue_writers) && ring_buffer->internal_stop) { ring_buffer->internal_stop = 0; @@ -92,6 +114,7 @@ size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buf } wakeup_queue(ring_buffer->wait_queue_readers); + ring_buffer_alert_waiters(ring_buffer); return written; } @@ -102,6 +125,7 @@ ring_buffer_t * ring_buffer_create(size_t size) { out->write_ptr = 0; out->read_ptr = 0; out->size = size; + out->alert_waiters = NULL; spin_init(out->lock); @@ -118,6 +142,7 @@ void ring_buffer_destroy(ring_buffer_t * ring_buffer) { wakeup_queue(ring_buffer->wait_queue_writers); wakeup_queue(ring_buffer->wait_queue_readers); + ring_buffer_alert_waiters(ring_buffer); list_free(ring_buffer->wait_queue_writers); list_free(ring_buffer->wait_queue_readers); diff --git a/kernel/fs/pipe.c b/kernel/fs/pipe.c index 5aa9cb97..2a478937 100644 --- a/kernel/fs/pipe.c +++ b/kernel/fs/pipe.c @@ -71,17 +71,14 @@ static inline void pipe_increment_write_by(pipe_device_t * pipe, size_t amount) pipe->write_ptr = (pipe->write_ptr + amount) % pipe->size; } -static void pipe_alert_waiters(fs_node_t * fs_node) { - pipe_device_t * pipe = (pipe_device_t *)fs_node->device; - +static void pipe_alert_waiters(pipe_device_t * pipe) { if (pipe->alert_waiters) { while (pipe->alert_waiters->head) { node_t * node = list_dequeue(pipe->alert_waiters); process_t * p = node->value; - process_alert_node(p, fs_node); + process_alert_node(p, pipe); free(node); } - } } @@ -180,7 +177,7 @@ uint32_t write_pipe(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *bu spin_unlock(pipe->lock_write); wakeup_queue(pipe->wait_queue_readers); - pipe_alert_waiters(node); + pipe_alert_waiters(pipe); if (written < size) { sleep_on(pipe->wait_queue_writers); } @@ -249,11 +246,6 @@ static int pipe_wait(fs_node_t * node, void * process) { return 0; } -static int pipe_match(fs_node_t * node, void * value) { - pipe_device_t * pipe = (pipe_device_t *)node->device; - return pipe == value; -} - fs_node_t * make_pipe(size_t size) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); pipe_device_t * pipe = malloc(sizeof(pipe_device_t)); @@ -278,7 +270,6 @@ fs_node_t * make_pipe(size_t size) { fnode->selectcheck = pipe_check; fnode->selectwait = pipe_wait; - fnode->match = pipe_match; fnode->atime = now(); fnode->mtime = fnode->atime; diff --git a/kernel/fs/tty.c b/kernel/fs/tty.c index 8f647f52..b62be61f 100644 --- a/kernel/fs/tty.c +++ b/kernel/fs/tty.c @@ -280,6 +280,34 @@ int pty_available_output(fs_node_t * node) { return ring_buffer_unread(pty->out); } +static int check_pty_master(fs_node_t * node) { + pty_t * pty = (pty_t *)node->device; + if (ring_buffer_unread(pty->out) > 0) { + return 0; + } + return 1; +} + +static int check_pty_slave(fs_node_t * node) { + pty_t * pty = (pty_t *)node->device; + if (ring_buffer_unread(pty->in) > 0) { + return 0; + } + return 1; +} + +static int wait_pty_master(fs_node_t * node, void * process) { + pty_t * pty = (pty_t *)node->device; + ring_buffer_select_wait(pty->out, process); + return 0; +} + +static int wait_pty_slave(fs_node_t * node, void * process) { + pty_t * pty = (pty_t *)node->device; + ring_buffer_select_wait(pty->in, process); + return 0; +} + fs_node_t * pty_master_create(pty_t * pty) { fs_node_t * fnode = malloc(sizeof(fs_node_t)); memset(fnode, 0x00, sizeof(fs_node_t)); @@ -294,6 +322,8 @@ fs_node_t * pty_master_create(pty_t * pty) { fnode->write = write_pty_master; fnode->open = open_pty_master; fnode->close = close_pty_master; + fnode->selectcheck = check_pty_master; + fnode->selectwait = wait_pty_master; fnode->readdir = NULL; fnode->finddir = NULL; fnode->ioctl = ioctl_pty_master; @@ -318,6 +348,8 @@ fs_node_t * pty_slave_create(pty_t * pty) { fnode->write = write_pty_slave; fnode->open = open_pty_slave; fnode->close = close_pty_slave; + fnode->selectcheck = check_pty_slave; + fnode->selectwait = wait_pty_slave; fnode->readdir = NULL; fnode->finddir = NULL; fnode->ioctl = ioctl_pty_slave; diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index b53bf2ed..b0be974e 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -115,16 +115,6 @@ int selectwait_fs(fs_node_t * node, void * process) { return -1; } -/** - * fsnode_matches: Compare a node internally against a magic value to determine if the value belongs to that node. - */ -int fsnode_matches(fs_node_t * node, void * value) { - if (!node) return 0; - if (!node->match) return 0; - return node->match(node, value); -} - - /** * read_fs: Read a file system node based on its underlying type. * diff --git a/kernel/include/fs.h b/kernel/include/fs.h index 322d705a..12e316ed 100644 --- a/kernel/include/fs.h +++ b/kernel/include/fs.h @@ -53,7 +53,6 @@ typedef void (*symlink_type_t) (struct fs_node *, char * name, char * value); typedef int (*readlink_type_t) (struct fs_node *, char * buf, size_t size); typedef int (*selectcheck_type_t) (struct fs_node *); typedef int (*selectwait_type_t) (struct fs_node *, void * process); -typedef int (*match_type_t) (struct fs_node *, void * value); typedef struct fs_node { char name[256]; /* The filename. */ @@ -95,7 +94,6 @@ typedef struct fs_node { selectcheck_type_t selectcheck; selectwait_type_t selectwait; - match_type_t match; } fs_node_t; struct dirent { @@ -149,7 +147,6 @@ int symlink_fs(char * value, char * name); int readlink_fs(fs_node_t * node, char * buf, size_t size); int selectcheck_fs(fs_node_t * node); int selectwait_fs(fs_node_t * node, void * process); -int fsnode_matches(fs_node_t * node, void * value); void vfs_install(void); void * vfs_mount(char * path, fs_node_t * local_root); diff --git a/kernel/include/process.h b/kernel/include/process.h index 13fbf529..34c56c87 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -137,7 +137,7 @@ extern process_t * kernel_idle_task; extern list_t * process_list; extern int process_wait_nodes(process_t * process,fs_node_t * nodes[]); -extern int process_alert_node(process_t * process, fs_node_t * fs_node); +extern int process_alert_node(process_t * process, void * value); typedef void (*tasklet_t) (void *, char *); extern int create_kernel_tasklet(tasklet_t tasklet, char * name, void * argp); diff --git a/kernel/include/ringbuffer.h b/kernel/include/ringbuffer.h index 25d83a58..8d1de7a5 100644 --- a/kernel/include/ringbuffer.h +++ b/kernel/include/ringbuffer.h @@ -10,6 +10,7 @@ typedef struct { list_t * wait_queue_readers; list_t * wait_queue_writers; int internal_stop; + list_t * alert_waiters; } ring_buffer_t; size_t ring_buffer_unread(ring_buffer_t * ring_buffer); @@ -21,5 +22,6 @@ size_t ring_buffer_write(ring_buffer_t * ring_buffer, size_t size, uint8_t * buf ring_buffer_t * ring_buffer_create(size_t size); void ring_buffer_destroy(ring_buffer_t * ring_buffer); void ring_buffer_interrupt(ring_buffer_t * ring_buffer); +void ring_buffer_select_wait(ring_buffer_t * ring_buffer, void * process); #endif diff --git a/kernel/sys/process.c b/kernel/sys/process.c index 5b61ecf4..281547ca 100644 --- a/kernel/sys/process.c +++ b/kernel/sys/process.c @@ -849,14 +849,14 @@ int process_wait_nodes(process_t * process,fs_node_t * nodes[]) { return process->awoken_index; } -int process_alert_node(process_t * process, fs_node_t * fs_node) { +int process_alert_node(process_t * process, void * value) { if (!process->node_waits) { return 0; /* Possibly already returned. Wait for another call. */ } int index = 0; foreach(node, process->node_waits) { - if (fsnode_matches(fs_node, node->value)) { + if (value == node->value) { process->awoken_index = index; list_free(process->node_waits); free(process->node_waits); diff --git a/modules/packetfs.c b/modules/packetfs.c index e7f4fed9..5e035653 100644 --- a/modules/packetfs.c +++ b/modules/packetfs.c @@ -238,10 +238,6 @@ static void close_client(fs_node_t * node) { free(c); } -static int match_server(fs_node_t * node, void * value) { - pex_ex_t * p = (pex_ex_t *)node->device; - return fsnode_matches(p->server_pipe,value); -} static int wait_server(fs_node_t * node, void * process) { pex_ex_t * p = (pex_ex_t *)node->device; return selectwait_fs(p->server_pipe, process); @@ -251,10 +247,6 @@ static int check_server(fs_node_t * node) { return selectcheck_fs(p->server_pipe); } -static int match_client(fs_node_t * node, void * value) { - pex_client_t * c = (pex_client_t *)node->inode; - return fsnode_matches(c->pipe, value); -} static int wait_client(fs_node_t * node, void * process) { pex_client_t * c = (pex_client_t *)node->inode; return selectwait_fs(c->pipe, process); @@ -278,7 +270,6 @@ static void open_pex(fs_node_t * node, unsigned int flags) { node->ioctl = ioctl_server; node->selectcheck = check_server; node->selectwait = wait_server; - node->match = match_server; debug_print(INFO, "[pex] Server launched: %s", t->name); debug_print(INFO, "fs_node = 0x%x", node); } else if (!(flags & O_CREAT)) { @@ -292,7 +283,6 @@ static void open_pex(fs_node_t * node, unsigned int flags) { node->selectcheck = check_client; node->selectwait = wait_client; - node->match = match_client; list_insert(t->clients, client); diff --git a/userspace/gui/terminal/terminal.c b/userspace/gui/terminal/terminal.c index b78bb256..591d8c23 100644 --- a/userspace/gui/terminal/terminal.c +++ b/userspace/gui/terminal/terminal.c @@ -1074,11 +1074,13 @@ void key_event(int ret, key_event_t * event) { } } -void * wait_for_exit(void * garbage) { - int pid; - do { - pid = waitpid(-1, NULL, 0); - } while (pid == -1 && errno == EINTR); +void check_for_exit(void) { + if (exit_application) return; + + int pid = waitpid(-1, NULL, WNOHANG); + + if (pid != child_pid) return; + /* Clean up */ exit_application = 1; /* Exit */ @@ -1251,122 +1253,123 @@ void mouse_event(int button, int x, int y) { handle_input_s(buf); } -void * handle_incoming(void * garbage) { +void * handle_incoming(void) { - yutani_timer_request(yctx, 0, 0); - - while (!exit_application) { - yutani_msg_t * m = yutani_poll(yctx); - if (m) { - switch (m->type) { - case YUTANI_MSG_KEY_EVENT: - { - struct yutani_msg_key_event * ke = (void*)m->data; - int ret = (ke->event.action == KEY_ACTION_DOWN) && (ke->event.key); - key_event(ret, &ke->event); + yutani_msg_t * m = yutani_poll(yctx); + if (m) { + switch (m->type) { + case YUTANI_MSG_KEY_EVENT: + { + struct yutani_msg_key_event * ke = (void*)m->data; + int ret = (ke->event.action == KEY_ACTION_DOWN) && (ke->event.key); + key_event(ret, &ke->event); + } + break; + case YUTANI_MSG_WINDOW_FOCUS_CHANGE: + { + struct yutani_msg_window_focus_change * wf = (void*)m->data; + yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); + if (win) { + win->focused = wf->focused; + render_decors(); } - break; - case YUTANI_MSG_WINDOW_FOCUS_CHANGE: - { - struct yutani_msg_window_focus_change * wf = (void*)m->data; - yutani_window_t * win = hashmap_get(yctx->windows, (void*)wf->wid); - if (win) { - win->focused = wf->focused; - render_decors(); - } - } - break; - case YUTANI_MSG_SESSION_END: - { - kill(child_pid, SIGKILL); - exit_application = 1; - } - break; - case YUTANI_MSG_RESIZE_OFFER: - { - struct yutani_msg_window_resize * wr = (void*)m->data; - resize_finish(wr->width, wr->height); - } - break; - case YUTANI_MSG_WINDOW_MOUSE_EVENT: - { - struct yutani_msg_window_mouse_event * me = (void*)m->data; - if (!_no_frame) { - if (decor_handle_event(yctx, m) == DECOR_CLOSE) { - kill(child_pid, SIGKILL); - exit_application = 1; - break; - } - } - if (me->new_x < 0 || me->new_x >= window_width || me->new_y < 0 || me->new_y >= window_height) { + } + break; + case YUTANI_MSG_SESSION_END: + { + kill(child_pid, SIGKILL); + exit_application = 1; + } + break; + case YUTANI_MSG_RESIZE_OFFER: + { + struct yutani_msg_window_resize * wr = (void*)m->data; + resize_finish(wr->width, wr->height); + } + break; + case YUTANI_MSG_WINDOW_MOUSE_EVENT: + { + struct yutani_msg_window_mouse_event * me = (void*)m->data; + if (!_no_frame) { + if (decor_handle_event(yctx, m) == DECOR_CLOSE) { + kill(child_pid, SIGKILL); + exit_application = 1; break; } - /* Map Cursor Action */ - if (ansi_state->mouse_on) { - int new_x = me->new_x; - int new_y = me->new_y; - if (!_no_frame) { - new_x -= decor_left_width; - new_y -= decor_top_height; - } - /* Convert from coordinate to cell positon */ - new_x /= char_width; - new_y /= char_height; + } + if (me->new_x < 0 || me->new_x >= window_width || me->new_y < 0 || me->new_y >= window_height) { + break; + } + /* Map Cursor Action */ + if (ansi_state->mouse_on) { + int new_x = me->new_x; + int new_y = me->new_y; + if (!_no_frame) { + new_x -= decor_left_width; + new_y -= decor_top_height; + } + /* Convert from coordinate to cell positon */ + new_x /= char_width; + new_y /= char_height; - if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { - mouse_event(32+32, new_x, new_y); - } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { - mouse_event(32+32+1, new_x, new_y); - } + if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { + mouse_event(32+32, new_x, new_y); + } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { + mouse_event(32+32+1, new_x, new_y); + } - if (me->buttons != button_state) { - /* Figure out what changed */ - if (me->buttons & YUTANI_MOUSE_BUTTON_LEFT && !(button_state & YUTANI_MOUSE_BUTTON_LEFT)) mouse_event(0, new_x, new_y); - if (me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE && !(button_state & YUTANI_MOUSE_BUTTON_MIDDLE)) mouse_event(1, new_x, new_y); - if (me->buttons & YUTANI_MOUSE_BUTTON_RIGHT && !(button_state & YUTANI_MOUSE_BUTTON_RIGHT)) mouse_event(2, new_x, new_y); - if (!(me->buttons & YUTANI_MOUSE_BUTTON_LEFT) && button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(3, new_x, new_y); - if (!(me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE) && button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(3, new_x, new_y); - if (!(me->buttons & YUTANI_MOUSE_BUTTON_RIGHT) && button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(3, new_x, new_y); - last_mouse_x = new_x; - last_mouse_y = new_y; - button_state = me->buttons; - } else if (ansi_state->mouse_on == 2) { - /* Report motion for pressed buttons */ - if (last_mouse_x == new_x && last_mouse_y == new_y) break; - if (button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(32, new_x, new_y); - if (button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(33, new_x, new_y); - if (button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(34, new_x, new_y); - last_mouse_x = new_x; - last_mouse_y = new_y; - } - } else { - if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { - scroll_up(5); - } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { - scroll_down(5); - } + if (me->buttons != button_state) { + /* Figure out what changed */ + if (me->buttons & YUTANI_MOUSE_BUTTON_LEFT && !(button_state & YUTANI_MOUSE_BUTTON_LEFT)) mouse_event(0, new_x, new_y); + if (me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE && !(button_state & YUTANI_MOUSE_BUTTON_MIDDLE)) mouse_event(1, new_x, new_y); + if (me->buttons & YUTANI_MOUSE_BUTTON_RIGHT && !(button_state & YUTANI_MOUSE_BUTTON_RIGHT)) mouse_event(2, new_x, new_y); + if (!(me->buttons & YUTANI_MOUSE_BUTTON_LEFT) && button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(3, new_x, new_y); + if (!(me->buttons & YUTANI_MOUSE_BUTTON_MIDDLE) && button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(3, new_x, new_y); + if (!(me->buttons & YUTANI_MOUSE_BUTTON_RIGHT) && button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(3, new_x, new_y); + last_mouse_x = new_x; + last_mouse_y = new_y; + button_state = me->buttons; + } else if (ansi_state->mouse_on == 2) { + /* Report motion for pressed buttons */ + if (last_mouse_x == new_x && last_mouse_y == new_y) break; + if (button_state & YUTANI_MOUSE_BUTTON_LEFT) mouse_event(32, new_x, new_y); + if (button_state & YUTANI_MOUSE_BUTTON_MIDDLE) mouse_event(33, new_x, new_y); + if (button_state & YUTANI_MOUSE_BUTTON_RIGHT) mouse_event(34, new_x, new_y); + last_mouse_x = new_x; + last_mouse_y = new_y; + } + } else { + if (me->buttons & YUTANI_MOUSE_SCROLL_UP) { + scroll_up(5); + } else if (me->buttons & YUTANI_MOUSE_SCROLL_DOWN) { + scroll_down(5); } } - break; - case YUTANI_MSG_TIMER_TICK: - { - uint64_t ticks = get_ticks(); - if (ticks > mouse_ticks + 600000LL) { - mouse_ticks = ticks; - spin_lock(&display_lock); - flip_cursor(); - spin_unlock(&display_lock); - } + } + break; + case YUTANI_MSG_TIMER_TICK: + { + uint64_t ticks = get_ticks(); + if (ticks > mouse_ticks + 600000LL) { + mouse_ticks = ticks; + spin_lock(&display_lock); + flip_cursor(); + spin_unlock(&display_lock); } - default: - break; - } - free(m); + } + default: + break; } + free(m); } - pthread_exit(0); } +#ifndef syscall_fswait +/* TODO: This isn't in our newlib syscall bindings yet. */ +DEFN_SYSCALL2(fswait,59,int,int*); +#endif + + int main(int argc, char ** argv) { _use_freetype = 1; @@ -1546,21 +1549,28 @@ int main(int argc, char ** argv) { child_pid = f; - pthread_t wait_for_exit_thread; - pthread_create(&wait_for_exit_thread, NULL, wait_for_exit, NULL); + yutani_timer_request(yctx, 0, 0); - pthread_t handle_incoming_thread; - pthread_create(&handle_incoming_thread, NULL, handle_incoming, NULL); + int fds[2] = {fd_master, fileno(yctx->sock)}; unsigned char buf[1024]; while (!exit_application) { - int r = read(fd_master, buf, 1024); - spin_lock(&display_lock); - for (uint32_t i = 0; i < r; ++i) { - ansi_put(ansi_state, buf[i]); + + int index = syscall_fswait(2,fds); + + check_for_exit(); + + if (index == 0) { + int r = read(fd_master, buf, 1024); + spin_lock(&display_lock); + for (uint32_t i = 0; i < r; ++i) { + ansi_put(ansi_state, buf[i]); + } + display_flip(); + spin_unlock(&display_lock); + } else { + handle_incoming(); } - display_flip(); - spin_unlock(&display_lock); } }