genode/repos/ports/src/noux/cpu_session_component.h

174 lines
4.8 KiB
C++

/*
* \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 <base/child.h>
#include <base/rpc_server.h>
#include <cpu_session/connection.h>
#include <cpu_thread/client.h>
/* Noux includes */
#include <pd_session_component.h>
namespace Noux {
class Cpu_session_component;
using namespace Genode;
}
class Noux::Cpu_session_component : public Rpc_object<Cpu_session>
{
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<Static_dataspace_info> _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 &registry)
:
_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<Cpu_thread> 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_session> 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> native_cpu() override {
return _cpu.native_cpu(); }
};
#endif /* _NOUX__CPU_SESSION_COMPONENT_H_ */