mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
Handle lifetime of dynamic allocations in Noux
This commit is contained in:
parent
4e3be6b146
commit
a9152ff412
@ -38,6 +38,9 @@
|
||||
#include <termios.h>
|
||||
|
||||
|
||||
enum { verbose = false };
|
||||
|
||||
|
||||
void *operator new (size_t, void *ptr) { return ptr; }
|
||||
|
||||
|
||||
@ -166,13 +169,15 @@ static bool serialize_string_array(char const * const * array, char *dst, Genode
|
||||
extern "C" int execve(const char *filename, char *const argv[],
|
||||
char *const envp[])
|
||||
{
|
||||
PDBG("filename=%s", filename);
|
||||
if (verbose) {
|
||||
PDBG("filename=%s", filename);
|
||||
|
||||
for (int i = 0; argv[i]; i++)
|
||||
PDBG("argv[%d]='%s'", i, argv[i]);
|
||||
for (int i = 0; argv[i]; i++)
|
||||
PDBG("argv[%d]='%s'", i, argv[i]);
|
||||
|
||||
for (int i = 0; envp[i]; i++)
|
||||
PDBG("envp[%d]='%s'", i, envp[i]);
|
||||
for (int i = 0; envp[i]; i++)
|
||||
PDBG("envp[%d]='%s'", i, envp[i]);
|
||||
}
|
||||
|
||||
Genode::strncpy(sysio()->execve_in.filename, filename, sizeof(sysio()->execve_in.filename));
|
||||
if (!serialize_string_array(argv, sysio()->execve_in.args,
|
||||
@ -420,6 +425,33 @@ extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** Signal handling **
|
||||
*********************/
|
||||
|
||||
extern "C" int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
/* XXX todo */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
extern "C" int _sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
return sigprocmask(how, set, oldset);
|
||||
}
|
||||
|
||||
|
||||
extern "C" int sigaction(int signum, const struct sigaction *act,
|
||||
struct sigaction *oldact)
|
||||
{
|
||||
/* XXX todo */
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** File operations **
|
||||
*********************/
|
||||
|
@ -15,7 +15,6 @@
|
||||
#define _NOUX__CHILD_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <init/child_policy.h>
|
||||
#include <base/signal.h>
|
||||
#include <base/semaphore.h>
|
||||
#include <cap_session/cap_session.h>
|
||||
@ -28,10 +27,9 @@
|
||||
#include <noux_session/capability.h>
|
||||
#include <args.h>
|
||||
#include <environment.h>
|
||||
#include <local_rm_service.h>
|
||||
#include <ram_session_component.h>
|
||||
#include <cpu_session_component.h>
|
||||
|
||||
#include <child_policy.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
@ -118,99 +116,9 @@ namespace Noux {
|
||||
};
|
||||
|
||||
|
||||
class Family_member : public List<Family_member>::Element
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
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
|
||||
class Child : public Rpc_object<Session>,
|
||||
public File_descriptor_registry,
|
||||
public Family_member
|
||||
{
|
||||
private:
|
||||
|
||||
@ -221,9 +129,6 @@ namespace Noux {
|
||||
*/
|
||||
Semaphore _blocker;
|
||||
|
||||
enum { MAX_NAME_LEN = 64 };
|
||||
char _name[MAX_NAME_LEN];
|
||||
|
||||
Child_exit_dispatcher _exit_dispatcher;
|
||||
Signal_context_capability _exit_context_cap;
|
||||
|
||||
@ -244,12 +149,12 @@ namespace Noux {
|
||||
* Entrypoint used to serve the RPC interfaces of the
|
||||
* locally-provided services
|
||||
*/
|
||||
Rpc_entrypoint &ep;
|
||||
Rpc_entrypoint &ep;
|
||||
|
||||
/**
|
||||
* Registry of dataspaces owned by the Noux process
|
||||
*/
|
||||
Dataspace_registry ds_registry;
|
||||
Dataspace_registry ds_registry;
|
||||
|
||||
/**
|
||||
* Locally-provided services for accessing platform resources
|
||||
@ -293,15 +198,6 @@ namespace Noux {
|
||||
*/
|
||||
Dataspace_capability const _binary_ds;
|
||||
|
||||
Genode::Child _child;
|
||||
|
||||
Service_registry * const _parent_services;
|
||||
|
||||
Init::Child_policy_enforce_labeling _labeling_policy;
|
||||
Init::Child_policy_provide_rom_file _binary_policy;
|
||||
Init::Child_policy_provide_rom_file _args_policy;
|
||||
Init::Child_policy_provide_rom_file _env_policy;
|
||||
|
||||
enum { PAGE_SIZE = 4096, PAGE_MASK = ~(PAGE_SIZE - 1) };
|
||||
enum { SYSIO_DS_SIZE = PAGE_MASK & (sizeof(Sysio) + PAGE_SIZE - 1) };
|
||||
|
||||
@ -310,25 +206,12 @@ namespace Noux {
|
||||
|
||||
Session_capability const _noux_session_cap;
|
||||
|
||||
struct Local_noux_service : public Service
|
||||
{
|
||||
Genode::Session_capability _cap;
|
||||
Local_noux_service _local_noux_service;
|
||||
Local_rm_service _local_rm_service;
|
||||
Service_registry &_parent_services;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param cap capability to return on session requests
|
||||
*/
|
||||
Local_noux_service(Genode::Session_capability cap)
|
||||
: Service(service_name()), _cap(cap) { }
|
||||
|
||||
Genode::Session_capability session(const char *args) { return _cap; }
|
||||
void upgrade(Genode::Session_capability, const char *args) { }
|
||||
void close(Genode::Session_capability) { }
|
||||
|
||||
} _local_noux_service;
|
||||
|
||||
Local_rm_service _local_rm_service;
|
||||
Child_policy _child_policy;
|
||||
Genode::Child _child;
|
||||
|
||||
/**
|
||||
* Exception type for failed file-descriptor lookup
|
||||
@ -375,7 +258,7 @@ namespace Noux {
|
||||
Args const &args,
|
||||
char const *env,
|
||||
Cap_session *cap_session,
|
||||
Service_registry *parent_services,
|
||||
Service_registry &parent_services,
|
||||
Rpc_entrypoint &resources_ep,
|
||||
bool forked)
|
||||
:
|
||||
@ -393,33 +276,30 @@ namespace Noux {
|
||||
_vfs(vfs),
|
||||
_binary_ds(forked ? Dataspace_capability()
|
||||
: vfs->dataspace_from_file(name)),
|
||||
_child(_binary_ds, _resources.ram.cap(), _resources.cpu.cap(),
|
||||
_resources.rm.cap(), &_entrypoint, this),
|
||||
_parent_services(parent_services),
|
||||
_labeling_policy(_name),
|
||||
_binary_policy("binary", _binary_ds, &_entrypoint),
|
||||
_args_policy( "args", _args.cap(), &_entrypoint),
|
||||
_env_policy( "env", _env.cap(), &_entrypoint),
|
||||
_sysio_ds(Genode::env()->ram_session(), SYSIO_DS_SIZE),
|
||||
_sysio(_sysio_ds.local_addr<Sysio>()),
|
||||
_noux_session_cap(Session_capability(_entrypoint.manage(this))),
|
||||
_local_noux_service(_noux_session_cap),
|
||||
_local_rm_service(_entrypoint, _resources.ds_registry)
|
||||
_local_rm_service(_entrypoint, _resources.ds_registry),
|
||||
_parent_services(parent_services),
|
||||
_child_policy(name, _binary_ds, _args.cap(), _env.cap(),
|
||||
_entrypoint, _local_noux_service,
|
||||
_local_rm_service, _parent_services,
|
||||
*this, _exit_context_cap, _resources.ram),
|
||||
_child(_binary_ds, _resources.ram.cap(), _resources.cpu.cap(),
|
||||
_resources.rm.cap(), &_entrypoint, &_child_policy)
|
||||
{
|
||||
_args.dump();
|
||||
strncpy(_name, name, sizeof(_name));
|
||||
}
|
||||
|
||||
~Child()
|
||||
{
|
||||
PDBG("Destructing child %p", this);
|
||||
|
||||
_sig_rec->dissolve(&_execve_cleanup_dispatcher);
|
||||
_sig_rec->dissolve(&_exit_dispatcher);
|
||||
|
||||
/* XXX _binary_ds */
|
||||
|
||||
_entrypoint.dissolve(this);
|
||||
|
||||
_vfs->release_dataspace_for_file(_child_policy.name(), _binary_ds);
|
||||
}
|
||||
|
||||
void start() { _entrypoint.activate(); }
|
||||
@ -439,61 +319,6 @@ namespace Noux {
|
||||
Dataspace_registry &ds_registry() { return _resources.ds_registry; }
|
||||
|
||||
|
||||
/****************************
|
||||
** Child_policy interface **
|
||||
****************************/
|
||||
|
||||
const char *name() const { return _name; }
|
||||
|
||||
Service *resolve_session_request(const char *service_name,
|
||||
const char *args)
|
||||
{
|
||||
Service *service = 0;
|
||||
|
||||
/* check for local ROM file requests */
|
||||
if ((service = _args_policy.resolve_session_request(service_name, args))
|
||||
|| (service = _env_policy.resolve_session_request(service_name, args))
|
||||
|| (service = _binary_policy.resolve_session_request(service_name, args)))
|
||||
return service;
|
||||
|
||||
/* check for locally implemented noux service */
|
||||
if (strcmp(service_name, Session::service_name()) == 0)
|
||||
return &_local_noux_service;
|
||||
|
||||
/*
|
||||
* Check for the creation of an RM session, which is used by
|
||||
* the dynamic linker to manually manage a part of the address
|
||||
* space.
|
||||
*/
|
||||
if (strcmp(service_name, Rm_session::service_name()) == 0)
|
||||
return &_local_rm_service;
|
||||
|
||||
return _parent_services->find(service_name);
|
||||
}
|
||||
|
||||
void filter_session_args(const char *service,
|
||||
char *args, size_t args_len)
|
||||
{
|
||||
_labeling_policy.filter_session_args(service, args, args_len);
|
||||
}
|
||||
|
||||
void exit(int exit_value)
|
||||
{
|
||||
PINF("child %s exited with exit value %d", _name, exit_value);
|
||||
|
||||
wakeup_parent(exit_value);
|
||||
|
||||
/* handle exit of the init process */
|
||||
if (parent() == 0)
|
||||
Signal_transmitter(_exit_context_cap).submit();
|
||||
}
|
||||
|
||||
Ram_session *ref_ram_session()
|
||||
{
|
||||
return &_resources.ram;
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
** Noux session interface **
|
||||
****************************/
|
||||
|
125
ports/src/noux/child_policy.h
Normal file
125
ports/src/noux/child_policy.h
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* \brief Noux child policy
|
||||
* \author Norman Feske
|
||||
* \date 2012-02-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 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__CHILD_POLICY_H_
|
||||
#define _NOUX__CHILD_POLICY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <init/child_policy.h>
|
||||
|
||||
/* Noux includes */
|
||||
#include <family_member.h>
|
||||
#include <local_noux_service.h>
|
||||
#include <local_rm_service.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
class Child_policy : public Genode::Child_policy
|
||||
{
|
||||
private:
|
||||
|
||||
enum { NAME_MAX_LEN = 128 };
|
||||
char _name_buf[NAME_MAX_LEN];
|
||||
char const *_name;
|
||||
Init::Child_policy_enforce_labeling _labeling_policy;
|
||||
Init::Child_policy_provide_rom_file _binary_policy;
|
||||
Init::Child_policy_provide_rom_file _args_policy;
|
||||
Init::Child_policy_provide_rom_file _env_policy;
|
||||
Local_noux_service &_local_noux_service;
|
||||
Local_rm_service &_local_rm_service;
|
||||
Service_registry &_parent_services;
|
||||
Family_member &_family_member;
|
||||
Signal_context_capability _exit_context_cap;
|
||||
Ram_session &_ref_ram_session;
|
||||
|
||||
public:
|
||||
|
||||
Child_policy(char const *name,
|
||||
Dataspace_capability binary_ds,
|
||||
Dataspace_capability args_ds,
|
||||
Dataspace_capability env_ds,
|
||||
Rpc_entrypoint &entrypoint,
|
||||
Local_noux_service &local_noux_service,
|
||||
Local_rm_service &local_rm_service,
|
||||
Service_registry &parent_services,
|
||||
Family_member &family_member,
|
||||
Signal_context_capability exit_context_cap,
|
||||
Ram_session &ref_ram_session)
|
||||
:
|
||||
_name(strncpy(_name_buf, name, sizeof(_name_buf))),
|
||||
_labeling_policy(_name),
|
||||
_binary_policy("binary", binary_ds, &entrypoint),
|
||||
_args_policy( "args", args_ds, &entrypoint),
|
||||
_env_policy( "env", env_ds, &entrypoint),
|
||||
_local_noux_service(local_noux_service),
|
||||
_local_rm_service(local_rm_service),
|
||||
_parent_services(parent_services),
|
||||
_family_member(family_member),
|
||||
_exit_context_cap(exit_context_cap),
|
||||
_ref_ram_session(ref_ram_session)
|
||||
{ }
|
||||
|
||||
const char *name() const { return _name; }
|
||||
|
||||
Service *resolve_session_request(const char *service_name,
|
||||
const char *args)
|
||||
{
|
||||
Service *service = 0;
|
||||
|
||||
/* check for local ROM file requests */
|
||||
if ((service = _args_policy.resolve_session_request(service_name, args))
|
||||
|| (service = _env_policy.resolve_session_request(service_name, args))
|
||||
|| (service = _binary_policy.resolve_session_request(service_name, args)))
|
||||
return service;
|
||||
|
||||
/* check for locally implemented noux service */
|
||||
if (strcmp(service_name, Session::service_name()) == 0)
|
||||
return &_local_noux_service;
|
||||
|
||||
/*
|
||||
* Check for the creation of an RM session, which is used by
|
||||
* the dynamic linker to manually manage a part of the address
|
||||
* space.
|
||||
*/
|
||||
if (strcmp(service_name, Rm_session::service_name()) == 0)
|
||||
return &_local_rm_service;
|
||||
|
||||
return _parent_services.find(service_name);
|
||||
}
|
||||
|
||||
void filter_session_args(const char *service,
|
||||
char *args, size_t args_len)
|
||||
{
|
||||
_labeling_policy.filter_session_args(service, args, args_len);
|
||||
}
|
||||
|
||||
void exit(int exit_value)
|
||||
{
|
||||
PINF("child %s exited with exit value %d", _name, exit_value);
|
||||
|
||||
_family_member.wakeup_parent(exit_value);
|
||||
|
||||
/* handle exit of the init process */
|
||||
if (_family_member.parent() == 0)
|
||||
Signal_transmitter(_exit_context_cap).submit();
|
||||
}
|
||||
|
||||
Ram_session *ref_ram_session()
|
||||
{
|
||||
return &_ref_ram_session;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _NOUX__CHILD_POLICY_H_ */
|
||||
|
@ -15,20 +15,12 @@
|
||||
#define _NOUX__DATASPACE_REGISTRY_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/object_pool.h>
|
||||
#include <base/rpc_server.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/*
|
||||
* XXX not used yet
|
||||
*/
|
||||
struct Dataspace_destroyer
|
||||
{
|
||||
virtual void destroy(Dataspace_capability) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Dataspace_registry;
|
||||
|
||||
@ -39,19 +31,18 @@ namespace Noux {
|
||||
|
||||
size_t _size;
|
||||
Dataspace_capability _ds_cap;
|
||||
Dataspace_destroyer &_destroyer;
|
||||
|
||||
public:
|
||||
|
||||
Dataspace_info(Dataspace_capability ds_cap,
|
||||
Dataspace_destroyer &destroyer)
|
||||
Dataspace_info(Dataspace_capability ds_cap)
|
||||
:
|
||||
Object_pool<Dataspace_info>::Entry(ds_cap),
|
||||
_size(Dataspace_client(ds_cap).size()),
|
||||
_ds_cap(ds_cap),
|
||||
_destroyer(destroyer)
|
||||
_ds_cap(ds_cap)
|
||||
{ }
|
||||
|
||||
virtual ~Dataspace_info() { }
|
||||
|
||||
size_t size() const { return _size; }
|
||||
Dataspace_capability ds_cap() const { return _ds_cap; }
|
||||
|
||||
@ -67,7 +58,6 @@ namespace Noux {
|
||||
* \return capability for the new dataspace
|
||||
*/
|
||||
virtual Dataspace_capability fork(Ram_session_capability ram,
|
||||
Dataspace_destroyer &destroyer,
|
||||
Dataspace_registry &ds_registry,
|
||||
Rpc_entrypoint &ep) = 0;
|
||||
|
||||
@ -79,8 +69,6 @@ namespace Noux {
|
||||
* \param len length of source buffer in bytes
|
||||
*/
|
||||
virtual void poke(addr_t dst_offset, void const *src, size_t len) = 0;
|
||||
|
||||
Dataspace_destroyer &destroyer() { return _destroyer; }
|
||||
};
|
||||
|
||||
|
||||
@ -92,6 +80,26 @@ namespace Noux {
|
||||
|
||||
public:
|
||||
|
||||
~Dataspace_registry()
|
||||
{
|
||||
/*
|
||||
* At the time the destructor is called, most 'Dataspace_info'
|
||||
* objects are expected to be gone already because
|
||||
* 'Child::_resources' and 'Child::_child' are destructed
|
||||
* before the 'Child::_ds_registry'. However, RM dataspaces
|
||||
* created via 'Rm_dataspace_info::fork', are not handled by
|
||||
* those destructors. So we have to clean them up here.
|
||||
*/
|
||||
for (;;) {
|
||||
Dataspace_info *info = _pool.first();
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
_pool.remove(info);
|
||||
destroy(Genode::env()->heap(), info);
|
||||
}
|
||||
}
|
||||
|
||||
void insert(Dataspace_info *info)
|
||||
{
|
||||
_pool.insert(info);
|
||||
|
@ -30,6 +30,7 @@ namespace Noux {
|
||||
struct Directory_service
|
||||
{
|
||||
virtual Genode::Dataspace_capability dataspace(char const *path) = 0;
|
||||
virtual void release(Genode::Dataspace_capability) = 0;
|
||||
|
||||
virtual Vfs_handle *open(Sysio *sysio, char const *path) = 0;
|
||||
|
||||
|
109
ports/src/noux/family_member.h
Normal file
109
ports/src/noux/family_member.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* \brief Helper for handling the relationship between Noux processes
|
||||
* \author Norman Feske
|
||||
* \date 2012-02-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 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__FAMILY_MEMBER_H_
|
||||
#define _NOUX__FAMILY_MEMBER_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/list.h>
|
||||
#include <base/lock.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
class Family_member : public List<Family_member>::Element
|
||||
{
|
||||
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(); }
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _NOUX__FAMILY_MEMBER_H_ */
|
42
ports/src/noux/local_noux_service.h
Normal file
42
ports/src/noux/local_noux_service.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* \brief Locally-provided Noux service
|
||||
* \author Norman Feske
|
||||
* \date 2011-02-17
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 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__LOCAL_NOUX_SERVICE_H_
|
||||
#define _NOUX__LOCAL_NOUX_SERVICE_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/service.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
struct Local_noux_service : public Service
|
||||
{
|
||||
Genode::Session_capability _cap;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param cap capability to return on session requests
|
||||
*/
|
||||
Local_noux_service(Genode::Session_capability cap)
|
||||
: Service(Session::service_name()), _cap(cap) { }
|
||||
|
||||
Genode::Session_capability session(const char *args) { return _cap; }
|
||||
void upgrade(Genode::Session_capability, const char *args) { }
|
||||
void close(Genode::Session_capability) { }
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _NOUX__LOCAL_NOUX_SERVICE_H_ */
|
@ -30,38 +30,52 @@ namespace Noux {
|
||||
{
|
||||
private:
|
||||
|
||||
struct Dummy_destroyer : Dataspace_destroyer
|
||||
{
|
||||
void destroy(Dataspace_capability) { }
|
||||
} _dummy_destroyer;
|
||||
|
||||
Rm_session_component &_sub_rm;
|
||||
Rm_session_component * const _sub_rm;
|
||||
Rpc_entrypoint &_ep;
|
||||
Rm_session_capability _rm_cap;
|
||||
|
||||
public:
|
||||
|
||||
Rm_dataspace_info(Rm_session_component &sub_rm)
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param sub_rm pointer to 'Rm_session_component' that belongs
|
||||
* to the 'Rm_dataspace_info' object
|
||||
* \param ep entrypoint to manage the 'Rm_session_component'
|
||||
*
|
||||
* The ownership of the pointed-to object gets transferred to the
|
||||
* 'Rm_dataspace_info' object. I.e., 'sub_rm' will get destructed
|
||||
* on the destruction of its corresponding 'Rm_dataspace_info'
|
||||
* object. Also, 'Rm_dataspace_info' takes care of associating
|
||||
* 'sub_rm' with 'ep'.
|
||||
*/
|
||||
Rm_dataspace_info(Rm_session_component *sub_rm,
|
||||
Rpc_entrypoint &ep)
|
||||
:
|
||||
Dataspace_info(sub_rm.dataspace(), _dummy_destroyer),
|
||||
_sub_rm(sub_rm)
|
||||
Dataspace_info(sub_rm->dataspace()),
|
||||
_sub_rm(sub_rm), _ep(ep), _rm_cap(_ep.manage(_sub_rm))
|
||||
{ }
|
||||
|
||||
~Rm_dataspace_info()
|
||||
{
|
||||
_ep.dissolve(_sub_rm);
|
||||
destroy(Genode::env()->heap(), _sub_rm);
|
||||
}
|
||||
|
||||
Rm_session_capability rm_cap() { return _rm_cap; }
|
||||
|
||||
Dataspace_capability fork(Ram_session_capability ram,
|
||||
Dataspace_destroyer &,
|
||||
Dataspace_registry &ds_registry,
|
||||
Rpc_entrypoint &ep)
|
||||
{
|
||||
Rm_session_component *new_sub_rm =
|
||||
new Rm_session_component(ds_registry, 0, size());
|
||||
|
||||
Rm_session_capability rm_cap = ep.manage(new_sub_rm);
|
||||
Rm_dataspace_info *rm_info = new Rm_dataspace_info(new_sub_rm, ep);
|
||||
|
||||
/*
|
||||
* XXX Where to dissolve the RM session?
|
||||
*/
|
||||
_sub_rm->replay(ram, rm_info->rm_cap(), ds_registry, ep);
|
||||
|
||||
_sub_rm.replay(ram, rm_cap, ds_registry, ep);
|
||||
|
||||
ds_registry.insert(new Rm_dataspace_info(*new_sub_rm));
|
||||
ds_registry.insert(rm_info);
|
||||
|
||||
return new_sub_rm->dataspace();
|
||||
}
|
||||
@ -72,7 +86,7 @@ namespace Noux {
|
||||
PERR("illegal attemt to write beyond RM boundary");
|
||||
return;
|
||||
}
|
||||
_sub_rm.poke(dst_offset, src, len);
|
||||
_sub_rm->poke(dst_offset, src, len);
|
||||
}
|
||||
};
|
||||
|
||||
@ -100,18 +114,34 @@ namespace Noux {
|
||||
Rm_session_component *rm =
|
||||
new Rm_session_component(_ds_registry, start, size);
|
||||
|
||||
Genode::Session_capability cap = _ep.manage(rm);
|
||||
|
||||
_ds_registry.insert(new Rm_dataspace_info(*rm));
|
||||
|
||||
return cap;
|
||||
Rm_dataspace_info *info = new Rm_dataspace_info(rm, _ep);
|
||||
_ds_registry.insert(info);
|
||||
return info->rm_cap();
|
||||
}
|
||||
|
||||
void upgrade(Genode::Session_capability, const char *args) { }
|
||||
|
||||
void close(Genode::Session_capability)
|
||||
void close(Genode::Session_capability session)
|
||||
{
|
||||
PWRN("Local_rm_service::close not implemented, leaking memory");
|
||||
Rm_session_component *rm_session =
|
||||
dynamic_cast<Rm_session_component *>(_ep.obj_by_cap(session));
|
||||
|
||||
if (!rm_session) {
|
||||
PWRN("Unexpected call of close with non-RM-session argument");
|
||||
return;
|
||||
}
|
||||
|
||||
/* use RM dataspace as key to obtain the dataspace info object */
|
||||
Dataspace_capability ds_cap = rm_session->dataspace();
|
||||
|
||||
/* release dataspace info */
|
||||
Dataspace_info *info = _ds_registry.lookup_info(ds_cap);
|
||||
if (info) {
|
||||
_ds_registry.remove(info);
|
||||
destroy(Genode::env()->heap(), info);
|
||||
} else {
|
||||
PWRN("Could not lookup dataspace info for local RM session");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -176,6 +176,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
_assign_io_channels_to(child);
|
||||
|
||||
/* signal main thread to remove ourself */
|
||||
PINF("submit signal to _execve_cleanup_context_cap");
|
||||
Genode::Signal_transmitter(_execve_cleanup_context_cap).submit();
|
||||
|
||||
/* start executing the new process */
|
||||
@ -294,7 +295,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
* unique name that includes the PID instead of just
|
||||
* reusing the name of the parent.
|
||||
*/
|
||||
Child *child = new Child(name(),
|
||||
Child *child = new Child(_child_policy.name(),
|
||||
this,
|
||||
new_pid,
|
||||
_sig_rec,
|
||||
@ -342,6 +343,11 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
|
||||
/* destroy 'Noux::Child' */
|
||||
destroy(Genode::env()->heap(), exited);
|
||||
|
||||
PINF("quota: avail=%zd, used=%zd",
|
||||
Genode::env()->ram_session()->avail(),
|
||||
Genode::env()->ram_session()->used());
|
||||
|
||||
} else {
|
||||
_sysio->wait4_out.pid = 0;
|
||||
_sysio->wait4_out.status = 0;
|
||||
@ -519,7 +525,7 @@ int main(int argc, char **argv)
|
||||
args_of_init_process(),
|
||||
env_string_of_init_process(),
|
||||
&cap,
|
||||
&parent_services,
|
||||
parent_services,
|
||||
resources_ep,
|
||||
false);
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
#define _NOUX__RAM_SESSION_COMPONENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <ram_session/capability.h>
|
||||
#include <ram_session/client.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/env.h>
|
||||
|
||||
@ -38,12 +38,10 @@ namespace Noux {
|
||||
struct Ram_dataspace_info : Dataspace_info,
|
||||
List<Ram_dataspace_info>::Element
|
||||
{
|
||||
Ram_dataspace_info(Ram_dataspace_capability ds_cap,
|
||||
Dataspace_destroyer &destroyer)
|
||||
: Dataspace_info(ds_cap, destroyer) { }
|
||||
Ram_dataspace_info(Ram_dataspace_capability ds_cap)
|
||||
: Dataspace_info(ds_cap) { }
|
||||
|
||||
Dataspace_capability fork(Ram_session_capability ram,
|
||||
Dataspace_destroyer &destroyer,
|
||||
Dataspace_registry &,
|
||||
Rpc_entrypoint &)
|
||||
{
|
||||
@ -101,8 +99,7 @@ namespace Noux {
|
||||
};
|
||||
|
||||
|
||||
class Ram_session_component : public Rpc_object<Ram_session>,
|
||||
public Dataspace_destroyer
|
||||
class Ram_session_component : public Rpc_object<Ram_session>
|
||||
{
|
||||
private:
|
||||
|
||||
@ -136,19 +133,6 @@ namespace Noux {
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
** Dataspace_destroyer interface **
|
||||
***********************************/
|
||||
|
||||
/*
|
||||
* XXX not used yet
|
||||
*/
|
||||
void destroy(Dataspace_capability ds)
|
||||
{
|
||||
free(static_cap_cast<Ram_dataspace>(ds));
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
** Ram_session interface **
|
||||
***************************/
|
||||
@ -158,7 +142,7 @@ namespace Noux {
|
||||
Ram_dataspace_capability ds_cap = env()->ram_session()->alloc(size);
|
||||
|
||||
Ram_dataspace_info *ds_info = new (env()->heap())
|
||||
Ram_dataspace_info(ds_cap, *this);
|
||||
Ram_dataspace_info(ds_cap);
|
||||
|
||||
_used_quota += ds_info->size();
|
||||
|
||||
|
@ -105,16 +105,6 @@ namespace Noux {
|
||||
Dataspace_registry &ds_registry,
|
||||
Rpc_entrypoint &ep)
|
||||
{
|
||||
/*
|
||||
* XXX remove this
|
||||
*/
|
||||
struct Dummy_destroyer : Dataspace_destroyer
|
||||
{
|
||||
void destroy(Dataspace_capability) { }
|
||||
};
|
||||
|
||||
static Dummy_destroyer dummy_destroyer;
|
||||
|
||||
for (Region *curr = _regions.first(); curr; curr = curr->next()) {
|
||||
|
||||
Dataspace_capability ds;
|
||||
@ -123,11 +113,7 @@ namespace Noux {
|
||||
|
||||
if (info) {
|
||||
|
||||
/*
|
||||
* XXX Using 'this' as destroyer may be false, the
|
||||
* destroyer should better correspond to dst_ram.
|
||||
*/
|
||||
ds = info->fork(dst_ram, dummy_destroyer, ds_registry, ep);
|
||||
ds = info->fork(dst_ram, ds_registry, ep);
|
||||
|
||||
/*
|
||||
* XXX We could detect dataspaces that are attached
|
||||
@ -148,7 +134,6 @@ namespace Noux {
|
||||
* like to detect unexpected dataspaces.
|
||||
*/
|
||||
ds = curr->ds;
|
||||
PWRN("replay: unknown dataspace type, assume ROM");
|
||||
}
|
||||
|
||||
if (!ds.valid()) {
|
||||
|
@ -274,19 +274,25 @@ namespace Noux {
|
||||
}
|
||||
|
||||
try {
|
||||
Attached_ram_dataspace *ds = new (env()->heap())
|
||||
Attached_ram_dataspace(env()->ram_session(), record->size());
|
||||
Ram_dataspace_capability ds_cap =
|
||||
env()->ram_session()->alloc(record->size());
|
||||
|
||||
PDBG("copying %s (%zd bytes) into new dataspace", path, record->size());
|
||||
void *local_addr = env()->rm_session()->attach(ds_cap);
|
||||
memcpy(local_addr, record->data(), record->size());
|
||||
env()->rm_session()->detach(local_addr);
|
||||
|
||||
memcpy(ds->local_addr<void>(), record->data(), record->size());
|
||||
return ds->cap();
|
||||
return ds_cap;
|
||||
}
|
||||
catch (...) { PDBG("Could not create new dataspace"); }
|
||||
|
||||
return Dataspace_capability();
|
||||
}
|
||||
|
||||
void release(Genode::Dataspace_capability ds_cap)
|
||||
{
|
||||
env()->ram_session()->free(static_cap_cast<Ram_dataspace>(ds_cap));
|
||||
}
|
||||
|
||||
bool stat(Sysio *sysio, char const *path)
|
||||
{
|
||||
Lookup_exact lookup_criterion(path);
|
||||
|
@ -46,6 +46,16 @@ namespace Noux {
|
||||
return Genode::Dataspace_capability();
|
||||
}
|
||||
|
||||
void release_dataspace_for_file(char const *filename,
|
||||
Genode::Dataspace_capability ds_cap)
|
||||
{
|
||||
for (File_system *fs = _file_systems.first(); fs; fs = fs->next()) {
|
||||
char const *fs_local_path = fs->local_path(filename);
|
||||
if (fs_local_path)
|
||||
fs->release(ds_cap);
|
||||
}
|
||||
}
|
||||
|
||||
void add_file_system(File_system *file_system)
|
||||
{
|
||||
_file_systems.insert(file_system);
|
||||
|
@ -51,6 +51,8 @@ namespace Noux {
|
||||
return Genode::Dataspace_capability();
|
||||
}
|
||||
|
||||
void release(Genode::Dataspace_capability) { }
|
||||
|
||||
bool stat(Sysio *, char const *) { return _msg("stat"); }
|
||||
Vfs_handle *open(Sysio *, char const *) { _msg("open"); return 0; }
|
||||
void close(Vfs_handle *) { _msg("close"); }
|
||||
|
Loading…
x
Reference in New Issue
Block a user