From 5a4cb7fcfbfa00014d0f70927ac7896277b00d3a Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Fri, 22 Nov 2013 21:55:28 +0100 Subject: [PATCH] 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 --- os/include/block/component.h | 348 ++++++++++++------------- os/src/drivers/ahci/main.cc | 10 +- os/src/drivers/sd_card/exynos5/main.cc | 11 +- os/src/drivers/sd_card/omap4/main.cc | 10 +- os/src/drivers/sd_card/pl180/main.cc | 10 +- 5 files changed, 201 insertions(+), 188 deletions(-) diff --git a/os/include/block/component.h b/os/include/block/component.h index e3611f1b7..c45a93069 100644 --- a/os/include/block/component.h +++ b/os/include/block/component.h @@ -1,6 +1,7 @@ /* * \brief Block-session component * \author Christian Helmuth + * \author Stefan Kalkowski * \date 2011-05-20 */ @@ -16,197 +17,192 @@ #include #include - #include - 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 - { - 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 _sink_ack; + Signal_dispatcher _sink_submit; - Rq_thread(Tx::Sink *sink, Driver &driver, addr_t rq_phys) - : - Thread("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 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 +{ + 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_ */ diff --git a/os/src/drivers/ahci/main.cc b/os/src/drivers/ahci/main.cc index 45c54286f..bb61a89fa 100644 --- a/os/src/drivers/ahci/main.cc +++ b/os/src/drivers/ahci/main.cc @@ -19,7 +19,6 @@ /* Genode includes */ #include #include -#include /* local includes */ #include @@ -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(s.context())->dispatch(s.num()); + } + return 0; } diff --git a/os/src/drivers/sd_card/exynos5/main.cc b/os/src/drivers/sd_card/exynos5/main.cc index 7fc9c29ad..eb5010209 100644 --- a/os/src/drivers/sd_card/exynos5/main.cc +++ b/os/src/drivers/sd_card/exynos5/main.cc @@ -12,7 +12,6 @@ */ /* Genode includes */ -#include #include #include #include @@ -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(s.context())->dispatch(s.num()); + } + return 0; } diff --git a/os/src/drivers/sd_card/omap4/main.cc b/os/src/drivers/sd_card/omap4/main.cc index 8f61bb155..6bc44d768 100644 --- a/os/src/drivers/sd_card/omap4/main.cc +++ b/os/src/drivers/sd_card/omap4/main.cc @@ -12,7 +12,6 @@ */ /* Genode includes */ -#include #include #include @@ -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(s.context())->dispatch(s.num()); + } + return 0; } diff --git a/os/src/drivers/sd_card/pl180/main.cc b/os/src/drivers/sd_card/pl180/main.cc index ad8869a81..4a2158c4d 100644 --- a/os/src/drivers/sd_card/pl180/main.cc +++ b/os/src/drivers/sd_card/pl180/main.cc @@ -12,7 +12,6 @@ */ #include -#include #include #include @@ -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(s.context())->dispatch(s.num()); + } + return 0; }