mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 20:05:54 +00:00
block: eliminate thread in generic block_component
Instead of using an additional thread in each Session_component of a block server, which uses the generic block component and driver classes, replace it with signal dispatchers. Ref #113
This commit is contained in:
parent
f4c724639b
commit
5a4cb7fcfb
@ -1,6 +1,7 @@
|
||||
/*
|
||||
* \brief Block-session component
|
||||
* \author Christian Helmuth
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2011-05-20
|
||||
*/
|
||||
|
||||
@ -16,197 +17,192 @@
|
||||
|
||||
#include <root/component.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
|
||||
#include <block/driver.h>
|
||||
|
||||
|
||||
namespace Block {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Session_component : public Session_rpc_object
|
||||
{
|
||||
private:
|
||||
class Session_component;
|
||||
class Root;
|
||||
};
|
||||
|
||||
enum { RQ_STACK_SIZE = 8192 };
|
||||
class Rq_thread : public Thread<RQ_STACK_SIZE>
|
||||
{
|
||||
private:
|
||||
|
||||
Tx::Sink *_sink;
|
||||
Driver &_driver;
|
||||
addr_t _rq_phys; /* physical addr. of rq_ds */
|
||||
class Block::Session_component : public Block::Session_rpc_object
|
||||
{
|
||||
private:
|
||||
|
||||
public:
|
||||
Driver_factory &_driver_factory;
|
||||
Driver &_driver;
|
||||
Ram_dataspace_capability _rq_ds;
|
||||
addr_t _rq_phys;
|
||||
Signal_dispatcher<Session_component> _sink_ack;
|
||||
Signal_dispatcher<Session_component> _sink_submit;
|
||||
|
||||
Rq_thread(Tx::Sink *sink, Driver &driver, addr_t rq_phys)
|
||||
:
|
||||
Thread<RQ_STACK_SIZE>("rq"),
|
||||
_sink(sink), _driver(driver), _rq_phys(rq_phys)
|
||||
{ start(); }
|
||||
void _ready_to_submit(unsigned)
|
||||
{
|
||||
/* handle requests */
|
||||
while (tx_sink()->packet_avail()) {
|
||||
|
||||
void entry()
|
||||
{
|
||||
/* handle requests */
|
||||
while (true) {
|
||||
|
||||
/* blocking-get packet from client */
|
||||
Packet_descriptor packet = _sink->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("received invalid packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
packet.succeeded(true);
|
||||
|
||||
switch (packet.operation()) {
|
||||
|
||||
case Block::Packet_descriptor::READ:
|
||||
|
||||
try {
|
||||
if (_driver.dma_enabled())
|
||||
_driver.read_dma(packet.block_number(), packet.block_count(),
|
||||
_rq_phys + packet.offset());
|
||||
else
|
||||
_driver.read(packet.block_number(), packet.block_count(),
|
||||
_sink->packet_content(packet));
|
||||
} catch (Driver::Io_error) {
|
||||
packet.succeeded(false);
|
||||
}
|
||||
break;
|
||||
|
||||
case Block::Packet_descriptor::WRITE:
|
||||
try {
|
||||
if (_driver.dma_enabled())
|
||||
_driver.write_dma(packet.block_number(), packet.block_count(),
|
||||
_rq_phys + packet.offset());
|
||||
else
|
||||
_driver.write(packet.block_number(), packet.block_count(),
|
||||
_sink->packet_content(packet));
|
||||
} catch (Driver::Io_error) {
|
||||
packet.succeeded(false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
PWRN("received invalid packet");
|
||||
packet.succeeded(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* acknowledge packet to the client */
|
||||
if (!_sink->ready_to_ack())
|
||||
PDBG("need to wait until ready-for-ack");
|
||||
|
||||
_sink->acknowledge_packet(packet);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Driver_factory &_driver_factory;
|
||||
Driver &_driver;
|
||||
Ram_dataspace_capability _rq_ds;
|
||||
Rq_thread _rq_thread;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Ram_dataspace_capability rq_ds,
|
||||
Driver &driver,
|
||||
Driver_factory &driver_factory,
|
||||
Rpc_entrypoint &ep)
|
||||
:
|
||||
Session_rpc_object(rq_ds, ep),
|
||||
_driver_factory(driver_factory),
|
||||
_driver(driver),
|
||||
_rq_ds(rq_ds),
|
||||
_rq_thread(tx_sink(), _driver, Dataspace_client(_rq_ds).phys_addr())
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Session_component()
|
||||
{
|
||||
_driver_factory.destroy(&_driver);
|
||||
}
|
||||
|
||||
void info(size_t *blk_count, size_t *blk_size,
|
||||
Operations *ops)
|
||||
{
|
||||
*blk_count = _driver.block_count();
|
||||
*blk_size = _driver.block_size();
|
||||
ops->set_operation(Packet_descriptor::READ);
|
||||
ops->set_operation(Packet_descriptor::WRITE);
|
||||
}
|
||||
|
||||
void sync() { _driver.sync(); }
|
||||
};
|
||||
|
||||
/*
|
||||
* Shortcut for single-client root component
|
||||
*/
|
||||
typedef Root_component<Session_component, Single_client> Root_component;
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Root : public Root_component
|
||||
{
|
||||
private:
|
||||
|
||||
Driver_factory &_driver_factory;
|
||||
Rpc_entrypoint &_ep;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Always returns the singleton block-session component
|
||||
*/
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
|
||||
/* delete ram quota by the memory needed for the session */
|
||||
size_t session_size = max((size_t)4096,
|
||||
sizeof(Session_component)
|
||||
+ sizeof(Allocator_avl));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both
|
||||
* communication buffers. Also check both sizes separately
|
||||
* to handle a possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
/* blocking-get packet from client */
|
||||
Packet_descriptor packet = tx_sink()->get_packet();
|
||||
if (!packet.valid()) {
|
||||
PWRN("received invalid packet");
|
||||
continue;
|
||||
}
|
||||
|
||||
Driver * driver = _driver_factory.create();
|
||||
Ram_dataspace_capability ds_cap;
|
||||
ds_cap = driver->alloc_dma_buffer(tx_buf_size);
|
||||
return new (md_alloc())
|
||||
Session_component(ds_cap, *driver, _driver_factory, _ep);
|
||||
packet.succeeded(true);
|
||||
|
||||
try {
|
||||
switch (packet.operation()) {
|
||||
|
||||
case Block::Packet_descriptor::READ:
|
||||
if (_driver.dma_enabled())
|
||||
_driver.read_dma(packet.block_number(),
|
||||
packet.block_count(),
|
||||
_rq_phys + packet.offset());
|
||||
else
|
||||
_driver.read(packet.block_number(),
|
||||
packet.block_count(),
|
||||
tx_sink()->packet_content(packet));
|
||||
break;
|
||||
|
||||
case Block::Packet_descriptor::WRITE:
|
||||
if (_driver.dma_enabled())
|
||||
_driver.write_dma(packet.block_number(),
|
||||
packet.block_count(),
|
||||
_rq_phys + packet.offset());
|
||||
else
|
||||
_driver.write(packet.block_number(),
|
||||
packet.block_count(),
|
||||
tx_sink()->packet_content(packet));
|
||||
break;
|
||||
|
||||
default:
|
||||
PWRN("received invalid packet");
|
||||
packet.succeeded(false);
|
||||
continue;
|
||||
}
|
||||
} catch (Driver::Io_error) {
|
||||
packet.succeeded(false);
|
||||
}
|
||||
|
||||
/* acknowledge packet to the client */
|
||||
if (!tx_sink()->ready_to_ack()) {
|
||||
PWRN("need to wait until ready-for-ack");
|
||||
return;
|
||||
}
|
||||
|
||||
tx_sink()->acknowledge_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
void _ack_avail(unsigned) { }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Ram_dataspace_capability rq_ds,
|
||||
Driver &driver,
|
||||
Driver_factory &driver_factory,
|
||||
Rpc_entrypoint &ep,
|
||||
Signal_receiver &receiver)
|
||||
:
|
||||
Session_rpc_object(rq_ds, ep),
|
||||
_driver_factory(driver_factory),
|
||||
_driver(driver),
|
||||
_rq_ds(rq_ds),
|
||||
_rq_phys(Dataspace_client(_rq_ds).phys_addr()),
|
||||
_sink_ack(receiver, *this, &Session_component::_ack_avail),
|
||||
_sink_submit(receiver, *this,
|
||||
&Session_component::_ready_to_submit)
|
||||
{
|
||||
_tx.sigh_ready_to_ack(_sink_ack);
|
||||
_tx.sigh_packet_avail(_sink_submit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Session_component()
|
||||
{
|
||||
_driver_factory.destroy(&_driver);
|
||||
}
|
||||
|
||||
void info(size_t *blk_count, size_t *blk_size,
|
||||
Operations *ops)
|
||||
{
|
||||
*blk_count = _driver.block_count();
|
||||
*blk_size = _driver.block_size();
|
||||
ops->set_operation(Packet_descriptor::READ);
|
||||
ops->set_operation(Packet_descriptor::WRITE);
|
||||
}
|
||||
|
||||
void sync() { _driver.sync(); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Block::Root :
|
||||
public Genode::Root_component<Block::Session_component, Single_client>
|
||||
{
|
||||
private:
|
||||
|
||||
Driver_factory &_driver_factory;
|
||||
Rpc_entrypoint &_ep;
|
||||
Signal_receiver &_receiver;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Always returns the singleton block-session component
|
||||
*/
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
|
||||
/* delete ram quota by the memory needed for the session */
|
||||
size_t session_size = max((size_t)4096,
|
||||
sizeof(Session_component)
|
||||
+ sizeof(Allocator_avl));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both
|
||||
* communication buffers. Also check both sizes separately
|
||||
* to handle a possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
public:
|
||||
Driver * driver = _driver_factory.create();
|
||||
Ram_dataspace_capability ds_cap;
|
||||
ds_cap = driver->alloc_dma_buffer(tx_buf_size);
|
||||
return new (md_alloc())
|
||||
Session_component(ds_cap, *driver, _driver_factory, _ep,
|
||||
_receiver);
|
||||
}
|
||||
|
||||
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
|
||||
Driver_factory &driver_factory)
|
||||
:
|
||||
Root_component(session_ep, md_alloc),
|
||||
_driver_factory(driver_factory), _ep(*session_ep)
|
||||
{ }
|
||||
};
|
||||
}
|
||||
public:
|
||||
|
||||
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
|
||||
Driver_factory &driver_factory, Signal_receiver &receiver)
|
||||
:
|
||||
Root_component(session_ep, md_alloc),
|
||||
_driver_factory(driver_factory), _ep(*session_ep),
|
||||
_receiver(receiver)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BLOCK__COMPONENT_H_ */
|
||||
|
@ -19,7 +19,6 @@
|
||||
/* Genode includes */
|
||||
#include <cap_session/connection.h>
|
||||
#include <block/component.h>
|
||||
#include <base/sleep.h>
|
||||
|
||||
/* local includes */
|
||||
#include <ahci_driver.h>
|
||||
@ -43,10 +42,15 @@ int main()
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "block_ep");
|
||||
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory);
|
||||
static Signal_receiver receiver;
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory, receiver);
|
||||
env()->parent()->announce(ep.manage(&block_root));
|
||||
|
||||
sleep_forever();
|
||||
while (true) {
|
||||
Signal s = receiver.wait_for_signal();
|
||||
static_cast<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/sleep.h>
|
||||
#include <base/printf.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <regulator_session/connection.h>
|
||||
@ -51,9 +50,15 @@ int main(int argc, char **argv)
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "block_ep");
|
||||
static Regulator::Connection mmc0_regulator(Regulator::CLK_MMC0);
|
||||
mmc0_regulator.state(true);
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory);
|
||||
|
||||
static Signal_receiver receiver;
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory, receiver);
|
||||
env()->parent()->announce(ep.manage(&block_root));
|
||||
|
||||
sleep_forever();
|
||||
while (true) {
|
||||
Signal s = receiver.wait_for_signal();
|
||||
static_cast<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/sleep.h>
|
||||
#include <base/printf.h>
|
||||
#include <cap_session/connection.h>
|
||||
|
||||
@ -53,9 +52,14 @@ int main(int argc, char **argv)
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "block_ep");
|
||||
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory);
|
||||
static Signal_receiver receiver;
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory, receiver);
|
||||
env()->parent()->announce(ep.manage(&block_root));
|
||||
|
||||
sleep_forever();
|
||||
while (true) {
|
||||
Signal s = receiver.wait_for_signal();
|
||||
static_cast<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -12,7 +12,6 @@
|
||||
*/
|
||||
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
|
||||
#include <cap_session/connection.h>
|
||||
#include <block/component.h>
|
||||
@ -58,9 +57,14 @@ int main(int argc, char **argv)
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "block_ep");
|
||||
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory);
|
||||
static Signal_receiver receiver;
|
||||
static Block::Root block_root(&ep, env()->heap(), driver_factory, receiver);
|
||||
env()->parent()->announce(ep.manage(&block_root));
|
||||
|
||||
sleep_forever();
|
||||
while (true) {
|
||||
Signal s = receiver.wait_for_signal();
|
||||
static_cast<Signal_dispatcher_base *>(s.context())->dispatch(s.num());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user