diff --git a/repos/gems/src/server/terminal_mux/main.cc b/repos/gems/src/server/terminal_mux/main.cc index bfdf56942..381ef6914 100644 --- a/repos/gems/src/server/terminal_mux/main.cc +++ b/repos/gems/src/server/terminal_mux/main.cc @@ -13,11 +13,10 @@ /* Genode includes */ #include -#include +#include #include -#include +#include #include -#include #include #include #include @@ -82,7 +81,7 @@ struct Registry /** * Return session label */ - virtual char const *label() const = 0; + virtual Genode::Session_label const & label() const = 0; /** * Submit character into entry @@ -178,217 +177,209 @@ class Session_manager namespace Terminal { - - class Session_component : public Genode::Rpc_object, - public Registry::Entry - { - public: - - enum { LABEL_MAX_LEN = 128 }; - - private: - - Read_buffer _read_buffer; - - Ncurses &_ncurses; - Ncurses::Window &_window; - - struct Label - { - char buf[LABEL_MAX_LEN]; - - Label(char const *label) - { - Genode::strncpy(buf, label, sizeof(buf)); - } - } _label; - - Session_manager &_session_manager; - - Genode::Attached_ram_dataspace _io_buffer; - - Cell_array _char_cell_array; - Char_cell_array_character_screen _char_cell_array_character_screen; - Terminal::Decoder _decoder; - - Terminal::Position _last_cursor_pos; - - - public: - - /** - * Constructor - */ - Session_component(Genode::size_t io_buffer_size, - Ncurses &ncurses, - Session_manager &session_manager, - char const *label) - : - _ncurses(ncurses), - _window(*ncurses.create_window(0, 1, ncurses.columns(), ncurses.lines() - 1)), - _label(label), - _session_manager(session_manager), - _io_buffer(Genode::env()->ram_session(), io_buffer_size), - _char_cell_array(ncurses.columns(), ncurses.lines() - 1, - Genode::env()->heap()), - _char_cell_array_character_screen(_char_cell_array), - _decoder(_char_cell_array_character_screen) - { - _session_manager.add(this); - } - - ~Session_component() - { - _session_manager.remove(this); - _ncurses.destroy_window(&_window); - } - - - /******************************* - ** Registry::Entry interface ** - *******************************/ - - void flush() - { - convert_char_array_to_window(&_char_cell_array, _window); - - int first_dirty_line = 10000, - last_dirty_line = -10000; - - for (int line = 0; line < (int)_char_cell_array.num_lines(); line++) { - if (!_char_cell_array.line_dirty(line)) continue; - - first_dirty_line = Genode::min(line, first_dirty_line); - last_dirty_line = Genode::max(line, last_dirty_line); - - _char_cell_array.mark_line_as_clean(line); - } - - Terminal::Position cursor_pos = - _char_cell_array_character_screen.cursor_pos(); - _window.move_cursor(cursor_pos.x, cursor_pos.y); - - _window.refresh(); - } - - void flush_all() - { - for (unsigned line = 0; line < _char_cell_array.num_lines(); line++) - _char_cell_array.mark_line_as_dirty(line); - - _window.erase(); - flush(); - } - - char const *label() const - { - return _label.buf; - } - - void submit_input(char c) - { - _read_buffer.add(c); - } - - - /******************************** - ** Terminal session interface ** - ********************************/ - - Size size() { return Size(_char_cell_array.num_cols(), - _char_cell_array.num_lines()); } - - bool avail() { return !_read_buffer.empty(); } - - Genode::size_t _read(Genode::size_t dst_len) - { - /* read data, block on first byte if needed */ - unsigned num_bytes = 0; - unsigned char *dst = _io_buffer.local_addr(); - Genode::size_t dst_size = Genode::min(_io_buffer.size(), dst_len); - do { - dst[num_bytes++] = _read_buffer.get(); - } while (!_read_buffer.empty() && num_bytes < dst_size); - - return num_bytes; - } - - void _write(Genode::size_t num_bytes) - { - unsigned char *src = _io_buffer.local_addr(); - - for (unsigned i = 0; i < num_bytes; i++) { - - /* submit character to sequence decoder */ - _decoder.insert(src[i]); - } - } - - Genode::Dataspace_capability _dataspace() - { - return _io_buffer.cap(); - } - - void connected_sigh(Genode::Signal_context_capability sigh) - { - /* - * Immediately reflect connection-established signal to the - * client because the session is ready to use immediately after - * creation. - */ - Genode::Signal_transmitter(sigh).submit(); - } - - void read_avail_sigh(Genode::Signal_context_capability cap) - { - _read_buffer.sigh(cap); - } - - Genode::size_t read(void *buf, Genode::size_t) { return 0; } - Genode::size_t write(void const *buf, Genode::size_t) { return 0; } - }; - - - class Root_component : public Genode::Root_component - { - private: - - Ncurses &_ncurses; - Session_manager &_session_manager; - - protected: - - Session_component *_create_session(const char *args) - { - /* - * XXX read I/O buffer size from args - */ - Genode::size_t io_buffer_size = 4096; - - char label[Session_component::LABEL_MAX_LEN]; - Genode::Arg_string::find_arg(args, "label").string(label, sizeof(label), ""); - - return new (md_alloc()) - Session_component(io_buffer_size, _ncurses, _session_manager, label); - } - - public: - - /** - * Constructor - */ - Root_component(Genode::Rpc_entrypoint &ep, - Genode::Allocator &md_alloc, - Ncurses &ncurses, - Session_manager &session_manager) - : - Genode::Root_component(&ep, &md_alloc), - _ncurses(ncurses), - _session_manager(session_manager) - { } - }; + class Session_component; + class Root_component; } +class Terminal::Session_component : public Genode::Rpc_object, + public Registry::Entry +{ + private: + + Genode::Env &_env; + + Read_buffer _read_buffer; + + Ncurses &_ncurses; + Ncurses::Window &_window; + + Genode::Session_label const _label; + + Session_manager &_session_manager; + + Genode::Attached_ram_dataspace _io_buffer; + + Cell_array _char_cell_array; + Char_cell_array_character_screen _char_cell_array_character_screen; + Terminal::Decoder _decoder; + + Terminal::Position _last_cursor_pos; + + public: + + Session_component(Genode::size_t io_buffer_size, + Ncurses &ncurses, + Session_manager &session_manager, + Genode::Session_label const &label, + Genode::Env &env, + Genode::Allocator &heap) + : + _env(env), + _ncurses(ncurses), + _window(*ncurses.create_window(0, 1, ncurses.columns(), ncurses.lines() - 1)), + _label(label), + _session_manager(session_manager), + _io_buffer(_env.ram(), _env.rm(), io_buffer_size), + _char_cell_array(ncurses.columns(), ncurses.lines() - 1, &heap), + _char_cell_array_character_screen(_char_cell_array), + _decoder(_char_cell_array_character_screen) + { + _session_manager.add(this); + } + + ~Session_component() + { + _session_manager.remove(this); + _ncurses.destroy_window(&_window); + } + + + /******************************* + ** Registry::Entry interface ** + *******************************/ + + void flush() override + { + convert_char_array_to_window(&_char_cell_array, _window); + + int first_dirty_line = 10000, + last_dirty_line = -10000; + + for (int line = 0; line < (int)_char_cell_array.num_lines(); line++) { + if (!_char_cell_array.line_dirty(line)) continue; + + first_dirty_line = Genode::min(line, first_dirty_line); + last_dirty_line = Genode::max(line, last_dirty_line); + + _char_cell_array.mark_line_as_clean(line); + } + + Terminal::Position cursor_pos = + _char_cell_array_character_screen.cursor_pos(); + _window.move_cursor(cursor_pos.x, cursor_pos.y); + + _window.refresh(); + } + + void flush_all() override + { + for (unsigned line = 0; line < _char_cell_array.num_lines(); line++) + _char_cell_array.mark_line_as_dirty(line); + + _window.erase(); + flush(); + } + + Genode::Session_label const & label() const override { return _label; } + + void submit_input(char c) override { _read_buffer.add(c); } + + + /******************************** + ** Terminal session interface ** + ********************************/ + + Size size() override { return Size(_char_cell_array.num_cols(), + _char_cell_array.num_lines()); } + + bool avail() override { return !_read_buffer.empty(); } + + Genode::size_t _read(Genode::size_t dst_len) + { + /* read data, block on first byte if needed */ + unsigned num_bytes = 0; + unsigned char *dst = _io_buffer.local_addr(); + Genode::size_t dst_size = Genode::min(_io_buffer.size(), dst_len); + do { + dst[num_bytes++] = _read_buffer.get(); + } while (!_read_buffer.empty() && num_bytes < dst_size); + + return num_bytes; + } + + void _write(Genode::size_t num_bytes) + { + unsigned char *src = _io_buffer.local_addr(); + + for (unsigned i = 0; i < num_bytes; i++) { + + /* submit character to sequence decoder */ + _decoder.insert(src[i]); + } + } + + Genode::Dataspace_capability _dataspace() + { + return _io_buffer.cap(); + } + + void connected_sigh(Genode::Signal_context_capability sigh) override + { + /* + * Immediately reflect connection-established signal to the + * client because the session is ready to use immediately after + * creation. + */ + Genode::Signal_transmitter(sigh).submit(); + } + + void read_avail_sigh(Genode::Signal_context_capability cap) override + { + _read_buffer.sigh(cap); + } + + Genode::size_t read(void *buf, Genode::size_t) override { return 0; } + Genode::size_t write(void const *buf, Genode::size_t) override { return 0; } +}; + + +class Terminal::Root_component : public Genode::Root_component +{ + private: + + Genode::Env &_env; + Ncurses &_ncurses; + Session_manager &_session_manager; + + /* + * FIXME The heap is shared between all clients. The allocator should + * be moved into the session component but this increases per-session + * RAM costs significantly, which would break all connections to this + * server. + */ + Genode::Heap _heap { _env.ram(), _env.rm() }; + + protected: + + Session_component *_create_session(const char *args) + { + /* + * XXX read I/O buffer size from args + */ + Genode::size_t io_buffer_size = 4096; + + return new (md_alloc()) + Session_component(io_buffer_size, _ncurses, _session_manager, + Genode::label_from_args(args), _env, _heap); + } + + public: + + /** + * Constructor + */ + Root_component(Genode::Env &env, + Genode::Allocator &md_alloc, + Ncurses &ncurses, + Session_manager &session_manager) + : + Genode::Root_component(env.ep(), md_alloc), + _env(env), + _ncurses(ncurses), + _session_manager(session_manager) + { } +}; + class Status_window { @@ -397,32 +388,27 @@ class Status_window Ncurses &_ncurses; Ncurses::Window &_window; - char _label[Terminal::Session_component::LABEL_MAX_LEN]; - public: Status_window(Ncurses &ncurses) : _ncurses(ncurses), _window(*_ncurses.create_window(0, 0, ncurses.columns(), 1)) - { - _label[0] = 0; - } + { } ~Status_window() { _ncurses.destroy_window(&_window); } - void label(char const *label) + void label(Genode::Session_label const &label) { - Genode::strncpy(_label, label, sizeof(_label)); - _window.erase(); _window.move_cursor(0, 0); _window.print_char('[', false, false); unsigned const max_columns = _ncurses.columns() - 2; + char const *_label = label.string(); for (unsigned i = 0; i < max_columns && _label[i]; i++) _window.print_char(_label[i], false, false); @@ -443,6 +429,8 @@ class Menu : public Registry::Entry unsigned _selected_idx; unsigned _max_idx; + Genode::Session_label const _label { "-" }; + /** * State tracker for escape sequences within user input * @@ -523,9 +511,9 @@ class Menu : public Registry::Entry void reset_selection() { _selected_idx = 0; } - void flush() { } + void flush() override { } - void flush_all() + void flush_all() override { _window.erase(); @@ -546,7 +534,7 @@ class Menu : public Registry::Entry unsigned const padding = 2; _window.move_cursor(padding, 1 + i); - char const *label = entry->label(); + char const *label = entry->label().string(); for (unsigned j = 0; j < (max_columns - padding) && label[j]; j++) _window.print_char(label[j], highlight, highlight); } @@ -555,7 +543,7 @@ class Menu : public Registry::Entry _window.refresh(); } - char const *label() const { return "-"; } + Genode::Session_label const & label() const { return _label; } void submit_input(char c) { @@ -666,37 +654,47 @@ void Session_manager::remove(Registry::Entry *entry) } -/******************* - ** Input handler ** - *******************/ +/*************** + ** Component ** + ***************/ -struct Input_handler +struct Main { - GENODE_RPC(Rpc_handle_input, void, handle); - GENODE_RPC_INTERFACE(Rpc_handle_input); -}; + Genode::Env &env; + Genode::Sliced_heap sliced_heap { env.ram(), env.rm() }; -struct Input_handler_component : Genode::Rpc_object -{ - User_input &_user_input; - Session_manager &_session_manager; + Registry registry; + Ncurses ncurses; + Status_window status_window { ncurses }; + Menu menu { ncurses, registry, status_window }; + User_input user_input { ncurses }; + Session_manager session_manager { ncurses, registry, status_window, menu }; - Input_handler_component(User_input &user_input, - Session_manager &session_manager) - : - _user_input(user_input), - _session_manager(session_manager) + Terminal::Root_component root { env, sliced_heap, ncurses, session_manager }; + + Timer::Connection timer { env }; + + Genode::Signal_handler
timer_handler { env.ep(), *this, &Main::handle_timer }; + + Main(Genode::Env &env) : env(env) { - _session_manager.activate_menu(); + Genode::log("--- terminal_mux service started ---"); + + registry.add(&menu); + session_manager.activate_menu(); + + env.parent().announce(env.ep().manage(root)); + + timer.sigh(timer_handler); + timer.trigger_periodic(10*1000); } - void handle() + void handle_timer() { for (;;) { - int c = _user_input.read_character(); + int c = user_input.read_character(); if (c == -1) break; @@ -712,55 +710,16 @@ struct Input_handler_component : Genode::Rpc_objectram_session(), env()->rm_session()); - - static ::Registry registry; - static Ncurses ncurses; - static Status_window status_window(ncurses); - static Menu menu(ncurses, registry, status_window); - - registry.add(&menu); - - static User_input user_input(ncurses); - static Session_manager session_manager(ncurses, registry, status_window, menu); - - /* create root interface for service */ - static Terminal::Root_component root(ep, sliced_heap, ncurses, session_manager); - - static Input_handler_component input_handler(user_input, session_manager); - Capability input_handler_cap = ep.manage(&input_handler); - - /* announce service at our parent */ - env()->parent()->announce(ep.manage(&root)); - - while (1) { - static Timer::Connection timer; - timer.msleep(10); - - input_handler_cap.call(); - } - return 0; -} +Genode::size_t Component::stack_size() { return 4096*sizeof(long); } +void Component::construct(Genode::Env &env) { static Main inst(env); }