/* * \brief CPU session provided to Noux processes * \author Norman Feske * \date 2012-02-22 * * The custom implementation of the CPU session interface is used to tweak * the startup procedure as performed by the 'Process' class. Normally, * processes start execution immediately at creation time at the ELF entry * point. For implementing fork semantics, however, this default behavior * does not work. Instead, we need to defer the start of the main thread * until we have finished copying the address space of the forking process. * Furthermore, we need to start the main thread at a custom trampoline * function rather than at the ELF entry point. Those customizations are * possible by wrapping core's CPU service. */ /* * 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__CPU_SESSION_COMPONENT_H_ #define _NOUX__CPU_SESSION_COMPONENT_H_ /* Genode includes */ #include #include #include #include /* Noux includes */ #include namespace Noux { class Cpu_session_component; using namespace Genode; } class Noux::Cpu_session_component : public Rpc_object { private: Rpc_entrypoint &_ep; bool const _forked; Cpu_connection _cpu; enum { MAX_THREADS = 8, MAIN_THREAD_IDX = 0 }; Thread_capability _threads[MAX_THREADS]; Dataspace_capability _trace_control { }; Dataspace_registry &_registry; Constructible _ds_info { }; public: /** * Constructor * * \param forked false if the CPU session belongs to a child * created via execve or to the init process, or * true if the CPU session belongs to a newly * forked process. * * The 'forked' parameter controls the policy applied to the * startup of the main thread. */ Cpu_session_component(Env &env, Rpc_entrypoint &ep, Child_policy::Name const &label, bool forked, Dataspace_registry ®istry) : _ep(ep), _forked(forked), _cpu(env, label.string()), _registry(registry) { _ep.manage(this); } ~Cpu_session_component() { _ep.dissolve(this); if (!_trace_control.valid()) return; } /** * Explicitly start main thread, only meaningful when * 'forked' is true */ void start_main_thread(addr_t ip, addr_t sp) { Capability main_thread = _threads[MAIN_THREAD_IDX]; Cpu_thread_client(main_thread).start(ip, sp); } Cpu_session_capability cpu_cap() { return _cpu.cap(); } /*************************** ** Cpu_session interface ** ***************************/ Thread_capability create_thread(Capability pd_cap, Name const &name, Affinity::Location affinity, Weight weight, addr_t utcb) override { /* create thread at core, keep local copy (needed on NOVA) */ for (unsigned i = 0; i < MAX_THREADS; i++) { if (_threads[i].valid()) continue; auto lambda = [&] (Pd_session_component *pd) { if (!pd) throw Thread_creation_failed(); return _cpu.create_thread(pd->core_pd_cap(), name, affinity, weight, utcb); }; Thread_capability cap = _ep.apply(pd_cap, lambda); _threads[i] = cap; return cap; } error("maximum number of threads per session reached"); throw Thread_creation_failed(); } void kill_thread(Thread_capability thread) override { /* purge local copy of thread capability */ for (unsigned i = 0; i < MAX_THREADS; i++) if (_threads[i].local_name() == thread.local_name()) _threads[i] = Thread_capability(); _cpu.kill_thread(thread); } void exception_sigh(Signal_context_capability handler) override { _cpu.exception_sigh(handler); } Affinity::Space affinity_space() const override { return _cpu.affinity_space(); } Dataspace_capability trace_control() override { if (!_trace_control.valid()) { _trace_control = _cpu.trace_control(); _ds_info.construct(_registry, _trace_control); } return _trace_control; } Quota quota() override { return _cpu.quota(); } int ref_account(Cpu_session_capability c) override { return _cpu.ref_account(c); } int transfer_quota(Cpu_session_capability c, size_t q) override { return _cpu.transfer_quota(c, q); } Capability native_cpu() override { return _cpu.native_cpu(); } }; #endif /* _NOUX__CPU_SESSION_COMPONENT_H_ */