mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
Noux: POSIX signal improvements
- 'kill()' syscall added - 'wait()' gets unblocked when a signal occurs - syscalls can get called from a signal handler without corrupting the 'sysio' object - the child's exit status gets correctly reported to 'wait()' - SIGCHLD gets ignored by default - pending signals survive 'execve()' Fixes #1035.
This commit is contained in:
parent
7876dfcb5e
commit
27ff408985
@ -76,6 +76,7 @@ namespace Noux {
|
||||
SYSCALL_CLOCK_GETTIME,
|
||||
SYSCALL_UTIMES,
|
||||
SYSCALL_SYNC,
|
||||
SYSCALL_KILL,
|
||||
SYSCALL_INVALID = -1
|
||||
};
|
||||
|
||||
@ -124,6 +125,7 @@ namespace Noux {
|
||||
NOUX_DECL_SYSCALL_NAME(CLOCK_GETTIME)
|
||||
NOUX_DECL_SYSCALL_NAME(UTIMES)
|
||||
NOUX_DECL_SYSCALL_NAME(SYNC)
|
||||
NOUX_DECL_SYSCALL_NAME(KILL)
|
||||
case SYSCALL_INVALID: return 0;
|
||||
}
|
||||
return 0;
|
||||
|
@ -37,6 +37,7 @@ namespace Noux {
|
||||
/* signal numbers must match with libc signal numbers */
|
||||
enum Signal {
|
||||
SIG_INT = 2,
|
||||
SIG_CHLD = 20,
|
||||
};
|
||||
|
||||
enum { SIGNAL_QUEUE_SIZE = 32 };
|
||||
@ -369,6 +370,10 @@ namespace Noux {
|
||||
UTIMES_ERR_NOT_DIRECTORY, UTIMES_ERR_NO_PERM,
|
||||
UTIMES_ERR_READ_ONLY };
|
||||
|
||||
enum Wait4_error { WAIT4_ERR_INTERRUPT };
|
||||
|
||||
enum Kill_error { KILL_ERR_SRCH };
|
||||
|
||||
union {
|
||||
General_error general;
|
||||
Stat_error stat;
|
||||
@ -395,6 +400,8 @@ namespace Noux {
|
||||
Socket_error socket;
|
||||
Clock_error clock;
|
||||
Utimes_error utimes;
|
||||
Wait4_error wait4;
|
||||
Kill_error kill;
|
||||
} error;
|
||||
|
||||
union {
|
||||
@ -508,6 +515,8 @@ namespace Noux {
|
||||
{ });
|
||||
|
||||
SYSIO_DECL(sync, { }, { });
|
||||
|
||||
SYSIO_DECL(kill, { int pid; Signal sig; }, { });
|
||||
};
|
||||
};
|
||||
};
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include <termios.h>
|
||||
#include <pwd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
/**
|
||||
* There is a off_t typedef clash between sys/socket.h
|
||||
@ -54,6 +55,7 @@
|
||||
/* libc-internal includes */
|
||||
#include <libc_mem_alloc.h>
|
||||
|
||||
|
||||
enum { verbose = false };
|
||||
enum { verbose_signals = false };
|
||||
|
||||
@ -100,27 +102,57 @@ Noux::Session *noux() { return noux_connection()->session(); }
|
||||
Noux::Sysio *sysio() { return noux_connection()->sysio(); }
|
||||
|
||||
|
||||
/* Array of signal handlers */
|
||||
static struct sigaction signal_action[SIGRTMAX+1];
|
||||
/*
|
||||
* Array of signal handlers, initialized with 0 (SIG_DFL)
|
||||
* TODO: preserve ignored signals across 'execve()'
|
||||
*/
|
||||
static struct sigaction signal_action[NSIG+1];
|
||||
|
||||
/*
|
||||
* Signal mask functionality is not fully implemented yet.
|
||||
* TODO: - actually block delivery of to be blocked signals
|
||||
* - preserve signal mask across 'execve()'
|
||||
*/
|
||||
static sigset_t signal_mask;
|
||||
|
||||
|
||||
static bool noux_syscall(Noux::Session::Syscall opcode)
|
||||
{
|
||||
/*
|
||||
* Signal handlers might do syscalls themselves, so the 'sysio' object
|
||||
* needs to get saved before and restored after calling the signal handler.
|
||||
*/
|
||||
Noux::Sysio saved_sysio;
|
||||
|
||||
bool ret = noux()->syscall(opcode);
|
||||
|
||||
/* handle signals */
|
||||
while (!sysio()->pending_signals.empty()) {
|
||||
Noux::Sysio::Signal signal = sysio()->pending_signals.get();
|
||||
if (verbose_signals)
|
||||
PDBG("received signal %d", signal);
|
||||
if (signal_action[signal].sa_flags & SA_SIGINFO) {
|
||||
memcpy(&saved_sysio, sysio(), sizeof(Noux::Sysio));
|
||||
/* TODO: pass siginfo_t struct */
|
||||
signal_action[signal].sa_sigaction(signal, 0, 0);
|
||||
memcpy(sysio(), &saved_sysio, sizeof(Noux::Sysio));
|
||||
} else {
|
||||
if (signal_action[signal].sa_handler == SIG_DFL) {
|
||||
/* do nothing */
|
||||
switch (signal) {
|
||||
case SIGCHLD:
|
||||
/* ignore */
|
||||
break;
|
||||
default:
|
||||
/* terminate the process */
|
||||
exit((signal << 8) | EXIT_FAILURE);
|
||||
}
|
||||
} else if (signal_action[signal].sa_handler == SIG_IGN) {
|
||||
/* do nothing */
|
||||
} else
|
||||
} else {
|
||||
memcpy(&saved_sysio, sysio(), sizeof(Noux::Sysio));
|
||||
signal_action[signal].sa_handler(signal);
|
||||
memcpy(sysio(), &saved_sysio, sizeof(Noux::Sysio));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -532,12 +564,19 @@ extern "C" pid_t _wait4(pid_t pid, int *status, int options,
|
||||
sysio()->wait4_in.pid = pid;
|
||||
sysio()->wait4_in.nohang = !!(options & WNOHANG);
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_WAIT4)) {
|
||||
PERR("wait4 error %d", sysio()->error.general);
|
||||
switch (sysio()->error.wait4) {
|
||||
case Noux::Sysio::WAIT4_ERR_INTERRUPT: errno = EINTR; break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* The libc expects status information in bits 0..6 and the exit value
|
||||
* in bits 8..15 (according to 'wait.h').
|
||||
*/
|
||||
if (status)
|
||||
*status = sysio()->wait4_out.status;
|
||||
*status = ((sysio()->wait4_out.status >> 8) & 0177) |
|
||||
((sysio()->wait4_out.status & 0xff) << 8);
|
||||
|
||||
return sysio()->wait4_out.pid;
|
||||
}
|
||||
@ -566,6 +605,25 @@ extern "C" void sync(void)
|
||||
}
|
||||
|
||||
|
||||
extern "C" int kill(int pid, int sig)
|
||||
{
|
||||
if (verbose_signals)
|
||||
PDBG("pid = %d, sig = %d", pid, sig);
|
||||
|
||||
sysio()->kill_in.pid = pid;
|
||||
sysio()->kill_in.sig = Noux::Sysio::Signal(sig);
|
||||
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_KILL)) {
|
||||
switch (sysio()->error.kill) {
|
||||
case Noux::Sysio::KILL_ERR_SRCH: errno = ESRCH; break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Time functions **
|
||||
********************/
|
||||
@ -636,9 +694,42 @@ extern "C" int utimes(const char* path, const struct timeval *times)
|
||||
|
||||
extern "C" int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
/* XXX todo */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
if (oldset)
|
||||
*oldset = signal_mask;
|
||||
|
||||
if (!set)
|
||||
return 0;
|
||||
|
||||
switch (how) {
|
||||
case SIG_BLOCK:
|
||||
for (int sig = 1; sig < NSIG; sig++)
|
||||
if (sigismember(set, sig)) {
|
||||
if (verbose_signals)
|
||||
PDBG("signal %d requested to get blocked", sig);
|
||||
sigaddset(&signal_mask, sig);
|
||||
}
|
||||
break;
|
||||
case SIG_UNBLOCK:
|
||||
for (int sig = 1; sig < NSIG; sig++)
|
||||
if (sigismember(set, sig)) {
|
||||
if (verbose_signals)
|
||||
PDBG("signal %d requested to get unblocked", sig);
|
||||
sigdelset(&signal_mask, sig);
|
||||
}
|
||||
break;
|
||||
case SIG_SETMASK:
|
||||
if (verbose_signals)
|
||||
for (int sig = 1; sig < NSIG; sig++)
|
||||
if (sigismember(set, sig))
|
||||
PDBG("signal %d requested to get blocked", sig);
|
||||
signal_mask = *set;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -653,7 +744,7 @@ extern "C" int _sigaction(int signum, const struct sigaction *act, struct sigact
|
||||
if (verbose_signals)
|
||||
PDBG("signum = %d, handler = %p", signum, act ? act->sa_handler : 0);
|
||||
|
||||
if ((signum < 0) || (signum > SIGRTMAX)) {
|
||||
if ((signum < 1) || (signum > NSIG)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
@ -1951,6 +2042,8 @@ extern char **environ;
|
||||
__attribute__((constructor))
|
||||
void init_libc_noux(void)
|
||||
{
|
||||
sigemptyset(&signal_mask);
|
||||
|
||||
/* copy command-line arguments from 'args' ROM dataspace */
|
||||
Genode::Rom_connection args_rom("args");
|
||||
char *args = (char *)Genode::env()->rm_session()->
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include <destruct_queue.h>
|
||||
#include <destruct_dispatcher.h>
|
||||
#include <interrupt_handler.h>
|
||||
#include <kill_broadcaster.h>
|
||||
#include <parent_execve.h>
|
||||
|
||||
#include <local_cpu_service.h>
|
||||
#include <local_ram_service.h>
|
||||
@ -88,6 +90,11 @@ namespace Noux {
|
||||
*/
|
||||
Dataspace_capability ldso_ds_cap();
|
||||
|
||||
/*
|
||||
* Return lock for protecting the signal queue
|
||||
*/
|
||||
Genode::Lock &signal_lock();
|
||||
|
||||
class Child;
|
||||
|
||||
bool is_init_process(Child *child);
|
||||
@ -101,17 +108,11 @@ namespace Noux {
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_receiver *_sig_rec;
|
||||
Parent_exit *_parent_exit;
|
||||
Kill_broadcaster &_kill_broadcaster;
|
||||
Parent_execve &_parent_execve;
|
||||
|
||||
/**
|
||||
* Lock used for implementing blocking syscalls, i.e., select
|
||||
*
|
||||
* The reason to have it as a member variable instead of creating
|
||||
* it on demand is to not have to register and unregister an
|
||||
* interrupt handler at every IO channel on every blocking syscall,
|
||||
* but only once when the IO channel gets added.
|
||||
*/
|
||||
Lock _blocker;
|
||||
Signal_receiver *_sig_rec;
|
||||
|
||||
Allocator *_alloc;
|
||||
Destruct_queue &_destruct_queue;
|
||||
@ -310,7 +311,9 @@ namespace Noux {
|
||||
* system
|
||||
*/
|
||||
Child(char const *binary_name,
|
||||
Family_member *parent,
|
||||
Parent_exit *parent_exit,
|
||||
Kill_broadcaster &kill_broadcaster,
|
||||
Parent_execve &parent_execve,
|
||||
int pid,
|
||||
Signal_receiver *sig_rec,
|
||||
Dir_file_system *root_dir,
|
||||
@ -324,8 +327,11 @@ namespace Noux {
|
||||
Destruct_queue &destruct_queue,
|
||||
bool verbose)
|
||||
:
|
||||
Family_member(pid, parent),
|
||||
Family_member(pid),
|
||||
Destruct_queue::Element<Child>(destruct_alloc),
|
||||
_parent_exit(parent_exit),
|
||||
_kill_broadcaster(kill_broadcaster),
|
||||
_parent_execve(parent_execve),
|
||||
_sig_rec(sig_rec),
|
||||
_destruct_queue(destruct_queue),
|
||||
_destruct_dispatcher(_destruct_queue, this),
|
||||
@ -354,7 +360,7 @@ namespace Noux {
|
||||
_entrypoint, _local_noux_service,
|
||||
_local_rm_service, _local_rom_service,
|
||||
_parent_services,
|
||||
*this, *this, _destruct_context_cap,
|
||||
*this, parent_exit, *this, _destruct_context_cap,
|
||||
_resources.ram, verbose),
|
||||
_child(forked ? Dataspace_capability() : _elf._binary_ds,
|
||||
_resources.ram.cap(), _resources.cpu.cap(),
|
||||
@ -457,8 +463,10 @@ namespace Noux {
|
||||
fd = File_descriptor_registry::add_io_channel(io_channel, fd);
|
||||
|
||||
/* Register the interrupt handler only once per IO channel */
|
||||
if (_is_the_only_fd_for_io_channel(fd, io_channel))
|
||||
io_channel->register_interrupt_handler(this);
|
||||
if (_is_the_only_fd_for_io_channel(fd, io_channel)) {
|
||||
Io_channel_listener *l = new (env()->heap()) Io_channel_listener(this);
|
||||
io_channel->register_interrupt_handler(l);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
@ -471,8 +479,11 @@ namespace Noux {
|
||||
* Unregister the interrupt handler only if there are no other
|
||||
* file descriptors associated with the IO channel.
|
||||
*/
|
||||
if (_is_the_only_fd_for_io_channel(fd, io_channel))
|
||||
io_channel->unregister_interrupt_handler(this);
|
||||
if (_is_the_only_fd_for_io_channel(fd, io_channel)) {
|
||||
Io_channel_listener *l = io_channel->lookup_io_channel_listener(this);
|
||||
io_channel->unregister_interrupt_handler(l);
|
||||
Genode::destroy(env()->heap(), l);
|
||||
}
|
||||
|
||||
File_descriptor_registry::remove_io_channel(fd);
|
||||
}
|
||||
@ -486,14 +497,14 @@ namespace Noux {
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
** Interrupt_handler interface **
|
||||
*********************************/
|
||||
/*****************************
|
||||
** Family_member interface **
|
||||
*****************************/
|
||||
|
||||
void handle_interrupt()
|
||||
void submit_signal(Noux::Sysio::Signal sig)
|
||||
{
|
||||
try {
|
||||
_pending_signals.add(Sysio::SIG_INT);
|
||||
_pending_signals.add(sig);
|
||||
} catch (Signal_queue::Overflow) {
|
||||
PERR("signal queue is full - signal dropped");
|
||||
}
|
||||
@ -501,6 +512,67 @@ namespace Noux {
|
||||
_blocker.unlock();
|
||||
}
|
||||
|
||||
Family_member *do_execve(const char *filename,
|
||||
Args const &args,
|
||||
Sysio::Env const &env,
|
||||
bool verbose)
|
||||
{
|
||||
Lock::Guard signal_lock_guard(signal_lock());
|
||||
|
||||
Child *child = new Child(filename,
|
||||
_parent_exit,
|
||||
_kill_broadcaster,
|
||||
_parent_execve,
|
||||
pid(),
|
||||
_sig_rec,
|
||||
root_dir(),
|
||||
args,
|
||||
env,
|
||||
_cap_session,
|
||||
_parent_services,
|
||||
_resources.ep,
|
||||
false,
|
||||
Genode::env()->heap(),
|
||||
_destruct_queue,
|
||||
verbose);
|
||||
|
||||
_assign_io_channels_to(child);
|
||||
|
||||
/* move the signal queue */
|
||||
while (!_pending_signals.empty())
|
||||
child->_pending_signals.add(_pending_signals.get());
|
||||
|
||||
/*
|
||||
* Close all open files.
|
||||
*
|
||||
* This action is not part of the child destructor,
|
||||
* because in the case that a child exits itself,
|
||||
* it may need to close all files to unblock the
|
||||
* parent (which might be reading from a pipe) before
|
||||
* the parent can destroy the child object.
|
||||
*/
|
||||
flush();
|
||||
|
||||
/* signal main thread to remove ourself */
|
||||
Genode::Signal_transmitter(_destruct_context_cap).submit();
|
||||
|
||||
/* start executing the new process */
|
||||
child->start();
|
||||
|
||||
/* this child will be removed by the execve_finalization_dispatcher */
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
** Interrupt_handler interface **
|
||||
*********************************/
|
||||
|
||||
void handle_interrupt()
|
||||
{
|
||||
submit_signal(Sysio::SIG_INT);
|
||||
}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
/* Noux includes */
|
||||
#include <family_member.h>
|
||||
#include <parent_exit.h>
|
||||
#include <file_descriptor_registry.h>
|
||||
#include <local_noux_service.h>
|
||||
#include <local_rm_service.h>
|
||||
@ -40,6 +41,7 @@ namespace Noux {
|
||||
Local_rom_service &_local_rom_service;
|
||||
Service_registry &_parent_services;
|
||||
Family_member &_family_member;
|
||||
Parent_exit *_parent_exit;
|
||||
File_descriptor_registry &_file_descriptor_registry;
|
||||
Signal_context_capability _destruct_context_cap;
|
||||
Ram_session &_ref_ram_session;
|
||||
@ -57,6 +59,7 @@ namespace Noux {
|
||||
Local_rom_service &local_rom_service,
|
||||
Service_registry &parent_services,
|
||||
Family_member &family_member,
|
||||
Parent_exit *parent_exit,
|
||||
File_descriptor_registry &file_descriptor_registry,
|
||||
Signal_context_capability destruct_context_cap,
|
||||
Ram_session &ref_ram_session,
|
||||
@ -72,6 +75,7 @@ namespace Noux {
|
||||
_local_rom_service(local_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_ram_session(ref_ram_session),
|
||||
@ -130,11 +134,15 @@ namespace Noux {
|
||||
*/
|
||||
_file_descriptor_registry.flush();
|
||||
|
||||
_family_member.wakeup_parent(exit_value);
|
||||
_family_member.exit(exit_value);
|
||||
|
||||
/* handle exit of the init process */
|
||||
if (_family_member.parent() == 0)
|
||||
/* notify the parent */
|
||||
if (_parent_exit)
|
||||
_parent_exit->exit_child();
|
||||
else {
|
||||
/* handle exit of the init process */
|
||||
Signal_transmitter(_destruct_context_cap).submit();
|
||||
}
|
||||
}
|
||||
|
||||
Ram_session *ref_ram_session()
|
||||
|
@ -18,34 +18,42 @@
|
||||
#include <util/list.h>
|
||||
#include <base/lock.h>
|
||||
|
||||
/* Noux includes */
|
||||
#include <parent_exit.h>
|
||||
#include <parent_execve.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
class Family_member : public List<Family_member>::Element
|
||||
class Family_member : public List<Family_member>::Element,
|
||||
public Parent_exit,
|
||||
public Parent_execve
|
||||
{
|
||||
private:
|
||||
|
||||
int const _pid;
|
||||
Lock _lock;
|
||||
List<Family_member> _list;
|
||||
Family_member * const _parent;
|
||||
bool _has_exited;
|
||||
int _exit_status;
|
||||
Semaphore _wait4_blocker;
|
||||
|
||||
void _wakeup_wait4() { _wait4_blocker.up(); }
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Lock used for implementing blocking syscalls,
|
||||
* i.e., select, wait4, ...
|
||||
*/
|
||||
Lock _blocker;
|
||||
|
||||
public:
|
||||
|
||||
Family_member(int pid, Family_member *parent)
|
||||
: _pid(pid), _parent(parent), _has_exited(false), _exit_status(0)
|
||||
Family_member(int pid)
|
||||
: _pid(pid), _has_exited(false), _exit_status(0)
|
||||
{ }
|
||||
|
||||
virtual ~Family_member() { }
|
||||
|
||||
int pid() const { return _pid; }
|
||||
|
||||
Family_member *parent() { return _parent; }
|
||||
|
||||
int exit_status() const { return _exit_status; }
|
||||
|
||||
/**
|
||||
@ -66,15 +74,73 @@ namespace Noux {
|
||||
_list.remove(member);
|
||||
}
|
||||
|
||||
virtual void submit_signal(Noux::Sysio::Signal sig) = 0;
|
||||
|
||||
/**
|
||||
* Called by the parent (originates from Kill_broadcaster)
|
||||
*/
|
||||
bool deliver_kill(int pid, Noux::Sysio::Signal sig)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
||||
if (pid == _pid) {
|
||||
submit_signal(sig);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (Family_member *child = _list.first(); child; child = child->next())
|
||||
if (child->deliver_kill(pid, sig))
|
||||
result = true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent_exit interface
|
||||
*/
|
||||
|
||||
/* Called by the child on the parent (via Parent_exit) */
|
||||
void exit_child()
|
||||
{
|
||||
submit_signal(Sysio::Signal::SIG_CHLD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parent_execve interface
|
||||
*/
|
||||
|
||||
/* Called by the parent from 'execve_child()' */
|
||||
virtual Family_member *do_execve(const char *filename,
|
||||
Args const &args,
|
||||
Sysio::Env const &env,
|
||||
bool verbose) = 0;
|
||||
|
||||
/* Called by the child on the parent (via Parent_execve) */
|
||||
void execve_child(Family_member &child,
|
||||
const char *filename,
|
||||
Args const &args,
|
||||
Sysio::Env const &env,
|
||||
bool verbose)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
Family_member *new_child = child.do_execve(filename,
|
||||
args,
|
||||
env,
|
||||
verbose);
|
||||
_list.insert(new_child);
|
||||
_list.remove(&child);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tell the parent that we exited
|
||||
*/
|
||||
void wakeup_parent(int exit_status)
|
||||
void exit(int exit_status)
|
||||
{
|
||||
_exit_status = exit_status;
|
||||
_has_exited = true;
|
||||
if (_parent)
|
||||
_parent->_wakeup_wait4();
|
||||
}
|
||||
|
||||
Family_member *poll4()
|
||||
@ -95,13 +161,18 @@ namespace Noux {
|
||||
*/
|
||||
Family_member *wait4()
|
||||
{
|
||||
for (;;) {
|
||||
Family_member *result = poll4();
|
||||
if (result)
|
||||
return result;
|
||||
/* reset the blocker lock to the 'locked' state */
|
||||
_blocker.unlock();
|
||||
_blocker.lock();
|
||||
|
||||
_wait4_blocker.down();
|
||||
}
|
||||
Family_member *result = poll4();
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
_blocker.lock();
|
||||
|
||||
/* either a child exited or a signal occurred */
|
||||
return poll4();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -14,12 +14,9 @@
|
||||
#ifndef _NOUX__INTERRUPT_HANDLER__H_
|
||||
#define _NOUX__INTERRUPT_HANDLER__H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Interrupt_handler : List<Interrupt_handler>::Element
|
||||
struct Interrupt_handler
|
||||
{
|
||||
virtual void handle_interrupt() = 0;
|
||||
};
|
||||
|
@ -24,10 +24,14 @@
|
||||
#include <noux_session/sysio.h>
|
||||
#include <shared_pointer.h>
|
||||
#include <wake_up_notifier.h>
|
||||
#include <interrupt_handler.h>
|
||||
#include <io_channel_listener.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
class Terminal_io_channel;
|
||||
|
||||
extern Genode::Lock &signal_lock();
|
||||
|
||||
/**
|
||||
* Input/output channel backend that is used for calling
|
||||
* different methos which does not belong to the original
|
||||
@ -53,10 +57,10 @@ namespace Noux {
|
||||
* List of notifiers (i.e., processes) used by threads that block
|
||||
* for an I/O-channel event
|
||||
*/
|
||||
List<Wake_up_notifier> _notifiers;
|
||||
Lock _notifiers_lock;
|
||||
List<Interrupt_handler> _interrupt_handlers;
|
||||
Lock _interrupt_handlers_lock;
|
||||
List<Wake_up_notifier> _notifiers;
|
||||
Lock _notifiers_lock;
|
||||
List<Io_channel_listener> _interrupt_handlers;
|
||||
Lock _interrupt_handlers_lock;
|
||||
|
||||
public:
|
||||
|
||||
@ -140,7 +144,7 @@ namespace Noux {
|
||||
* This function is called by Child objects to get woken up if the
|
||||
* terminal sends, for example, Ctrl-C.
|
||||
*/
|
||||
void register_interrupt_handler(Interrupt_handler *handler)
|
||||
void register_interrupt_handler(Io_channel_listener *handler)
|
||||
{
|
||||
Lock::Guard guard(_interrupt_handlers_lock);
|
||||
|
||||
@ -150,23 +154,37 @@ namespace Noux {
|
||||
/**
|
||||
* Unregister interrupt handler
|
||||
*/
|
||||
void unregister_interrupt_handler(Interrupt_handler *handler)
|
||||
void unregister_interrupt_handler(Io_channel_listener *handler)
|
||||
{
|
||||
Lock::Guard guard(_interrupt_handlers_lock);
|
||||
|
||||
_interrupt_handlers.remove(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the 'Io_channel_listener' object which contains the given
|
||||
* 'Interrupt_handler' pointer
|
||||
*/
|
||||
Io_channel_listener *lookup_io_channel_listener(Interrupt_handler *handler)
|
||||
{
|
||||
for (Io_channel_listener *l = _interrupt_handlers.first();
|
||||
l; l = l->next())
|
||||
if (l->object() == handler)
|
||||
return l;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell all registered handlers about an interrupt event
|
||||
*/
|
||||
void invoke_all_interrupt_handlers()
|
||||
{
|
||||
Lock::Guard signal_lock_guard(signal_lock());
|
||||
Lock::Guard guard(_interrupt_handlers_lock);
|
||||
|
||||
for (Interrupt_handler *h = _interrupt_handlers.first();
|
||||
h; h = h->next())
|
||||
h->handle_interrupt();
|
||||
for (Io_channel_listener *l = _interrupt_handlers.first();
|
||||
l; l = l->next())
|
||||
l->object()->handle_interrupt();
|
||||
}
|
||||
|
||||
/**
|
||||
|
28
ports/src/noux/io_channel_listener.h
Normal file
28
ports/src/noux/io_channel_listener.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* \brief IO channel listener
|
||||
* \author Christian Prochaska
|
||||
* \date 2014-01-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _NOUX__IO_CHANNEL_LISTENER__H_
|
||||
#define _NOUX__IO_CHANNEL_LISTENER__H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
|
||||
/* Noux includes */
|
||||
#include <interrupt_handler.h>
|
||||
|
||||
namespace Noux {
|
||||
typedef List_element<Interrupt_handler> Io_channel_listener;
|
||||
}
|
||||
|
||||
#endif /* _NOUX__IO_CHANNEL_LISTENER__H_ */
|
||||
|
29
ports/src/noux/kill_broadcaster.h
Normal file
29
ports/src/noux/kill_broadcaster.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* \brief Kill_broadcaster interface
|
||||
* \author Christian Prochaska
|
||||
* \date 2014-01-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _NOUX__KILL_BROADCASTER__H_
|
||||
#define _NOUX__KILL_BROADCASTER__H_
|
||||
|
||||
/* Noux includes */
|
||||
#include <noux_session/sysio.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Kill_broadcaster
|
||||
{
|
||||
virtual bool kill(int pid, Noux::Sysio::Signal sig) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _NOUX__KILL_BROADCASTER__H_ */
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <user_info.h>
|
||||
#include <io_receptor_registry.h>
|
||||
#include <destruct_queue.h>
|
||||
#include <kill_broadcaster.h>
|
||||
|
||||
|
||||
static const bool verbose_quota = false;
|
||||
@ -46,7 +47,6 @@ namespace Noux {
|
||||
|
||||
extern void init_network();
|
||||
|
||||
|
||||
/**
|
||||
* Timeout thread for SYSCALL_SELECT
|
||||
*/
|
||||
@ -219,7 +219,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
size_t path_len = strlen(_sysio->stat_in.path);
|
||||
uint32_t path_hash = hash_path(_sysio->stat_in.path, path_len);
|
||||
|
||||
bool result = root_dir()->stat(_sysio, _sysio->stat_in.path);
|
||||
result = root_dir()->stat(_sysio, _sysio->stat_in.path);
|
||||
|
||||
/**
|
||||
* Instead of using the uid/gid given by the actual file system
|
||||
@ -232,14 +232,14 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->stat_out.st.inode = path_hash;
|
||||
}
|
||||
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_FSTAT:
|
||||
{
|
||||
Shared_pointer<Io_channel> io = _lookup_channel(_sysio->fstat_in.fd);
|
||||
|
||||
bool result = io->fstat(_sysio);
|
||||
result = io->fstat(_sysio);
|
||||
|
||||
if (result) {
|
||||
Sysio::Path path;
|
||||
@ -255,7 +255,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_FCNTL:
|
||||
@ -265,16 +265,18 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
/* we assume that there is only the close-on-execve flag */
|
||||
_lookup_channel(_sysio->fcntl_in.fd)->close_on_execve =
|
||||
!!_sysio->fcntl_in.long_arg;
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return _lookup_channel(_sysio->fcntl_in.fd)->fcntl(_sysio);
|
||||
result = _lookup_channel(_sysio->fcntl_in.fd)->fcntl(_sysio);
|
||||
break;
|
||||
|
||||
case SYSCALL_OPEN:
|
||||
{
|
||||
Vfs_handle *vfs_handle = root_dir()->open(_sysio, _sysio->open_in.path);
|
||||
if (!vfs_handle)
|
||||
return false;
|
||||
break;
|
||||
|
||||
char const *leaf_path = root_dir()->leaf_path(_sysio->open_in.path);
|
||||
|
||||
@ -294,26 +296,31 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
Genode::env()->heap());
|
||||
|
||||
_sysio->open_out.fd = add_io_channel(channel);
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_CLOSE:
|
||||
{
|
||||
remove_io_channel(_sysio->close_in.fd);
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_IOCTL:
|
||||
|
||||
return _lookup_channel(_sysio->ioctl_in.fd)->ioctl(_sysio);
|
||||
result = _lookup_channel(_sysio->ioctl_in.fd)->ioctl(_sysio);
|
||||
break;
|
||||
|
||||
case SYSCALL_LSEEK:
|
||||
|
||||
return _lookup_channel(_sysio->lseek_in.fd)->lseek(_sysio);
|
||||
result = _lookup_channel(_sysio->lseek_in.fd)->lseek(_sysio);
|
||||
break;
|
||||
|
||||
case SYSCALL_DIRENT:
|
||||
|
||||
return _lookup_channel(_sysio->dirent_in.fd)->dirent(_sysio);
|
||||
result = _lookup_channel(_sysio->dirent_in.fd)->dirent(_sysio);
|
||||
break;
|
||||
|
||||
case SYSCALL_EXECVE:
|
||||
{
|
||||
@ -327,7 +334,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
if (!binary_ds.valid()) {
|
||||
_sysio->error.execve = Sysio::EXECVE_NONEXISTENT;
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
Child_env<sizeof(_sysio->execve_in.args)>
|
||||
@ -340,57 +347,28 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
if (!binary_ds.valid()) {
|
||||
_sysio->error.execve = Sysio::EXECVE_NONEXISTENT;
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
root_dir()->release(child_env.binary_name(), binary_ds);
|
||||
|
||||
try {
|
||||
Child *child = new Child(child_env.binary_name(),
|
||||
parent(),
|
||||
pid(),
|
||||
_sig_rec,
|
||||
root_dir(),
|
||||
child_env.args(),
|
||||
child_env.env(),
|
||||
_cap_session,
|
||||
_parent_services,
|
||||
_resources.ep,
|
||||
false,
|
||||
env()->heap(),
|
||||
_destruct_queue,
|
||||
verbose);
|
||||
|
||||
/* replace ourself by the new child at the parent */
|
||||
parent()->remove(this);
|
||||
parent()->insert(child);
|
||||
|
||||
_assign_io_channels_to(child);
|
||||
_parent_execve.execve_child(*this,
|
||||
child_env.binary_name(),
|
||||
child_env.args(),
|
||||
child_env.env(),
|
||||
verbose);
|
||||
|
||||
/*
|
||||
* Close all open files.
|
||||
*
|
||||
* This action is not part of the child destructor,
|
||||
* because in the case that a child exits itself,
|
||||
* it may need to close all files to unblock the
|
||||
* parent (which might be reading from a pipe) before
|
||||
* the parent can destroy the child object.
|
||||
* 'return' instead of 'break' to skip possible signal delivery,
|
||||
* which might cause the old child process to exit itself
|
||||
*/
|
||||
flush();
|
||||
|
||||
/* signal main thread to remove ourself */
|
||||
Genode::Signal_transmitter(_destruct_context_cap).submit();
|
||||
|
||||
/* start executing the new process */
|
||||
child->start();
|
||||
|
||||
/* this child will be removed by the execve_finalization_dispatcher */
|
||||
return true;
|
||||
}
|
||||
catch (Child::Binary_does_not_exist) {
|
||||
_sysio->error.execve = Sysio::EXECVE_NONEXISTENT; }
|
||||
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_SELECT:
|
||||
@ -593,6 +571,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
*/
|
||||
Child *child = new Child(_child_policy.name(),
|
||||
this,
|
||||
_kill_broadcaster,
|
||||
*this,
|
||||
new_pid,
|
||||
_sig_rec,
|
||||
root_dir(),
|
||||
@ -622,7 +602,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
_sysio->fork_out.pid = new_pid;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_GETPID:
|
||||
@ -645,10 +626,16 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
static_cast<Child *>(exited)->submit_exit_signal();
|
||||
|
||||
} else {
|
||||
_sysio->wait4_out.pid = 0;
|
||||
_sysio->wait4_out.status = 0;
|
||||
if (_sysio->wait4_in.nohang) {
|
||||
_sysio->wait4_out.pid = 0;
|
||||
_sysio->wait4_out.status = 0;
|
||||
} else {
|
||||
_sysio->error.wait4 = Sysio::WAIT4_ERR_INTERRUPT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_PIPE:
|
||||
@ -663,7 +650,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->pipe_out.fd[0] = add_io_channel(pipe_source);
|
||||
_sysio->pipe_out.fd[1] = add_io_channel(pipe_sink);
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_DUP2:
|
||||
@ -673,30 +661,36 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
_sysio->dup2_out.fd = fd;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_UNLINK:
|
||||
|
||||
return root_dir()->unlink(_sysio, _sysio->unlink_in.path);
|
||||
result = root_dir()->unlink(_sysio, _sysio->unlink_in.path);
|
||||
break;
|
||||
|
||||
case SYSCALL_READLINK:
|
||||
|
||||
return root_dir()->readlink(_sysio, _sysio->readlink_in.path);
|
||||
result = root_dir()->readlink(_sysio, _sysio->readlink_in.path);
|
||||
break;
|
||||
|
||||
|
||||
case SYSCALL_RENAME:
|
||||
|
||||
return root_dir()->rename(_sysio, _sysio->rename_in.from_path,
|
||||
_sysio->rename_in.to_path);
|
||||
result = root_dir()->rename(_sysio, _sysio->rename_in.from_path,
|
||||
_sysio->rename_in.to_path);
|
||||
break;
|
||||
|
||||
case SYSCALL_MKDIR:
|
||||
|
||||
return root_dir()->mkdir(_sysio, _sysio->mkdir_in.path);
|
||||
result = root_dir()->mkdir(_sysio, _sysio->mkdir_in.path);
|
||||
break;
|
||||
|
||||
case SYSCALL_SYMLINK:
|
||||
|
||||
return root_dir()->symlink(_sysio, _sysio->symlink_in.newpath);
|
||||
result = root_dir()->symlink(_sysio, _sysio->symlink_in.newpath);
|
||||
break;
|
||||
|
||||
case SYSCALL_USERINFO:
|
||||
{
|
||||
@ -705,7 +699,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->userinfo_out.uid = Noux::user_info()->uid;
|
||||
_sysio->userinfo_out.gid = Noux::user_info()->gid;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -713,16 +708,23 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
* got a unknown uid.
|
||||
*/
|
||||
if (_sysio->userinfo_in.uid != Noux::user_info()->uid)
|
||||
return false;
|
||||
break;
|
||||
|
||||
Genode::memcpy(_sysio->userinfo_out.name, Noux::user_info()->name, sizeof(Noux::user_info()->name));
|
||||
Genode::memcpy(_sysio->userinfo_out.shell, Noux::user_info()->shell, sizeof(Noux::user_info()->shell));
|
||||
Genode::memcpy(_sysio->userinfo_out.home, Noux::user_info()->home, sizeof(Noux::user_info()->home));
|
||||
Genode::memcpy(_sysio->userinfo_out.name,
|
||||
Noux::user_info()->name,
|
||||
sizeof(Noux::user_info()->name));
|
||||
Genode::memcpy(_sysio->userinfo_out.shell,
|
||||
Noux::user_info()->shell,
|
||||
sizeof(Noux::user_info()->shell));
|
||||
Genode::memcpy(_sysio->userinfo_out.home,
|
||||
Noux::user_info()->home,
|
||||
sizeof(Noux::user_info()->home));
|
||||
|
||||
_sysio->userinfo_out.uid = user_info()->uid;
|
||||
_sysio->userinfo_out.gid = user_info()->gid;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_GETTIMEOFDAY:
|
||||
@ -741,7 +743,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->gettimeofday_out.sec = (time / 1000);
|
||||
_sysio->gettimeofday_out.usec = (time % 1000) * 1000;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_CLOCK_GETTIME:
|
||||
@ -759,7 +762,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->clock_gettime_out.sec = (time / 1000);
|
||||
_sysio->clock_gettime_out.nsec = 0;
|
||||
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@ -768,12 +772,12 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_sysio->clock_gettime_out.nsec = 0;
|
||||
_sysio->error.clock = Sysio::CLOCK_ERR_INVALID;
|
||||
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@ -786,13 +790,26 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
* But we return true anyway to keep certain programs, e.g. make
|
||||
* happy.
|
||||
*/
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_SYNC:
|
||||
{
|
||||
root_dir()->sync();
|
||||
return true;
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_KILL:
|
||||
{
|
||||
if (_kill_broadcaster.kill(_sysio->kill_in.pid,
|
||||
_sysio->kill_in.sig))
|
||||
result = true;
|
||||
else
|
||||
_sysio->error.kill = Sysio::KILL_ERR_SRCH;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SYSCALL_SOCKET:
|
||||
@ -809,7 +826,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
case SYSCALL_SHUTDOWN:
|
||||
case SYSCALL_CONNECT:
|
||||
|
||||
return _syscall_net(sc);
|
||||
result = _syscall_net(sc);
|
||||
break;
|
||||
|
||||
case SYSCALL_INVALID: break;
|
||||
}
|
||||
@ -823,8 +841,9 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
/* handle signals which might have occured */
|
||||
while (!_pending_signals.empty() &&
|
||||
(_sysio->pending_signals.avail_capacity() > 0))
|
||||
(_sysio->pending_signals.avail_capacity() > 0)) {
|
||||
_sysio->pending_signals.add(_pending_signals.get());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -956,6 +975,20 @@ Genode::Dataspace_capability Noux::ldso_ds_cap()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This lock is needed to delay the insertion of signals into a child object.
|
||||
* This is necessary during an 'execve()' syscall, when signals get copied from
|
||||
* the old child object to the new one. Without the lock, an IO channel could
|
||||
* insert a signal into both objects, which could lead to a duplicated signal
|
||||
* in the new child object.
|
||||
*/
|
||||
Genode::Lock &Noux::signal_lock()
|
||||
{
|
||||
static Genode::Lock inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
void *operator new (Genode::size_t size) {
|
||||
return Genode::env()->heap()->alloc(size); }
|
||||
|
||||
@ -1007,8 +1040,22 @@ int main(int argc, char **argv)
|
||||
static Genode::Signal_receiver sig_rec;
|
||||
static Destruct_queue destruct_queue;
|
||||
|
||||
struct Kill_broadcaster_implementation : Kill_broadcaster
|
||||
{
|
||||
Family_member *init_process;
|
||||
|
||||
bool kill(int pid, Noux::Sysio::Signal sig)
|
||||
{
|
||||
return init_process->deliver_kill(pid, sig);
|
||||
}
|
||||
};
|
||||
|
||||
static Kill_broadcaster_implementation kill_broadcaster;
|
||||
|
||||
init_child = new Noux::Child(name_of_init_process(),
|
||||
0,
|
||||
kill_broadcaster,
|
||||
*init_child,
|
||||
pid_allocator()->alloc(),
|
||||
&sig_rec,
|
||||
&root_dir,
|
||||
@ -1022,6 +1069,8 @@ int main(int argc, char **argv)
|
||||
destruct_queue,
|
||||
verbose);
|
||||
|
||||
kill_broadcaster.init_process = init_child;
|
||||
|
||||
/*
|
||||
* I/O channels must be dynamically allocated to handle cases where the
|
||||
* init program closes one of these.
|
||||
|
36
ports/src/noux/parent_execve.h
Normal file
36
ports/src/noux/parent_execve.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* \brief Parent_execve interface
|
||||
* \author Christian Prochaska
|
||||
* \date 2014-01-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _NOUX__PARENT_EXECVE__H_
|
||||
#define _NOUX__PARENT_EXECVE__H_
|
||||
|
||||
/* Noux includes */
|
||||
#include <noux_session/sysio.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Family_member;
|
||||
|
||||
struct Parent_execve
|
||||
{
|
||||
virtual void execve_child(Family_member &child,
|
||||
const char *filename,
|
||||
Args const &args,
|
||||
Sysio::Env const &env,
|
||||
bool verbose) = 0;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _NOUX__PARENT_EXECVE__H_ */
|
||||
|
33
ports/src/noux/parent_exit.h
Normal file
33
ports/src/noux/parent_exit.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* \brief Parent_exit interface
|
||||
* \author Christian Prochaska
|
||||
* \date 2014-01-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _NOUX__PARENT_EXIT__H_
|
||||
#define _NOUX__PARENT_EXIT__H_
|
||||
|
||||
namespace Noux {
|
||||
|
||||
struct Family_member;
|
||||
|
||||
struct Parent_exit
|
||||
{
|
||||
/*
|
||||
* Handle the exiting of a child
|
||||
*/
|
||||
|
||||
virtual void exit_child() = 0;
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#endif /* _NOUX__PARENT_EXIT__H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user