/* * \brief Test program for detecting faults * \author Norman Feske * \date 2013-01-03 */ /* * Copyright (C) 2008-2017 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. */ #include #include #include #include #include #include #include using namespace Genode; template class Iterative_test { private: Env &_env; Signal_context_capability _finished_sigh; unsigned const _cnt_max = 5; unsigned _cnt = 0; Signal_handler _fault_handler { _env.ep(), *this, &Iterative_test::_handle_fault }; TEST _test { }; void _handle_fault() { if (_cnt++ >= _cnt_max) { Signal_transmitter(_finished_sigh).submit(); log("-- finished ", _test.name(), " --"); return; } _test.start_iteration(_env, _fault_handler); } public: Iterative_test(Env &env, Signal_context_capability finished_sigh) : _env(env), _finished_sigh(finished_sigh) { log("-- exercise ", _test.name(), " --"); _test.start_iteration(_env, _fault_handler); } }; /******************************************************************** ** Test for detecting the failure of an immediate child component ** ********************************************************************/ class Test_child : public Genode::Child_policy { private: Env &_env; Cap_quota const _cap_quota { 50 }; Ram_quota const _ram_quota { 1024*1024 }; Binary_name const _binary_name; Signal_context_capability _sigh; Parent_service _cpu_service { _env, Cpu_session::service_name() }; Parent_service _pd_service { _env, Pd_session::service_name() }; Parent_service _log_service { _env, Log_session::service_name() }; Parent_service _rom_service { _env, Rom_session::service_name() }; Child _child; public: /** * Constructor */ Test_child(Env &env, Name const &binary_name, Genode::Signal_context_capability sigh) : _env(env), _binary_name(binary_name), _sigh(sigh), _child(_env.rm(), _env.ep().rpc_ep(), *this) { } /**************************** ** Child-policy interface ** ****************************/ Name name() const override { return "child"; } Binary_name binary_name() const override { return _binary_name; } Pd_session &ref_pd() override { return _env.pd(); } Pd_session_capability ref_pd_cap() const override { return _env.pd_session_cap(); } void init(Cpu_session &cpu, Cpu_session_capability) override { /* register default exception handler */ cpu.exception_sigh(_sigh); } void init(Pd_session &pd, Pd_session_capability pd_cap) override { pd.ref_account(ref_pd_cap()); ref_pd().transfer_quota(pd_cap, _cap_quota); ref_pd().transfer_quota(pd_cap, _ram_quota); /* register handler for unresolvable page faults */ Region_map_client address_space(pd.address_space()); address_space.fault_handler(_sigh); } Route resolve_session_request(Service::Name const &service, Session_label const &label) override { auto route = [&] (Service &service) { return Route { .service = service, .label = label, .diag = Session::Diag() }; }; if (service == Cpu_session::service_name()) return route(_cpu_service); if (service == Pd_session::service_name()) return route( _pd_service); if (service == Log_session::service_name()) return route(_log_service); if (service == Rom_session::service_name()) return route(_rom_service); throw Service_denied(); } }; struct Faulting_child_test { static char const *name() { return "failure detection in immediate child"; } Constructible _child; void start_iteration(Env &env, Signal_context_capability fault_sigh) { _child.construct(env, "test-segfault", fault_sigh); } }; /****************************************************************** ** Test for detecting failures in a child started by the loader ** ******************************************************************/ struct Faulting_loader_child_test { static char const *name() { return "failure detection in loaded child"; } Constructible loader; void start_iteration(Env &env, Signal_context_capability fault_sigh) { loader.construct(env, Ram_quota{1024*1024}, Cap_quota{100}); /* register fault handler at loader session */ loader->fault_sigh(fault_sigh); /* start subsystem */ loader->start("test-segfault"); } }; /*********************************************************************** ** Test for detecting failures in a grandchild started by the loader ** ***********************************************************************/ struct Faulting_loader_grand_child_test { static char const *name() { return "failure detection of loaded grand child"; } static char const *config() { return "\n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" " \n" ""; } static size_t config_size() { return strlen(config()); } Constructible loader; void start_iteration(Env &env, Signal_context_capability fault_sigh) { loader.construct(env, Ram_quota{4*1024*1024}, Cap_quota{120}); /* import config into loader session */ { Attached_dataspace ds(env.rm(), loader->alloc_rom_module("config", config_size())); memcpy(ds.local_addr(), config(), config_size()); loader->commit_rom_module("config"); } /* register fault handler at loader session */ loader->fault_sigh(fault_sigh); /* start subsystem */ loader->start("init", "init"); } }; struct Main { Env &_env; Constructible > _test_1 { }; Constructible > _test_2 { }; Constructible > _test_3 { }; Signal_handler
_test_1_finished_handler { _env.ep(), *this, &Main::_handle_test_1_finished }; Signal_handler
_test_2_finished_handler { _env.ep(), *this, &Main::_handle_test_2_finished }; Signal_handler
_test_3_finished_handler { _env.ep(), *this, &Main::_handle_test_3_finished }; void _handle_test_1_finished() { _test_1.destruct(); _test_2.construct(_env, _test_2_finished_handler); } void _handle_test_2_finished() { _test_2.destruct(); _test_3.construct(_env, _test_3_finished_handler); } void _handle_test_3_finished() { _test_3.destruct(); log("--- finished fault_detection test ---"); _env.parent().exit(0); } Main(Env &env) : _env(env) { _test_1.construct(_env, _test_1_finished_handler); } }; void Component::construct(Env &env) { static Main main(env); }