/* * \brief Noux child policy * \author Norman Feske * \date 2012-02-25 */ /* * Copyright (C) 2012-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. */ #ifndef _NOUX__CHILD_POLICY_H_ #define _NOUX__CHILD_POLICY_H_ /* Genode includes */ #include /* Noux includes */ #include #include #include #include #include namespace Noux { typedef Registered Parent_service; typedef Registry Parent_services; typedef Local_service Pd_service; typedef Local_service Cpu_service; typedef Local_service > Noux_service; class Child_policy; } class Noux::Child_policy : public Genode::Child_policy { private: /** * Noncopyable */ Child_policy(Child_policy const &); Child_policy &operator = (Child_policy const &); Name const _name; bool _forked; Init::Child_policy_provide_rom_file _args_policy; Init::Child_policy_provide_rom_file _env_policy; Init::Child_policy_provide_rom_file _config_policy; Pd_service &_pd_service; Cpu_service &_cpu_service; Noux_service &_noux_service; Empty_rom_service &_empty_rom_service; Local_rom_service &_rom_service; Parent_services &_parent_services; Family_member &_family_member; Parent_exit *_parent_exit; File_descriptor_registry &_file_descriptor_registry; Signal_context_capability _destruct_context_cap; Pd_session &_ref_pd; Pd_session_capability _ref_pd_cap; int _exit_value; bool _verbose; template static Genode::Service *_find_service(Genode::Registry &services, Genode::Service::Name const &name) { Genode::Service *service = nullptr; services.for_each([&] (T &s) { if (!service && (s.name() == name)) service = &s; }); return service; } /** * Find suitable service for a given session request * * \throw Service_denied */ Service &_matching_service(Service::Name const &service_name, Session_label const &label) { /* * Route initial ROM requests (binary and linker) of a forked child * to the empty ROM service, since the ROMs are already attached in * the replayed region map. */ if (_forked && (service_name == Genode::Rom_session::service_name())) { if (label.last_element() == name()) return _empty_rom_service; if (label.last_element() == linker_name()) return _empty_rom_service; } Genode::Service *service = nullptr; /* check for local ROM requests */ if ((service = _args_policy .resolve_session_request_with_label(service_name, label)) || (service = _env_policy .resolve_session_request_with_label(service_name, label)) || (service = _config_policy.resolve_session_request_with_label(service_name, label))) return *service; /* check for local services */ if (service_name == Genode::Cpu_session::service_name()) return _cpu_service; if (service_name == Genode::Rom_session::service_name()) return _rom_service; if (service_name == Genode::Pd_session::service_name()) return _pd_service; if (service_name == Noux::Session::service_name()) return _noux_service; /* check for parent services */ if ((service = _find_service(_parent_services, service_name))) return *service; throw Service_denied(); } public: Child_policy(Name const &name, bool forked, Dataspace_capability args_ds, Dataspace_capability env_ds, Dataspace_capability config_ds, Rpc_entrypoint &entrypoint, Pd_service &pd_service, Cpu_service &cpu_service, Noux_service &noux_service, Empty_rom_service &empty_rom_service, Local_rom_service &rom_service, Parent_services &parent_services, Family_member &family_member, Parent_exit *parent_exit, File_descriptor_registry &file_descriptor_registry, Signal_context_capability destruct_context_cap, Pd_session &ref_pd, Pd_session_capability ref_pd_cap, bool verbose) : _name(name), _forked(forked), _args_policy( "args", args_ds, &entrypoint), _env_policy( "env", env_ds, &entrypoint), _config_policy("config", config_ds, &entrypoint), _pd_service(pd_service), _cpu_service(cpu_service), _noux_service(noux_service), _empty_rom_service(empty_rom_service), _rom_service(rom_service), _parent_services(parent_services), _family_member(family_member), _parent_exit(parent_exit), _file_descriptor_registry(file_descriptor_registry), _destruct_context_cap(destruct_context_cap), _ref_pd (ref_pd), _ref_pd_cap (ref_pd_cap), _exit_value(~0), _verbose(verbose) { } int exit_value() const { return _exit_value; } /**************************** ** Child policy interface ** ****************************/ Name name() const override { return _name; } Pd_session &ref_pd() override { return _ref_pd; } Pd_session_capability ref_pd_cap() const override { return _ref_pd_cap; } void init(Pd_session &session, Pd_session_capability) override { session.ref_account(_ref_pd_cap); } Route resolve_session_request(Service::Name const &service_name, Session_label const &label) override { return Route { .service = _matching_service(service_name, label), .label = label, .diag = Session::Diag() }; } void exit(int exit_value) override { _exit_value = exit_value; if (_verbose || (exit_value != 0)) log("child ", _name, " exited with exit value ", exit_value); /* * Close all open file descriptors. This is necessary to unblock * the parent if it is trying to read from a pipe (connected to * the child) before calling 'wait4()'. */ _file_descriptor_registry.flush(); _family_member.exit(exit_value); /* notify the parent */ if (_parent_exit) _parent_exit->exit_child(); else { /* handle exit of the init process */ Signal_transmitter(_destruct_context_cap).submit(); } } Region_map *address_space(Pd_session &pd) override { return &static_cast(pd).address_space_region_map(); } bool forked() const override { return _forked; } }; #endif /* _NOUX__CHILD_POLICY_H_ */