From a22ce4091140ee10ec795827317e392b80956bd9 Mon Sep 17 00:00:00 2001 From: Raphael Fuchs Date: Wed, 26 Jun 2013 20:26:31 +0200 Subject: [PATCH] libbarrelfish: Adjust libbarrelfish to new terminal API and remove old API. --- errors/errno.fugu | 2 - hake/ArchDefaults.hs | 1 + include/barrelfish/terminal.h | 30 +--- lib/barrelfish/Hakefile | 12 +- lib/barrelfish/init.c | 11 +- lib/barrelfish/terminal.c | 422 +++++------------------------------------ 6 files changed, 75 insertions(+), 403 deletions(-) diff --git a/errors/errno.fugu b/errors/errno.fugu index e3d9845..e85f86e 100644 --- a/errors/errno.fugu +++ b/errors/errno.fugu @@ -338,8 +338,6 @@ errors libbarrelfish LIB_ERR_ { failure GET_NAME_IREF "Error while retrieving name service IREF from monitor", failure GET_RAMFS_IREF "Error while retrieving ramfsd service IREF from monitor", failure NAMESERVICE_CLIENT_INIT "Failure initialising nameservice client", - failure SERIAL_BIND "Failed binding to serial driver", - failure KBD_BIND "Failed binding to keyboard driver", // Threads package failure THREAD_CREATE "A version of thread create failed", diff --git a/hake/ArchDefaults.hs b/hake/ArchDefaults.hs index cdde8a7..882bf84 100644 --- a/hake/ArchDefaults.hs +++ b/hake/ArchDefaults.hs @@ -84,6 +84,7 @@ ldCxxFlags arch = -- Libraries that are linked to all applications. stdLibs arch = [ In InstallTree arch "/lib/libbarrelfish.a", + In InstallTree arch "/lib/libterm_client.a", In InstallTree arch "/lib/liboctopus_parser.a", -- XXX: For NS client in libbarrelfish In InstallTree arch "/errors/errno.o", In InstallTree arch ("/lib/lib" ++ Config.libc ++ ".a"), diff --git a/include/barrelfish/terminal.h b/include/barrelfish/terminal.h index 0179c29..713e06b 100644 --- a/include/barrelfish/terminal.h +++ b/include/barrelfish/terminal.h @@ -4,44 +4,28 @@ */ /* - * Copyright (c) 2007, 2008, ETH Zurich. + * Copyright (c) 2007, 2008, 2012, ETH Zurich. * All rights reserved. * * This file is distributed under the terms in the attached LICENSE file. * If you do not find this file, copies can be found by writing to: - * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. + * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, + * Attn: Systems Group. */ -#ifndef TERMINAL_H -#define TERMINAL_H +#ifndef BARRELFISH_TERMINAL_H +#define BARRELFISH_TERMINAL_H #include __BEGIN_DECLS -/** - * \brief Callback function to be called when input arrives at the terminal. - * - * This function must not alter the input string. - */ -typedef void (*terminal_input_handler) (void * user_data, const char *data, - size_t length); - -errval_t terminal_register_input_handler (terminal_input_handler handler, - void * user_data); -void terminal_unregister_input_handler (terminal_input_handler handler); - size_t terminal_write(const char *data, size_t length); size_t terminal_read(char *data, size_t count); -void terminal_input(char *data, size_t length); errval_t terminal_init(void); -errval_t terminal_want_stdin(unsigned int sources); - -// XXX: arguments to terminal_want_stdin (bitmask) -#define TERMINAL_SOURCE_SERIAL 0x1 -#define TERMINAL_SOURCE_KEYBOARD 0x2 +void terminal_exit(void); __END_DECLS -#endif +#endif // BARRELFISH_TERMINAL_H diff --git a/lib/barrelfish/Hakefile b/lib/barrelfish/Hakefile index f07f706..bd64603 100644 --- a/lib/barrelfish/Hakefile +++ b/lib/barrelfish/Hakefile @@ -1,10 +1,11 @@ -------------------------------------------------------------------------- --- Copyright (c) 2007-2011, ETH Zurich +-- Copyright (c) 2007-2012, ETH Zurich -- All rights reserved. -- -- This file is distributed under the terms in the attached LICENSE file. -- If you do not find this file, copies can be found by writing to: --- ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. +-- ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, +-- Attn: Systems Group. -- -- Hakefile for lib/barrelfish -- @@ -74,16 +75,15 @@ cFiles = arch_srcs arch ++ archfam_srcs (archFamily arch) ++ common_srcs ++ idc_srcs, assemblyFiles = arch_assembly (archFamily arch), - flounderBindings = [ "mem", "octopus", "serial", - "interdisp", "spawn", "keyboard" ], + flounderBindings = [ "mem", "octopus", "interdisp", "spawn", + "terminal" ], -- only makes sense to compile monitor binding for lmp flounderTHCStubs = [ "octopus" ], flounderExtraBindings = [ ("monitor", ["lmp"]), ("monitor_blocking", ["lmp", "rpcclient"]), ("mem", ["rpcclient"]), ("octopus", ["rpcclient"]), - ("spawn", ["rpcclient"]), - ("serial", ["rpcclient"])], + ("spawn", ["rpcclient"])], addIncludes = [ "include", "include" ./. arch_dir ], addGeneratedDependencies = [ "/include/asmoffsets.h" ] } diff --git a/lib/barrelfish/init.c b/lib/barrelfish/init.c index d3de66b..08504c6 100644 --- a/lib/barrelfish/init.c +++ b/lib/barrelfish/init.c @@ -9,7 +9,8 @@ * * This file is distributed under the terms in the attached LICENSE file. * If you do not find this file, copies can be found by writing to: - * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. + * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, + * Attn: Systems Group. */ #include @@ -43,6 +44,12 @@ void libc_exit(int); void libc_exit(int status) { + errval_t err; + + if (!init_domain) { + terminal_exit(); + } + // Use spawnd if spawned through spawnd if(disp_get_domain_id() == 0) { errval_t err = cap_revoke(cap_dispatcher); @@ -55,7 +62,7 @@ void libc_exit(int status) // XXX: Leak all other domain allocations } else { - errval_t err = spawn_exit(status); + err = spawn_exit(status); if(err_is_fail(err)) { DEBUG_ERR(err, "spawn_exit"); } diff --git a/lib/barrelfish/terminal.c b/lib/barrelfish/terminal.c index 30e0cd4..bb63c9e 100644 --- a/lib/barrelfish/terminal.c +++ b/lib/barrelfish/terminal.c @@ -4,421 +4,103 @@ */ /* - * Copyright (c) 2007, 2008, 2010, ETH Zurich. + * Copyright (c) 2007, 2008, 2010, 2012, ETH Zurich. * All rights reserved. * * This file is distributed under the terms in the attached LICENSE file. * If you do not find this file, copies can be found by writing to: - * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. + * ETH Zurich D-INFK, CAB F.78, Universitaetstr. 6, CH-8092 Zurich, + * Attn: Systems Group. */ +#include + #include -#include #include -#include -#include -#include -#include - -#define BUFSIZE 256 -#define MAX_INPUT_HANDLERS 10 - -struct input_handler { - terminal_input_handler f; - void *user_data; -}; +#include struct terminal_state { - bool want_stdin, serial_bound, kbd_bound; - struct thread_mutex mutex; - struct serial_binding *serial; - struct keyboard_binding *kbd; - struct waitset waitset; - - /* input */ - char stdin_buf[BUFSIZE]; - unsigned int produced; - unsigned int consumed; -}; - -// this table maps keyboard scan codes to input characters -// XXX: this is completely bogus. we need termcap etc. -static char scancode_map[] = { - [0x1E] = 'a', - [0x30] = 'b', - [0x2E] = 'c', - [0x20] = 'd', - [0x12] = 'e', - [0x21] = 'f', - [0x22] = 'g', - [0x23] = 'h', - [0x17] = 'i', - [0x24] = 'j', - [0x25] = 'k', - [0x26] = 'l', - [0x32] = 'm', - [0x31] = 'n', - [0x18] = 'o', - [0x19] = 'p', - [0x10] = 'q', - [0x13] = 'r', - [0x1F] = 's', - [0x14] = 't', - [0x16] = 'u', - [0x2F] = 'v', - [0x11] = 'w', - [0x2D] = 'x', - [0x15] = 'y', - [0x2C] = 'z', - [0x02] = '1', - [0x03] = '2', - [0x04] = '3', - [0x05] = '4', - [0x06] = '5', - [0x07] = '6', - [0x08] = '7', - [0x09] = '8', - [0x0a] = '9', - [0x0b] = '0', - [0x0c] = '_', // XXX: really -, but this is more useful :) - [0x0d] = '=', - [0x1a] = '[', - [0x1b] = ']', - [0x2b] = '\\', - [0x27] = ';', - [0x28] = '\'', - [0x29] = '`', - [0x33] = ',', - [0x34] = '.', - [0x35] = '/', - - // control characters - [0x0e] = 0x08, // back-space / delete? - [0x1c] = '\r', // enter - [0x01] = 0x1b, // escape - [0x39] = ' ', // space - [0x0f] = '\t', // tab1 -}; - -static struct input_handler input_handlers[MAX_INPUT_HANDLERS]; - -static void handle_stdin(struct serial_binding *b, char *data, size_t len) -{ - terminal_input(data, len); - free(data); -} - -static struct serial_rx_vtbl serial_rx_vtbl = { - .input = handle_stdin, -}; - -static void handle_key_event(struct keyboard_binding *b, uint8_t scancode, - bool extended) -{ - char sc = scancode < sizeof(scancode_map) ? scancode_map[scancode] : 0; - if (sc) { - terminal_input(&sc, 1); - } -} - -static struct keyboard_rx_vtbl keyboard_rx_vtbl = { - .key_event = handle_key_event, + /** + * Is domain part of a session or a daemon? + */ + bool session_domain; + + /** + * Terminal device used from stdin, stdout and stderr. + */ + struct term_client client; }; -/// Filter output for serial driver -// just converts \n to \r\n for the moment -static void filter_output(char *outbuf, size_t outbuflen, - const char *in, size_t inlen) -{ - while (inlen--) { - char c = *in++; - if (c == '\n') { - assert(outbuflen--); - *outbuf++ = '\r'; - } - assert(outbuflen--); - *outbuf++ = c; - } -} - -/// Returns length of buffer required by filter_output() -static size_t filter_output_len(const char *in, size_t inlen) -{ - size_t outlen = 0; - while (inlen--) { - outlen++; - if (*in++ == '\n') { - outlen++; - } - } - return outlen; -} - -static void serial_write(struct terminal_state *st, - const char *data, size_t inlen) -{ - assert(st != NULL); - assert(st->serial != NULL); - errval_t err; - - size_t outlen = filter_output_len(data, inlen); - // check sane size for buffer on stack; after all, this is the terminal! - assert(outlen <= 4096); - char outbuf[outlen]; - filter_output(outbuf, outlen, data, inlen); - - // try to send - assert(st->serial->can_send(st->serial)); - err = st->serial->tx_vtbl.output(st->serial, NOP_CONT, outbuf, outlen); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "error sending terminal output to serial driver"); - } - - // block on output completion. - // this is necessary to maintain libc buffering semantics, and prevent - // output being lost if a dispatcher exit()s after a printf - while (!st->serial->can_send(st->serial)) { - err = event_dispatch(&st->waitset); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "error in event_dispatch on terminal waitset"); - } - } -} - size_t terminal_write(const char *data, size_t length) { + errval_t err; + size_t written = 0; struct terminal_state *state = get_terminal_state(); - if (length > 0) { - assert(data != NULL); - - if (state != NULL && state->serial != NULL) { - thread_mutex_lock(&state->mutex); - serial_write(state, data, length); - thread_mutex_unlock(&state->mutex); - } else { - sys_print(data, length); - } + if (state != NULL && state->session_domain) { + err = term_client_blocking_write(&state->client, data, length, + &written); + assert(err_is_ok(err)); + return written; + } else { + sys_print(data, length); + return length; } - - return length; } size_t terminal_read(char *data, size_t count) { - struct terminal_state *state = get_terminal_state(); errval_t err; - size_t i; - - thread_mutex_lock(&state->mutex); - - for(i = 0; i < count; i++) { - while(state->consumed == state->produced) { - err = event_dispatch(&state->waitset); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "error in event_dispatch on terminal waitset"); - } - } - - data[i] = state->stdin_buf[(state->consumed++) % BUFSIZE]; - } - - thread_mutex_unlock(&state->mutex); - - return count; -} - -void terminal_input(char *data, size_t length) -{ + size_t read = 0; struct terminal_state *state = get_terminal_state(); - for (size_t i = 0; i < length; i++) { - /* XXX: translate \r to \n in place */ - if (data[i] == '\r') { - data[i] = '\n'; - } - - state->stdin_buf[(state->produced++) % BUFSIZE] = data[i]; - assert(state->produced != state->consumed); // FIXME! - } - - for (int i = 0; i < MAX_INPUT_HANDLERS; i++) { - if (input_handlers[i].f != NULL) { - input_handlers[i].f(input_handlers[i].user_data, data, length); - } - } -} - -static void serial_bind_cb(void *st, errval_t err, struct serial_binding *b) -{ - struct terminal_state *state = st; - - if (err_is_ok(err)) { - b->rx_vtbl = serial_rx_vtbl; - b->st = state; - state->serial = b; - if (state->want_stdin) { - err = b->tx_vtbl.associate_stdin(b, NOP_CONT); - assert(err_is_ok(err)); // XXX: can fail!! - } - } else { - state->serial_bound = false; - USER_PANIC_ERR(err, "error binding to serial driver"); - } -} - -static void keyboard_bind_cb(void *st, errval_t err, struct keyboard_binding *b) -{ - struct terminal_state *state = st; - - if (err_is_ok(err)) { - b->rx_vtbl = keyboard_rx_vtbl; - b->st = state; - state->kbd = b; + if (state->session_domain) { + err = term_client_blocking_read(&state->client, data, count, &read); + assert(err_is_ok(err)); + return read; } else { - state->kbd_bound = false; - USER_PANIC_ERR(err, "error binding to keyboard driver"); + /** + * Only domains that are part of a session can read from a terminal + * device. + */ + assert(!"Daemons can't read from a terminal."); } } errval_t terminal_init(void) { - memset(input_handlers, 0, sizeof(input_handlers)); + errval_t err; + struct capability cap; - /* Allocate and initialize dispatcher-specific state */ + /* Allocate and initialize dispatcher-specific state. */ struct terminal_state *state = malloc(sizeof(struct terminal_state)); if (!state) { return LIB_ERR_MALLOC_FAIL; } set_terminal_state(state); - thread_mutex_init(&state->mutex); - state->want_stdin = false; - state->serial_bound = false; - state->kbd_bound = false; - state->produced = state->consumed = 0; - state->serial = NULL; - waitset_init(&state->waitset); - - iref_t iref; - errval_t err; - /* Connect to serial driver if possible */ - err = nameservice_lookup("serial", &iref); - if (err_is_fail(err)) { - if (err_no(err) == LIB_ERR_NAMESERVICE_UNKNOWN_NAME) { - // serial not present, ignore it and continue - return SYS_ERR_OK; - } else { + /* Check if domain is part of a session. */ + err = debug_cap_identify(cap_sessionid, &cap); + if (err_is_ok(err)) { + /* Initialize libterm_client. */ + err = term_client_blocking_init(&state->client, cap_sessionid); + if (err_is_fail(err)) { return err; } - } - err = serial_bind(iref, serial_bind_cb, state, &state->waitset, - IDC_BIND_FLAGS_DEFAULT); - if (err_is_fail(err)) { - return err_push(err, LIB_ERR_SERIAL_BIND); + state->session_domain = true; + return SYS_ERR_OK; + } else { + state->session_domain = false; + return SYS_ERR_OK; } - - state->serial_bound = true; - - return SYS_ERR_OK; } -errval_t terminal_want_stdin(unsigned sources) +void terminal_exit(void) { struct terminal_state *state = get_terminal_state(); - assert(state != NULL); - - iref_t iref; - errval_t err; - - thread_mutex_lock(&state->mutex); - - state->want_stdin = true; - - if ((sources & TERMINAL_SOURCE_SERIAL) && !state->serial_bound) { - // didn't connect at init time, try again, blocking on the lookup - err = nameservice_blocking_lookup("serial", &iref); - if (err_is_fail(err)) { - goto out; - } - - err = serial_bind(iref, serial_bind_cb, state, &state->waitset, - IDC_BIND_FLAGS_DEFAULT); - if (err_is_fail(err)) { - err = err_push(err, LIB_ERR_SERIAL_BIND); - goto out; - } - state->serial_bound = true; - } - // connect to keyboard driver if desired - if ((sources & TERMINAL_SOURCE_KEYBOARD) && !state->kbd_bound) { - err = nameservice_blocking_lookup("keyboard", &iref); - if (err_is_fail(err)) { - goto out; - } - - err = keyboard_bind(iref, keyboard_bind_cb, state, - &state->waitset, IDC_BIND_FLAGS_DEFAULT); - if (err_is_fail(err)) { - err = err_push(err, LIB_ERR_KBD_BIND); - goto out; - } - state->kbd_bound = true; - } - - // XXX: I don't believe this waiting is correct. It changes this from a - // non-blocking to a blocking API call. The caller should dispatch - // the default waitset, and the bind will eventually complete. -AB - while ((sources & TERMINAL_SOURCE_SERIAL) && state->serial == NULL) { - err = event_dispatch(get_default_waitset()); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "event_dispatch on default waitset failed."); - } - } - - if (sources & TERMINAL_SOURCE_SERIAL && state->serial != NULL) { - err = state->serial->tx_vtbl.associate_stdin(state->serial, NOP_CONT); - if (err_is_fail(err)) { - USER_PANIC_ERR(err, "sending associate_stdin failed"); - } - } - - err = SYS_ERR_OK; - - out: - thread_mutex_unlock(&state->mutex); - - return err; -} - -/** - * \brief Register a handler to be called when input arrives at the terminal. - */ -errval_t terminal_register_input_handler (terminal_input_handler handler, - void * user_data) -{ - for (int i = 0; i < MAX_INPUT_HANDLERS; i++) { - if (input_handlers[i].f == NULL) { - input_handlers[i].f = handler; - input_handlers[i].user_data = user_data; - return SYS_ERR_OK; - } - } - - return TERM_ERR_REGISTER_HANDLER; -} - -/** - * \brief Unregister a previously registered input handler. - */ -void terminal_unregister_input_handler (terminal_input_handler handler) -{ - for (int i = 0; i < MAX_INPUT_HANDLERS; i++) { - if (input_handlers[i].f == handler) { - input_handlers[i].f = NULL; - input_handlers[i].user_data = NULL; - } + if (state != NULL && state->session_domain) { + term_client_blocking_exit(&state->client); } } -- 1.7.2.5