diff --git a/os/include/os/attached_dataspace.h b/os/include/os/attached_dataspace.h new file mode 100644 index 0000000000..87b104491d --- /dev/null +++ b/os/include/os/attached_dataspace.h @@ -0,0 +1,83 @@ +/* + * \brief Dataspace utility + * \author Norman Feske + * \date 2014-01-10 + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__OS__ATTACHED_DATASPACE_H_ +#define _INCLUDE__OS__ATTACHED_DATASPACE_H_ + +#include <dataspace/client.h> +#include <base/env.h> + +namespace Genode { class Attached_dataspace; } + + +class Genode::Attached_dataspace : Noncopyable +{ + public: + + /** + * Exception type + */ + class Invalid_dataspace { }; + + private: + + Dataspace_capability _ds; + + size_t const _size = { Dataspace_client(_ds).size() }; + + void * const _local_addr = { env()->rm_session()->attach(_ds) }; + + Dataspace_capability _check(Dataspace_capability ds) + { + if (ds.valid()) + return ds; + + throw Invalid_dataspace(); + } + + public: + + /** + * Constructor + * + * \throw Rm_session::Attach_failed + * \throw Invalid_dataspace + */ + Attached_dataspace(Dataspace_capability ds) : _ds(_check(ds)) { } + + /** + * Destructor + */ + ~Attached_dataspace() { env()->rm_session()->detach(_local_addr); } + + /** + * Return capability of the used dataspace + */ + Dataspace_capability cap() const { return _ds; } + + /** + * Request local address + * + * This is a template to avoid inconvenient casts at the caller. + * A newly attached dataspace is untyped memory anyway. + */ + template <typename T> + T *local_addr() { return static_cast<T *>(_local_addr); } + + /** + * Return size + */ + size_t size() const { return _size; } +}; + +#endif /* _INCLUDE__OS__ATTACHED_DATASPACE_H_ */ diff --git a/os/include/os/attached_rom_dataspace.h b/os/include/os/attached_rom_dataspace.h index cebdc458d4..f86182b4a7 100644 --- a/os/include/os/attached_rom_dataspace.h +++ b/os/include/os/attached_rom_dataspace.h @@ -14,93 +14,65 @@ #ifndef _INCLUDE__OS__ATTACHED_ROM_DATASPACE_H_ #define _INCLUDE__OS__ATTACHED_ROM_DATASPACE_H_ +#include <util/volatile_object.h> +#include <os/attached_dataspace.h> #include <rom_session/connection.h> -#include <dataspace/client.h> -#include <base/env.h> -namespace Genode { +namespace Genode { class Attached_rom_dataspace; } - class Attached_rom_dataspace - { - private: - Rom_connection _rom; - Rom_dataspace_capability _ds; - size_t _size; - void *_local_addr = 0; +class Genode::Attached_rom_dataspace +{ + private: - void _detach() - { - if (!_local_addr) - return; + Rom_connection _rom; - env()->rm_session()->detach(_local_addr); - _local_addr = 0; - _size = 0; - } + /* + * A ROM module may change or disappear over the lifetime of a ROM + * session. In contrast to the plain 'Attached_dataspace', which is + * always be valid once constructed, a 'Attached_rom_dataspace' has + * to handle the validity of the dataspace. + */ + Lazy_volatile_object<Attached_dataspace> _ds; - void _attach() - { - if (_local_addr) - _detach(); + /** + * Try to attach the ROM module, ignore invalid dataspaces + */ + void _try_attach() + { + try { _ds.construct(_rom.dataspace()); } + catch (Attached_dataspace::Invalid_dataspace) { } + } - _ds = _rom.dataspace(); - if (_ds.valid()) { - _size = Dataspace_client(_ds).size(); - _local_addr = env()->rm_session()->attach(_ds); - } - } + public: - public: + /** + * Constructor + * + * \throw Rom_connection::Rom_connection_failed + * \throw Rm_session::Attach_failed + */ + Attached_rom_dataspace(char const *name) + : _rom(name) { _try_attach(); } - /** - * Constructor - * - * \throw Rom_connection::Rom_connection_failed - * \throw Rm_session::Attach_failed - */ - Attached_rom_dataspace(char const *name) - : _rom(name) { _attach(); } + template <typename T> T *local_addr() { return _ds->local_addr<T>(); } - /** - * Destructor - */ - ~Attached_rom_dataspace() { _detach(); } + size_t size() const { return _ds->size(); } - /** - * Return capability of the used ROM dataspace - */ - Rom_dataspace_capability cap() const { return _ds; } + /** + * Register signal handler for ROM module changes + */ + void sigh(Signal_context_capability sigh) { _rom.sigh(sigh); } - /** - * Request local address - * - * This is a template to avoid inconvenient casts at the caller. - * A newly allocated ROM dataspace is untyped memory anyway. - */ - template <typename T> - T *local_addr() { return static_cast<T *>(_local_addr); } + /** + * Re-attach ROM module + */ + void update() { _try_attach(); } - /** - * Return size - */ - size_t size() const { return _size; } - - /** - * Register signal handler for ROM module changes - */ - void sigh(Signal_context_capability sigh) { _rom.sigh(sigh); } - - /** - * Re-attach ROM module - */ - void update() { _attach(); } - - /** - * Return true of content is present - */ - bool is_valid() const { return _local_addr != 0; } - }; -} + /** + * Return true of content is present + */ + bool is_valid() const { return _ds.is_constructed(); } +}; #endif /* _INCLUDE__OS__ATTACHED_ROM_DATASPACE_H_ */ diff --git a/os/include/terminal_session/client.h b/os/include/terminal_session/client.h index 7d8b5212a1..32b868acae 100644 --- a/os/include/terminal_session/client.h +++ b/os/include/terminal_session/client.h @@ -18,103 +18,86 @@ #include <util/misc_math.h> #include <util/string.h> #include <base/lock.h> -#include <base/env.h> #include <base/rpc_client.h> +#include <os/attached_dataspace.h> #include <terminal_session/terminal_session.h> -namespace Terminal { +namespace Terminal { class Session_client; } - class Session_client : public Genode::Rpc_client<Session> - { - private: - /** - * Shared-memory buffer used for carrying the payload - * of read/write operations - */ - struct Io_buffer - { - Genode::Dataspace_capability ds_cap; - char *base; - Genode::size_t size; - Genode::Lock lock; +class Terminal::Session_client : public Genode::Rpc_client<Session> +{ + private: - Io_buffer(Genode::Dataspace_capability ds_cap) - : - ds_cap(ds_cap), - base(Genode::env()->rm_session()->attach(ds_cap)), - size(ds_cap.call<Genode::Dataspace::Rpc_size>()) - { } + Genode::Lock _lock; - ~Io_buffer() - { - Genode::env()->rm_session()->detach(base); - } - }; + /** + * Shared-memory buffer used for carrying the payload + * of read/write operations + */ + Genode::Attached_dataspace _io_buffer; - Io_buffer _io_buffer; + public: - public: + Session_client(Genode::Capability<Session> cap) + : + Genode::Rpc_client<Session>(cap), + _io_buffer(call<Rpc_dataspace>()) + { } - Session_client(Genode::Capability<Session> cap) - : - Genode::Rpc_client<Session>(cap), - _io_buffer(call<Rpc_dataspace>()) - { } + Size size() { return call<Rpc_size>(); } - Size size() { return call<Rpc_size>(); } + bool avail() { return call<Rpc_avail>(); } - bool avail() { return call<Rpc_avail>(); } + Genode::size_t read(void *buf, Genode::size_t buf_size) + { + Genode::Lock::Guard _guard(_lock); - Genode::size_t read(void *buf, Genode::size_t buf_size) - { - Genode::Lock::Guard _guard(_io_buffer.lock); + /* instruct server to fill the I/O buffer */ + Genode::size_t num_bytes = call<Rpc_read>(buf_size); - /* instruct server to fill the I/O buffer */ - Genode::size_t num_bytes = call<Rpc_read>(buf_size); + /* copy-out I/O buffer */ + num_bytes = Genode::min(num_bytes, buf_size); + Genode::memcpy(buf, _io_buffer.local_addr<char>(), num_bytes); - /* copy-out I/O buffer */ - num_bytes = Genode::min(num_bytes, buf_size); - Genode::memcpy(buf, _io_buffer.base, num_bytes); + return num_bytes; + } - return num_bytes; + Genode::size_t write(void const *buf, Genode::size_t num_bytes) + { + Genode::Lock::Guard _guard(_lock); + + Genode::size_t written_bytes = 0; + char const * const src = (char const *)buf; + + while (written_bytes < num_bytes) { + + /* copy payload to I/O buffer */ + Genode::size_t n = Genode::min(num_bytes - written_bytes, + _io_buffer.size()); + Genode::memcpy(_io_buffer.local_addr<char>(), + src + written_bytes, n); + + /* tell server to pick up new I/O buffer content */ + call<Rpc_write>(n); + + written_bytes += n; } + return num_bytes; + } - Genode::size_t write(void const *buf, Genode::size_t num_bytes) - { - Genode::Lock::Guard _guard(_io_buffer.lock); + void connected_sigh(Genode::Signal_context_capability cap) + { + call<Rpc_connected_sigh>(cap); + } - Genode::size_t written_bytes = 0; - char const * const src = (char const *)buf; + void read_avail_sigh(Genode::Signal_context_capability cap) + { + call<Rpc_read_avail_sigh>(cap); + } - while (written_bytes < num_bytes) { - - /* copy payload to I/O buffer */ - Genode::size_t n = Genode::min(num_bytes - written_bytes, - _io_buffer.size); - Genode::memcpy(_io_buffer.base, src + written_bytes, n); - - /* tell server to pick up new I/O buffer content */ - call<Rpc_write>(n); - - written_bytes += n; - } - return num_bytes; - } - - void connected_sigh(Genode::Signal_context_capability cap) - { - call<Rpc_connected_sigh>(cap); - } - - void read_avail_sigh(Genode::Signal_context_capability cap) - { - call<Rpc_read_avail_sigh>(cap); - } - - Genode::size_t io_buffer_size() const { return _io_buffer.size; } - }; -} + Genode::size_t io_buffer_size() const { return _io_buffer.size(); } +}; #endif /* _INCLUDE__TERMINAL_SESSION__CLIENT_H_ */