New 'os/attached_dataspace.h' utility

The new Attached_dataspace complements the existing Attached_*
utilities with a simple version that can be used with any kind of
dataspaces. It may be even useful as a common base type for the other
variants. For example, this patch simplifies Attached_rom_dataspace
and removes the Terminal::Client::Io_buffer.
This commit is contained in:
Norman Feske 2014-01-11 00:09:13 +01:00 committed by Christian Helmuth
parent 759e11f9af
commit bdfbe9f20e
3 changed files with 189 additions and 151 deletions

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */