Implementation of wait4 syscall

The 'noux_bash.run' script has become able to present the user with an
interactive bash shell for executing various coreutils programs. It is
still pretty limited, i.e., the environment is not correctly passed to
child processes and pipes are not supported. But bash and coreutils are
operational.
This commit is contained in:
Norman Feske 2012-02-24 23:43:35 +01:00
parent 7e7d290008
commit 780507f42b
4 changed files with 133 additions and 27 deletions

View File

@ -95,8 +95,6 @@ append config {
<fstab> <tar name="bash.tar" at="/"/> </fstab>
<start name="/bin/bash">
<env name="TERM" value="linux" />
<env name="FOO" value="/slashemdir,BAR=baz" />
<env name="FUZ" value="holla\"die waldfee" />
</start>
</config>
</start>

View File

@ -93,7 +93,6 @@ namespace Noux {
/* trigger exit of main event loop */
init_process_exited();
}
/* XXX destroy child */
}
};
@ -119,13 +118,101 @@ namespace Noux {
};
class Child : private Child_policy,
public Rpc_object<Session>,
public File_descriptor_registry
class Family_member : public List<Family_member>::Element
{
private:
int const _pid;
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();
}
public:
Family_member(int pid, Family_member *parent)
: _pid(pid), _parent(parent), _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; }
/**
* Called by the parent at creation time of the process
*/
void insert(Family_member *member)
{
Lock::Guard guard(_lock);
_list.insert(member);
}
/**
* Called by the parent from the return path of the wait4 syscall
*/
void remove(Family_member *member)
{
Lock::Guard guard(_lock);
_list.remove(member);
}
/**
* Tell the parent that we exited
*/
void wakeup_parent(int exit_status)
{
_exit_status = exit_status;
_has_exited = true;
if (_parent)
_parent->_wakeup_wait4();
}
Family_member *poll4()
{
Lock::Guard guard(_lock);
/* check if any of our children has exited */
Family_member *curr = _list.first();
for (; curr; curr = curr->next()) {
if (curr->_has_exited)
return curr;
}
return 0;
}
/**
* Wait for the exit of any of our children
*/
Family_member *wait4()
{
for (;;) {
Family_member *result = poll4();
if (result)
return result;
_wait4_blocker.down();
}
}
};
class Child : private Child_policy,
public Rpc_object<Session>,
public File_descriptor_registry,
public Family_member
{
private:
Signal_receiver *_sig_rec;
@ -281,6 +368,7 @@ namespace Noux {
* true if the child is a fork from another child
*/
Child(char const *name,
Family_member *parent,
int pid,
Signal_receiver *sig_rec,
Vfs *vfs,
@ -291,7 +379,7 @@ namespace Noux {
Rpc_entrypoint &resources_ep,
bool forked)
:
_pid(pid),
Family_member(pid, parent),
_sig_rec(sig_rec),
_exit_dispatcher(this),
_exit_context_cap(sig_rec->manage(&_exit_dispatcher)),
@ -324,6 +412,11 @@ namespace Noux {
~Child()
{
PDBG("Destructing child %p", this);
_sig_rec->dissolve(&_execve_cleanup_dispatcher);
_sig_rec->dissolve(&_exit_dispatcher);
/* XXX _binary_ds */
_entrypoint.dissolve(this);
@ -387,7 +480,12 @@ namespace Noux {
void exit(int exit_value)
{
PINF("child %s exited with exit value %d", _name, exit_value);
Signal_transmitter(_exit_context_cap).submit();
wakeup_parent(exit_value);
/* handle exit of the init process */
if (parent() == 0)
Signal_transmitter(_exit_context_cap).submit();
}
Ram_session *ref_ram_session()

View File

@ -48,7 +48,7 @@ namespace Noux {
return false;
}
void _assign_fd(int fd, Shared_pointer<Io_channel> io_channel)
void _assign_fd(int fd, Shared_pointer<Io_channel> &io_channel)
{
_fds[fd].io_channel = io_channel;
_fds[fd].allocated = true;

View File

@ -32,7 +32,7 @@
* - pipe
* ;- read init binary from vfs
* - import env into child (execve and fork)
* - shell
* ;- shell
* - debug 'find'
* - stacked file system infrastructure
* - TMP file system
@ -75,7 +75,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
{
if (verbose_syscall)
Genode::printf("PID %d -> SYSCALL %s\n",
_pid, Noux::Session::syscall_name(sc));
pid(), Noux::Session::syscall_name(sc));
try {
switch (sc) {
@ -157,7 +157,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
char const *env = "PWD=\"/\"";
char const *filename = _sysio->execve_in.filename;
Child *child = new Child(filename,
_pid,
parent(),
pid(),
_sig_rec,
_vfs,
Args(_sysio->execve_in.args,
@ -168,6 +169,10 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
_resources.ep,
false);
/* replace ourself by the new child at the parent */
parent()->remove(this);
parent()->insert(child);
_assign_io_channels_to(child);
/* signal main thread to remove ourself */
@ -290,6 +295,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
* reusing the name of the parent.
*/
Child *child = new Child(name(),
this,
new_pid,
_sig_rec,
_vfs,
@ -300,6 +306,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
_resources.ep,
true);
Family_member::insert(child);
_assign_io_channels_to(child);
/* copy our address space into the new child */
@ -319,25 +327,25 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
case SYSCALL_GETPID:
{
_sysio->getpid_out.pid = _pid;
_sysio->getpid_out.pid = pid();
return true;
}
case SYSCALL_WAIT4:
{
PINF("SYSCALL_WAIT4 called");
Family_member *exited = _sysio->wait4_in.nohang ? poll4() : wait4();
/*
* XXX check if one of out children exited
*/
if (exited) {
_sysio->wait4_out.pid = exited->pid();
_sysio->wait4_out.status = exited->exit_status();
Family_member::remove(exited);
if (!_sysio->wait4_in.nohang)
_blocker.down();
_sysio->wait4_out.pid = -1;
_sysio->wait4_out.status = 0;
PINF("SYSCALL_WAIT4 returning");
/* destroy 'Noux::Child' */
destroy(Genode::env()->heap(), exited);
} else {
_sysio->wait4_out.pid = 0;
_sysio->wait4_out.status = 0;
}
return true;
}
@ -504,6 +512,7 @@ int main(int argc, char **argv)
static Genode::Signal_receiver sig_rec;
init_child = new Noux::Child(name_of_init_process(),
0,
pid_allocator()->alloc(),
&sig_rec,
&vfs,
@ -540,8 +549,9 @@ int main(int argc, char **argv)
Signal_dispatcher *dispatcher =
static_cast<Signal_dispatcher *>(signal.context());
for (int i = 0; i < signal.num(); i++)
dispatcher->dispatch();
if (dispatcher)
for (int i = 0; i < signal.num(); i++)
dispatcher->dispatch();
}
PINF("-- exiting noux ---");