os: make 'terminal_crosslink' buffer size configurable

Fixes #5135
This commit is contained in:
Christian Prochaska 2024-03-07 10:55:51 +01:00 committed by Christian Helmuth
parent 32cb245cb8
commit 011a521968
6 changed files with 146 additions and 35 deletions

View File

@ -30,6 +30,7 @@
<start name="terminal_crosslink">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Terminal"/> </provides>
<config buffer="4K"/>
</start>
<start name="test-terminal_crosslink">
<resource name="RAM" quantum="1M"/>

View File

@ -1,14 +1,11 @@
The 'terminal_crosslink' server allows exactly two clients to communicate with
each other using the 'Terminal' interface. Data sent to the server gets stored
in a buffer of 4096 bytes (one buffer per client). As long as the data to be
written fits into the buffer, the 'write()' call returns immediately. If no
more data fits into the buffer, the 'write()' call blocks until the other
client has consumed some of the data from the buffer via the 'read()' call. The
'read()' call never blocks. A signal receiver can be used to block until new
data is ready for reading.
in a buffer of configurable size (one buffer per client, 4K by default). The
'read()' and 'write()' calls never block. A signal receiver can be used to
block until new data is ready for reading.
Example
-------
An example run script 'terminal_crosslink.run' can be found in the 'os/run'
directory.
An example depot package 'test-terminal_crosslink' can be found in the
'os/recipes/pkg' directory.

View File

@ -5,13 +5,14 @@
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
* Copyright (C) 2012-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
@ -27,10 +28,18 @@ namespace Terminal_crosslink {
struct Terminal_crosslink::Main
{
Env &_env;
Heap _heap { _env.ram(), _env.rm() };
Env &_env;
Root _terminal_root { _env, _heap };
Sliced_heap _heap { _env.ram(), _env.rm() };
Attached_rom_dataspace _config { _env, "config" };
Number_of_bytes const DEFAULT_BUFFER_SIZE { 4096 };
size_t const _buffer_size {
_config.xml().attribute_value("buffer", DEFAULT_BUFFER_SIZE) };
Root _terminal_root { _env, _heap, _buffer_size };
Main(Env &env) : _env(env)
{

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
* Copyright (C) 2012-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -67,10 +67,10 @@ namespace Terminal_crosslink {
/**
* Constructor
*/
Root(Env &env, Allocator &alloc)
Root(Env &env, Allocator &alloc, size_t buffer_size)
: Root_component(&env.ep().rpc_ep(), &alloc),
_session_component1(env, _session_component2),
_session_component2(env, _session_component1),
_session_component1(env, _session_component2, buffer_size),
_session_component2(env, _session_component1, buffer_size),
_session_state(0)
{ }
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
* Copyright (C) 2012-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -23,11 +23,13 @@
using namespace Genode;
Terminal_crosslink::Session_component::Session_component(Env &env,
Session_component &partner)
Session_component &partner,
size_t buffer_size)
: _env(env),
_partner(partner),
_buffer_size(buffer_size),
_session_cap(_env.ep().rpc_ep().manage(this)),
_io_buffer(env.ram(), env.rm(), BUFFER_SIZE),
_io_buffer(env.ram(), env.rm(), IO_BUFFER_SIZE),
_cross_num_bytes_avail(0)
{
}
@ -85,22 +87,25 @@ bool Terminal_crosslink::Session_component::avail()
size_t Terminal_crosslink::Session_component::_read(size_t dst_len)
{
return _partner.cross_read(_io_buffer.local_addr<unsigned char>(), dst_len);
return _partner.cross_read(_io_buffer.local_addr<unsigned char>(),
min(dst_len, _io_buffer.size()));
}
size_t Terminal_crosslink::Session_component::_write(size_t num_bytes)
{
num_bytes = min(num_bytes, _io_buffer.size());
unsigned char *src = _io_buffer.local_addr<unsigned char>();
size_t num_bytes_written = 0;
while (num_bytes_written < num_bytes)
try {
_buffer.add(src[num_bytes_written]);
++num_bytes_written;
} catch(Local_buffer::Overflow) {
break;
}
bool error = false;
while ((num_bytes_written < num_bytes) && !error)
_buffer.add(src[num_bytes_written]).with_result(
[&] (Ring_buffer::Add_ok) { ++num_bytes_written; },
[&] (Ring_buffer::Add_error) { error = true; }
);
_cross_num_bytes_avail += num_bytes_written;
_partner.cross_write();

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (C) 2012-2017 Genode Labs GmbH
* Copyright (C) 2012-2024 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
@ -15,17 +15,113 @@
#define _TERMINAL_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/heap.h>
#include <base/rpc_server.h>
#include <base/attached_ram_dataspace.h>
#include <os/ring_buffer.h>
#include <terminal_session/terminal_session.h>
namespace Terminal_crosslink {
using namespace Genode;
enum { STACK_SIZE = sizeof(addr_t)*1024 };
enum { BUFFER_SIZE = 4096 };
static constexpr size_t IO_BUFFER_SIZE = 4096;
class Ring_buffer
{
private:
size_t _head = 0;
size_t _tail = 0;
char *_queue { };
size_t _queue_size;
/*
* Noncopyable
*/
Ring_buffer(Ring_buffer const &);
Ring_buffer &operator = (Ring_buffer const &);
public:
/**
* Constructor
*/
Ring_buffer(Byte_range_ptr const &buffer)
: _queue(buffer.start), _queue_size(buffer.num_bytes) { }
struct Add_ok { };
enum class Add_error { OVERFLOW };
using Add_result = Attempt<Add_ok, Add_error>;
/**
* Place element into ring buffer
*/
Add_result add(char ev)
{
if ((_head + 1)%_queue_size != _tail) {
_queue[_head] = ev;
_head = (_head + 1)%_queue_size;
return Add_ok();
} else
return Add_error::OVERFLOW;
}
/**
* Take element from ring buffer
*
* \return element
*/
char get()
{
unsigned char e = _queue[_tail];
_tail = (_tail + 1)%_queue_size;
return e;
}
/**
* Return true if ring buffer is empty
*/
bool empty() const { return _tail == _head; }
};
class Allocated_ring_buffer : public Ring_buffer
{
private:
Genode::Allocator &_alloc;
char *_buffer { };
char *_init_buffer(Genode::Allocator &alloc, size_t size)
{
_buffer = static_cast<char*>(alloc.alloc(size));
return _buffer;
};
/*
* Noncopyable
*/
Allocated_ring_buffer(Allocated_ring_buffer const &);
Allocated_ring_buffer &operator = (Allocated_ring_buffer const &);
public:
Allocated_ring_buffer(Genode::Allocator &alloc, size_t queue_size)
: Ring_buffer(Byte_range_ptr(_init_buffer(alloc, queue_size),
queue_size)),
_alloc(alloc)
{ }
~Allocated_ring_buffer()
{
destroy(_alloc, _buffer);
}
};
class Session_component : public Rpc_object<Terminal::Session,
Session_component>
@ -33,15 +129,17 @@ namespace Terminal_crosslink {
private:
Env &_env;
Heap _alloc { _env.ram(), _env.rm() };
Session_component &_partner;
size_t _buffer_size;
Genode::Session_capability _session_cap;
Attached_ram_dataspace _io_buffer;
typedef Genode::Ring_buffer<unsigned char, BUFFER_SIZE+1> Local_buffer;
Local_buffer _buffer { };
Allocated_ring_buffer _buffer { _alloc, _buffer_size + 1 };
size_t _cross_num_bytes_avail;
Signal_context_capability _read_avail_sigh { };
@ -50,7 +148,8 @@ namespace Terminal_crosslink {
/**
* Constructor
*/
Session_component(Env &env, Session_component &partner);
Session_component(Env &env, Session_component &partner,
size_t buffer_size);
Session_capability cap();