Intercept CPU session of Noux::Child

To implement fork semantics, we need to customize the bootstrapping of
the newly created process, in particular the startup of the main thread.
The CPU session interface provides a suitable hook. By virtualizing the
CPU connection of the process to core, we can defer (and parametrize)
the startup of the main thread. Furthermore, this enables us to detect
illegal attempts by the Noux process to create threads in addition to
the main thread.
This commit is contained in:
Norman Feske 2012-02-16 21:45:37 +01:00
parent 652a4afd51
commit 5aaf04915c
2 changed files with 105 additions and 10 deletions

View File

@ -256,24 +256,108 @@ namespace Noux {
};
/**
* Used to defer the execution of the process' main thread
*/
struct Local_cpu_session : Rpc_object<Genode::Cpu_session>
{
bool forked;
Genode::Cpu_connection cpu;
Genode::Thread_capability main_thread;
Local_cpu_session(char const *label, bool forked)
: forked(forked), cpu(label) { }
Genode::Thread_capability create_thread(Name const &name)
{
/*
* Prevent any attempt to create more than the main
* thread.
*/
if (main_thread.valid()) {
PWRN("Invalid attempt to create a thread besides main");
return Genode::Thread_capability();
}
main_thread = cpu.create_thread(name);
PINF("created main thread");
return main_thread;
}
void kill_thread(Genode::Thread_capability thread) {
cpu.kill_thread(thread); }
Genode::Thread_capability first() {
return cpu.first(); }
Genode::Thread_capability next(Genode::Thread_capability curr) {
return cpu.next(curr); }
int set_pager(Genode::Thread_capability thread,
Genode::Pager_capability pager) {
return cpu.set_pager(thread, pager); }
int start(Genode::Thread_capability thread, Genode::addr_t ip, Genode::addr_t sp)
{
if (forked) {
PINF("defer attempt to start thread at ip 0x%lx", ip);
return 0;
}
return cpu.start(thread, ip, sp);
}
void pause(Genode::Thread_capability thread) {
cpu.pause(thread); }
void resume(Genode::Thread_capability thread) {
cpu.resume(thread); }
void cancel_blocking(Genode::Thread_capability thread) {
cpu.cancel_blocking(thread); }
int state(Genode::Thread_capability thread, Genode::Thread_state *dst) {
return cpu.state(thread, dst); }
void exception_handler(Genode::Thread_capability thread,
Genode::Signal_context_capability handler) {
cpu.exception_handler(thread, handler); }
void single_step(Genode::Thread_capability thread, bool enable) {
cpu.single_step(thread, enable); }
/**
* Explicity start main thread, only meaningful when
* 'forked' is true
*/
void start_main_thread(Genode::addr_t ip, Genode::addr_t sp)
{
cpu.start(main_thread, ip, sp);
}
};
Genode::Rpc_entrypoint ep;
Local_ram_session ram;
Genode::Cpu_connection cpu;
Local_cpu_session cpu;
Local_rm_session rm;
Resources(char const *label, Genode::Rpc_entrypoint &ep)
Resources(char const *label, Genode::Rpc_entrypoint &ep, bool forked)
:
ep(ep),
cpu(label)
cpu(label, forked)
{
ep.manage(&ram);
ep.manage(&rm);
ep.manage(&cpu);
}
~Resources()
{
ep.dissolve(&rm);
ep.dissolve(&ram);
ep.dissolve(&rm);
ep.dissolve(&cpu);
}
} _resources;
@ -349,6 +433,14 @@ namespace Noux {
public:
/**
* Constructor
*
* \param forked false if the child is spawned directly from
* an executable binary (i.e., the init process,
* or children created via execve, or
* true if the child is a fork from another child
*/
Child(char const *name,
int pid,
Genode::Signal_receiver *sig_rec,
@ -357,7 +449,8 @@ namespace Noux {
char const *env,
Genode::Cap_session *cap_session,
Genode::Service_registry *parent_services,
Genode::Rpc_entrypoint &resources_ep)
Genode::Rpc_entrypoint &resources_ep,
bool forked)
:
_pid(pid),
_sig_rec(sig_rec),
@ -367,7 +460,7 @@ namespace Noux {
_execve_cleanup_context_cap(sig_rec->manage(&_execve_cleanup_dispatcher)),
_cap_session(cap_session),
_entrypoint(cap_session, STACK_SIZE, "noux_process", false),
_resources(name, resources_ep),
_resources(name, resources_ep, false),
_args(ARGS_DS_SIZE, args),
_env(env),
_vfs(vfs),

View File

@ -148,6 +148,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
}
case SYSCALL_IOCTL:
return _lookup_channel(_sysio->ioctl_in.fd)->ioctl(_sysio);
case SYSCALL_DIRENT:
@ -171,14 +172,14 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
env, /* XXX */
_cap_session,
_parent_services,
_resources.ep);
_resources.ep,
false);
/* let new chuld inherit our file descriptors */
/* let new child inherit our file descriptors */
for (int fd = 0; fd < MAX_FILE_DESCRIPTORS; fd++)
if (fd_in_use(fd))
child->add_io_channel(io_channel_by_fd(fd), fd);
/* signal main thread to remove ourself */
Genode::Signal_transmitter(_execve_cleanup_context_cap).submit();
@ -462,7 +463,8 @@ int main(int argc, char **argv)
env_string_of_init_process(),
&cap,
&parent_services,
resources_ep);
resources_ep,
false);
static Terminal::Connection terminal;