Move 'Child' API implementation to library
This commit is contained in:
parent
f635cc4a19
commit
4a1b545770
|
@ -1,5 +1,5 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
LIBS = cxx ipc heap core_printf process pager lock \
|
LIBS = cxx ipc heap core_printf child pager lock \
|
||||||
raw_signal raw_server
|
raw_signal raw_server
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
REQUIRES = fiasco
|
REQUIRES = fiasco
|
||||||
LIBS = cxx ipc heap core_printf process pager lock raw_signal raw_server
|
LIBS = cxx ipc heap core_printf child pager lock raw_signal raw_server
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
REQUIRES = foc
|
REQUIRES = foc
|
||||||
LIBS = cxx ipc heap core_printf process pager lock raw_signal raw_server
|
LIBS = cxx ipc heap core_printf child pager lock raw_signal raw_server
|
||||||
|
|
||||||
LD_TEXT_ADDR = 0x500000
|
LD_TEXT_ADDR = 0x500000
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
LIBS = cxx ipc heap core_printf process pager lock \
|
LIBS = cxx ipc heap core_printf child pager lock \
|
||||||
raw_signal raw_server
|
raw_signal raw_server
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
|
@ -11,7 +11,7 @@ TARGET = core
|
||||||
STARTUP_LIB = startup_core
|
STARTUP_LIB = startup_core
|
||||||
|
|
||||||
# add library dependencies
|
# add library dependencies
|
||||||
LIBS += cxx raw_ipc heap process pager lock console signal raw_server \
|
LIBS += cxx raw_ipc heap child pager lock console signal raw_server \
|
||||||
syscall startup_core core_support
|
syscall startup_core core_support
|
||||||
|
|
||||||
# add include paths
|
# add include paths
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
REQUIRES = linux
|
REQUIRES = linux
|
||||||
LIBS = cxx ipc heap core_printf process lock raw_server syscall rpath
|
LIBS = cxx ipc heap core_printf child lock raw_server syscall rpath
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
LIBS = kernel_core cxx ipc heap printf_microblaze process pager lock \
|
LIBS = kernel_core cxx ipc heap printf_microblaze child pager lock \
|
||||||
raw_signal raw_server
|
raw_signal raw_server
|
||||||
|
|
||||||
STARTUP_LIB = kernel_core
|
STARTUP_LIB = kernel_core
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
LIBS = cxx ipc heap core_printf process pager lock \
|
LIBS = cxx ipc heap core_printf child pager lock \
|
||||||
raw_signal raw_server
|
raw_signal raw_server
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
REQUIRES = okl4
|
REQUIRES = okl4
|
||||||
LIBS = cxx ipc heap core_printf process pager lock \
|
LIBS = cxx ipc heap core_printf child pager lock \
|
||||||
raw_signal raw_server bootinfo
|
raw_signal raw_server bootinfo child
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
TARGET = core
|
TARGET = core
|
||||||
REQUIRES = pistachio
|
REQUIRES = pistachio
|
||||||
LIBS = cxx ipc heap core_printf process pager lock \
|
LIBS = cxx ipc heap core_printf child pager lock \
|
||||||
raw_signal raw_server kip hexdump
|
raw_signal raw_server kip hexdump
|
||||||
|
|
||||||
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
GEN_CORE_DIR = $(BASE_DIR)/src/core
|
||||||
|
|
|
@ -125,151 +125,7 @@ namespace Genode {
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
class Session;
|
||||||
* Representation of an open session
|
|
||||||
*/
|
|
||||||
class Session : public Object_pool<Session>::Entry,
|
|
||||||
public List<Session>::Element
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
enum { IDENT_LEN = 16 };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Session capability at the server
|
|
||||||
*/
|
|
||||||
Session_capability _cap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service interface that was used to create the session
|
|
||||||
*/
|
|
||||||
Service *_service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Server implementing the session
|
|
||||||
*
|
|
||||||
* Even though we can normally determine the server of the
|
|
||||||
* session via '_service->server()', this does not apply
|
|
||||||
* when destructing a server. During destruction, we use
|
|
||||||
* the 'Server' pointer as opaque key for revoking active
|
|
||||||
* sessions of the server. So we keep a copy independent of
|
|
||||||
* the 'Service' object.
|
|
||||||
*/
|
|
||||||
Server *_server;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total of quota associated with this session
|
|
||||||
*/
|
|
||||||
size_t _donated_ram_quota;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of session, used for debugging
|
|
||||||
*/
|
|
||||||
char _ident[IDENT_LEN];
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param session session capability
|
|
||||||
* \param service service that implements the session
|
|
||||||
* \param ram_quota initial quota donation associated with
|
|
||||||
* the session
|
|
||||||
* \param ident optional session identifier, used for
|
|
||||||
* debugging
|
|
||||||
*/
|
|
||||||
Session(Session_capability session, Service *service,
|
|
||||||
size_t ram_quota, const char *ident = "<noname>")
|
|
||||||
:
|
|
||||||
Object_pool<Session>::Entry(session), _cap(session),
|
|
||||||
_service(service), _server(service->server()),
|
|
||||||
_donated_ram_quota(ram_quota) {
|
|
||||||
strncpy(_ident, ident, sizeof(_ident)); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor creates invalid session
|
|
||||||
*/
|
|
||||||
Session() : _service(0), _donated_ram_quota(0) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend amount of ram attached to the session
|
|
||||||
*/
|
|
||||||
void upgrade_ram_quota(size_t ram_quota) {
|
|
||||||
_donated_ram_quota += ram_quota; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Accessors
|
|
||||||
*/
|
|
||||||
Session_capability cap() const { return _cap; }
|
|
||||||
size_t donated_ram_quota() const { return _donated_ram_quota; }
|
|
||||||
bool valid() const { return _service != 0; }
|
|
||||||
Service *service() const { return _service; }
|
|
||||||
Server *server() const { return _server; }
|
|
||||||
const char *ident() const { return _ident; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Guard for transferring quota donation
|
|
||||||
*
|
|
||||||
* This class is used to provide transactional semantics of quota
|
|
||||||
* transfers. Establishing a new session involves several steps, in
|
|
||||||
* particular subsequent quota transfers. If one intermediate step
|
|
||||||
* fails, we need to revert all quota transfers that already took
|
|
||||||
* place. When instantated at a local scope, a 'Transfer' object
|
|
||||||
* guards a quota transfer. If the scope is left without prior an
|
|
||||||
* explicit acknowledgement of the transfer (for example via an
|
|
||||||
* exception), the destructor the 'Transfer' object reverts the
|
|
||||||
* transfer in flight.
|
|
||||||
*/
|
|
||||||
class Transfer {
|
|
||||||
|
|
||||||
bool _ack;
|
|
||||||
size_t _quantum;
|
|
||||||
Ram_session_capability _from;
|
|
||||||
Ram_session_capability _to;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* \param quantim number of bytes to transfer
|
|
||||||
* \param from donator RAM session
|
|
||||||
* \param to receiver RAM session
|
|
||||||
*/
|
|
||||||
Transfer(size_t quantum,
|
|
||||||
Ram_session_capability from,
|
|
||||||
Ram_session_capability to)
|
|
||||||
: _ack(false), _quantum(quantum), _from(from), _to(to)
|
|
||||||
{
|
|
||||||
if (_from.valid() && _to.valid() &&
|
|
||||||
Ram_session_client(_from).transfer_quota(_to, quantum)) {
|
|
||||||
PWRN("not enough quota for a donation of %zd bytes", quantum);
|
|
||||||
throw Quota_exceeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destructor
|
|
||||||
*
|
|
||||||
* The destructor will be called when leaving the scope of
|
|
||||||
* the 'session' function. If the scope is left because of
|
|
||||||
* an error (e.g., an exception), the donation will be
|
|
||||||
* reverted.
|
|
||||||
*/
|
|
||||||
~Transfer()
|
|
||||||
{
|
|
||||||
if (!_ack && _from.valid() && _to.valid())
|
|
||||||
Ram_session_client(_to).transfer_quota(_from, _quantum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledge quota donation
|
|
||||||
*/
|
|
||||||
void acknowledge() { _ack = true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/* RAM session that contains the quota of the child */
|
/* RAM session that contains the quota of the child */
|
||||||
Ram_session_capability _ram;
|
Ram_session_capability _ram;
|
||||||
|
@ -316,43 +172,12 @@ namespace Genode {
|
||||||
* \throw Ram_session::Quota_exceeded the child's heap partition cannot
|
* \throw Ram_session::Quota_exceeded the child's heap partition cannot
|
||||||
* hold the session meta data
|
* hold the session meta data
|
||||||
*/
|
*/
|
||||||
void _add_session(const Session &s)
|
void _add_session(const Session &s);
|
||||||
{
|
|
||||||
Lock::Guard lock_guard(_lock);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Store session information in a new child's meta data
|
|
||||||
* structure. The allocation from 'heap()' may throw a
|
|
||||||
* 'Ram_session::Quota_exceeded' exception.
|
|
||||||
*/
|
|
||||||
Session *session = 0;
|
|
||||||
try {
|
|
||||||
session = new (heap())
|
|
||||||
Session(s.cap(), s.service(),
|
|
||||||
s.donated_ram_quota(), s.ident()); }
|
|
||||||
catch (Allocator::Out_of_memory) {
|
|
||||||
throw Parent::Quota_exceeded(); }
|
|
||||||
|
|
||||||
/* these functions may also throw 'Ram_session::Quota_exceeded' */
|
|
||||||
_session_pool.insert(session);
|
|
||||||
_session_list.insert(session);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close session and revert quota donation associated with it
|
* Close session and revert quota donation associated with it
|
||||||
*/
|
*/
|
||||||
void _remove_session(Session *s)
|
void _remove_session(Session *s);
|
||||||
{
|
|
||||||
/* forget about this session */
|
|
||||||
_session_pool.remove(s);
|
|
||||||
_session_list.remove(s);
|
|
||||||
|
|
||||||
/* return session quota to the ram session of the child */
|
|
||||||
if (_policy->ref_ram_session()->transfer_quota(_ram, s->donated_ram_quota()))
|
|
||||||
PERR("We ran out of our own quota");
|
|
||||||
|
|
||||||
destroy(heap(), s);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return service interface targetting the parent
|
* Return service interface targetting the parent
|
||||||
|
@ -362,11 +187,7 @@ namespace Genode {
|
||||||
* solely used for targeting resource donations during
|
* solely used for targeting resource donations during
|
||||||
* 'Parent::upgrade_quota()' calls.
|
* 'Parent::upgrade_quota()' calls.
|
||||||
*/
|
*/
|
||||||
static Service *_parent_service()
|
static Service *_parent_service();
|
||||||
{
|
|
||||||
static Parent_service parent_service("");
|
|
||||||
return &parent_service;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -403,18 +224,7 @@ namespace Genode {
|
||||||
Child_policy *policy,
|
Child_policy *policy,
|
||||||
Service &ram_service = *_parent_service(),
|
Service &ram_service = *_parent_service(),
|
||||||
Service &cpu_service = *_parent_service(),
|
Service &cpu_service = *_parent_service(),
|
||||||
Service &rm_service = *_parent_service())
|
Service &rm_service = *_parent_service());
|
||||||
:
|
|
||||||
_ram(ram), _ram_session_client(ram), _cpu(cpu), _rm(rm),
|
|
||||||
_ram_service(ram_service), _cpu_service(cpu_service),
|
|
||||||
_rm_service(rm_service),
|
|
||||||
_heap(&_ram_session_client, env()->rm_session()),
|
|
||||||
_entrypoint(entrypoint),
|
|
||||||
_parent_cap(_entrypoint->manage(this)),
|
|
||||||
_policy(policy),
|
|
||||||
_server(ram),
|
|
||||||
_process(elf_ds, ram, cpu, rm, _parent_cap, policy->name(), 0)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destructor
|
* Destructor
|
||||||
|
@ -422,14 +232,7 @@ namespace Genode {
|
||||||
* On destruction of a child, we close all sessions of the child to
|
* On destruction of a child, we close all sessions of the child to
|
||||||
* other services.
|
* other services.
|
||||||
*/
|
*/
|
||||||
virtual ~Child()
|
virtual ~Child();
|
||||||
{
|
|
||||||
_entrypoint->dissolve(this);
|
|
||||||
_policy->unregister_services();
|
|
||||||
|
|
||||||
for (Session *s; (s = _session_pool.first()); )
|
|
||||||
close(s->cap());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return heap that uses the child's quota
|
* Return heap that uses the child's quota
|
||||||
|
@ -450,196 +253,18 @@ namespace Genode {
|
||||||
* that the specified server object may not exist anymore. We do
|
* that the specified server object may not exist anymore. We do
|
||||||
* not de-reference the server argument in here!
|
* not de-reference the server argument in here!
|
||||||
*/
|
*/
|
||||||
void revoke_server(const Server *server)
|
void revoke_server(const Server *server);
|
||||||
{
|
|
||||||
Lock::Guard lock_guard(_lock);
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* search session belonging to the specified server */
|
|
||||||
Session *s = _session_list.first();
|
|
||||||
for ( ; s && (s->server() != server); s = s->next());
|
|
||||||
|
|
||||||
/* if no matching session exists, we are done */
|
|
||||||
if (!s) return;
|
|
||||||
|
|
||||||
_remove_session(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************
|
/**********************
|
||||||
** Parent interface **
|
** Parent interface **
|
||||||
**********************/
|
**********************/
|
||||||
|
|
||||||
void announce(Service_name const &name, Root_capability root)
|
void announce(Service_name const &, Root_capability);
|
||||||
{
|
Session_capability session(Service_name const &, Session_args const &);
|
||||||
if (!name.is_valid_string()) return;
|
void upgrade(Session_capability, Upgrade_args const &);
|
||||||
|
void close(Session_capability);
|
||||||
_policy->announce_service(name.string(), root, heap(), &_server);
|
void exit(int);
|
||||||
}
|
|
||||||
|
|
||||||
Session_capability session(Service_name const &name, Session_args const &args)
|
|
||||||
{
|
|
||||||
if (!name.is_valid_string() || !args.is_valid_string()) throw Unavailable();
|
|
||||||
|
|
||||||
/* return sessions that we created for the child */
|
|
||||||
if (!strcmp("Env::ram_session", name.string())) return _ram;
|
|
||||||
if (!strcmp("Env::cpu_session", name.string())) return _cpu;
|
|
||||||
if (!strcmp("Env::rm_session", name.string())) return _rm;
|
|
||||||
if (!strcmp("Env::pd_session", name.string())) return _process.pd_session_cap();
|
|
||||||
|
|
||||||
/* filter session arguments according to the child policy */
|
|
||||||
strncpy(_args, args.string(), sizeof(_args));
|
|
||||||
_policy->filter_session_args(name.string(), _args, sizeof(_args));
|
|
||||||
|
|
||||||
/* transfer the quota donation from the child's account to ourself */
|
|
||||||
size_t ram_quota = Arg_string::find_arg(_args, "ram_quota").long_value(0);
|
|
||||||
|
|
||||||
Transfer donation_from_child(ram_quota, _ram, env()->ram_session_cap());
|
|
||||||
|
|
||||||
Service *service = _policy->resolve_session_request(name.string(), _args);
|
|
||||||
|
|
||||||
/* raise an error if no matching service provider could be found */
|
|
||||||
if (!service)
|
|
||||||
throw Service_denied();
|
|
||||||
|
|
||||||
/* transfer session quota from ourself to the service provider */
|
|
||||||
Transfer donation_to_service(ram_quota, env()->ram_session_cap(),
|
|
||||||
service->ram_session_cap());
|
|
||||||
|
|
||||||
/* create session */
|
|
||||||
Session_capability cap;
|
|
||||||
try { cap = service->session(_args); }
|
|
||||||
catch (Service::Invalid_args) { throw Service_denied(); }
|
|
||||||
catch (Service::Unavailable) { throw Service_denied(); }
|
|
||||||
catch (Service::Quota_exceeded) { throw Quota_exceeded(); }
|
|
||||||
|
|
||||||
/* register session */
|
|
||||||
try { _add_session(Session(cap, service, ram_quota, name.string())); }
|
|
||||||
catch (Ram_session::Quota_exceeded) { throw Quota_exceeded(); }
|
|
||||||
|
|
||||||
/* finish transaction */
|
|
||||||
donation_from_child.acknowledge();
|
|
||||||
donation_to_service.acknowledge();
|
|
||||||
|
|
||||||
return cap;
|
|
||||||
}
|
|
||||||
|
|
||||||
void upgrade(Session_capability to_session, Upgrade_args const &args)
|
|
||||||
{
|
|
||||||
Service *targeted_service = 0;
|
|
||||||
|
|
||||||
/* check of upgrade refers to an Env:: resource */
|
|
||||||
if (to_session.local_name() == _ram.local_name())
|
|
||||||
targeted_service = &_ram_service;
|
|
||||||
if (to_session.local_name() == _cpu.local_name())
|
|
||||||
targeted_service = &_cpu_service;
|
|
||||||
if (to_session.local_name() == _rm.local_name())
|
|
||||||
targeted_service = &_rm_service;
|
|
||||||
|
|
||||||
/* check if upgrade refers to server */
|
|
||||||
Session * const session = _session_pool.obj_by_cap(to_session);
|
|
||||||
if (session)
|
|
||||||
targeted_service = session->service();
|
|
||||||
|
|
||||||
if (!targeted_service) {
|
|
||||||
PWRN("could not lookup service for session upgrade");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!args.is_valid_string()) {
|
|
||||||
PWRN("no valid session-upgrade arguments");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t const ram_quota =
|
|
||||||
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
|
|
||||||
|
|
||||||
/* transfer quota from client to ourself */
|
|
||||||
Transfer donation_from_child(ram_quota, _ram,
|
|
||||||
env()->ram_session_cap());
|
|
||||||
|
|
||||||
/* transfer session quota from ourself to the service provider */
|
|
||||||
Transfer donation_to_service(ram_quota, env()->ram_session_cap(),
|
|
||||||
targeted_service->ram_session_cap());
|
|
||||||
|
|
||||||
try { targeted_service->upgrade(to_session, args.string()); }
|
|
||||||
catch (Service::Quota_exceeded) { throw Quota_exceeded(); }
|
|
||||||
|
|
||||||
/* remember new amount attached to the session */
|
|
||||||
if (session)
|
|
||||||
session->upgrade_ram_quota(ram_quota);
|
|
||||||
|
|
||||||
/* finish transaction */
|
|
||||||
donation_from_child.acknowledge();
|
|
||||||
donation_to_service.acknowledge();
|
|
||||||
}
|
|
||||||
|
|
||||||
void close(Session_capability session_cap)
|
|
||||||
{
|
|
||||||
/* refuse to close the child's initial sessions */
|
|
||||||
if (session_cap.local_name() == _ram.local_name()
|
|
||||||
|| session_cap.local_name() == _cpu.local_name()
|
|
||||||
|| session_cap.local_name() == _rm.local_name()
|
|
||||||
|| session_cap.local_name() == _process.pd_session_cap().local_name())
|
|
||||||
return;
|
|
||||||
|
|
||||||
Session *s = _session_pool.obj_by_cap(session_cap);
|
|
||||||
|
|
||||||
if (!s) {
|
|
||||||
PWRN("no session structure found");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* There is a chance that the server is not responding to
|
|
||||||
* the 'close' call, making us block infinitely. However,
|
|
||||||
* by using core's cancel-blocking mechanism, we can cancel
|
|
||||||
* the 'close' call by another (watchdog) thread that
|
|
||||||
* invokes 'cancel_blocking' at our thread after a timeout.
|
|
||||||
* The unblocking is reflected at the API level as an
|
|
||||||
* 'Blocking_canceled' exception. We catch this exception
|
|
||||||
* to proceed with normal operation after being unblocked.
|
|
||||||
*/
|
|
||||||
try { s->service()->close(s->cap()); }
|
|
||||||
catch (Blocking_canceled) {
|
|
||||||
PDBG("Got Blocking_canceled exception during %s->close call\n",
|
|
||||||
s->ident()); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the session was provided by a child of us,
|
|
||||||
* 'server()->ram_session_cap()' returns the RAM session of the
|
|
||||||
* corresponding child. Since the session to the server is
|
|
||||||
* closed now, we expect that the server released all donated
|
|
||||||
* resources and we can decrease the servers' quota.
|
|
||||||
*
|
|
||||||
* If this goes wrong, the server is misbehaving.
|
|
||||||
*/
|
|
||||||
if (s->service()->ram_session_cap().valid()) {
|
|
||||||
Ram_session_client server_ram(s->service()->ram_session_cap());
|
|
||||||
if (server_ram.transfer_quota(env()->ram_session_cap(),
|
|
||||||
s->donated_ram_quota())) {
|
|
||||||
PERR("Misbehaving server '%s'!", s->service()->name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Lock::Guard lock_guard(_lock);
|
|
||||||
_remove_session(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
void exit(int exit_value)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* This function receives the hint from the child that now, its
|
|
||||||
* a good time to kill it. An inherited child class could use
|
|
||||||
* this hint to schedule the destruction of the child object.
|
|
||||||
*
|
|
||||||
* Note that the child object must not be destructed from by
|
|
||||||
* this function because it is executed by the thread contained
|
|
||||||
* in the child object.
|
|
||||||
*/
|
|
||||||
return _policy->exit(exit_value);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
base/lib/mk/child.mk
Normal file
4
base/lib/mk/child.mk
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
SRC_CC = child.cc
|
||||||
|
LIBS += process
|
||||||
|
|
||||||
|
vpath child.cc $(REP_DIR)/src/base/child
|
440
base/src/base/child/child.cc
Normal file
440
base/src/base/child/child.cc
Normal file
|
@ -0,0 +1,440 @@
|
||||||
|
/*
|
||||||
|
* \brief Child creation framework
|
||||||
|
* \author Norman Feske
|
||||||
|
* \date 2006-07-22
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2006-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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <base/child.h>
|
||||||
|
|
||||||
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Utilities **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Guard for transferring quota donation
|
||||||
|
*
|
||||||
|
* This class is used to provide transactional semantics of quota
|
||||||
|
* transfers. Establishing a new session involves several steps, in
|
||||||
|
* particular subsequent quota transfers. If one intermediate step
|
||||||
|
* fails, we need to revert all quota transfers that already took
|
||||||
|
* place. When instantated at a local scope, a 'Transfer' object guards
|
||||||
|
* a quota transfer. If the scope is left without prior an explicit
|
||||||
|
* acknowledgement of the transfer (for example via an exception), the
|
||||||
|
* destructor the 'Transfer' object reverts the transfer in flight.
|
||||||
|
*/
|
||||||
|
class Transfer {
|
||||||
|
|
||||||
|
bool _ack;
|
||||||
|
size_t _quantum;
|
||||||
|
Ram_session_capability _from;
|
||||||
|
Ram_session_capability _to;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param quantim number of bytes to transfer
|
||||||
|
* \param from donator RAM session
|
||||||
|
* \param to receiver RAM session
|
||||||
|
*/
|
||||||
|
Transfer(size_t quantum,
|
||||||
|
Ram_session_capability from,
|
||||||
|
Ram_session_capability to)
|
||||||
|
: _ack(false), _quantum(quantum), _from(from), _to(to)
|
||||||
|
{
|
||||||
|
if (_from.valid() && _to.valid() &&
|
||||||
|
Ram_session_client(_from).transfer_quota(_to, quantum)) {
|
||||||
|
PWRN("not enough quota for a donation of %zd bytes", quantum);
|
||||||
|
throw Parent::Quota_exceeded();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor
|
||||||
|
*
|
||||||
|
* The destructor will be called when leaving the scope of the
|
||||||
|
* 'session' function. If the scope is left because of an error
|
||||||
|
* (e.g., an exception), the donation will be reverted.
|
||||||
|
*/
|
||||||
|
~Transfer()
|
||||||
|
{
|
||||||
|
if (!_ack && _from.valid() && _to.valid())
|
||||||
|
Ram_session_client(_to).transfer_quota(_from, _quantum);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge quota donation
|
||||||
|
*/
|
||||||
|
void acknowledge() { _ack = true; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********************
|
||||||
|
** Child::Session **
|
||||||
|
********************/
|
||||||
|
|
||||||
|
class Child::Session : public Object_pool<Session>::Entry,
|
||||||
|
public List<Session>::Element
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
enum { IDENT_LEN = 16 };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session capability at the server
|
||||||
|
*/
|
||||||
|
Session_capability _cap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service interface that was used to create the session
|
||||||
|
*/
|
||||||
|
Service *_service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server implementing the session
|
||||||
|
*
|
||||||
|
* Even though we can normally determine the server of the session via
|
||||||
|
* '_service->server()', this does not apply when destructing a server.
|
||||||
|
* During destruction, we use the 'Server' pointer as opaque key for
|
||||||
|
* revoking active sessions of the server. So we keep a copy
|
||||||
|
* independent of the 'Service' object.
|
||||||
|
*/
|
||||||
|
Server *_server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total of quota associated with this session
|
||||||
|
*/
|
||||||
|
size_t _donated_ram_quota;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of session, used for debugging
|
||||||
|
*/
|
||||||
|
char _ident[IDENT_LEN];
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*
|
||||||
|
* \param session session capability
|
||||||
|
* \param service service that implements the session
|
||||||
|
* \param ram_quota initial quota donation associated with
|
||||||
|
* the session
|
||||||
|
* \param ident optional session identifier, used for
|
||||||
|
* debugging
|
||||||
|
*/
|
||||||
|
Session(Session_capability session, Service *service,
|
||||||
|
size_t ram_quota, const char *ident = "<noname>")
|
||||||
|
:
|
||||||
|
Object_pool<Session>::Entry(session), _cap(session),
|
||||||
|
_service(service), _server(service->server()),
|
||||||
|
_donated_ram_quota(ram_quota) {
|
||||||
|
strncpy(_ident, ident, sizeof(_ident)); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor creates invalid session
|
||||||
|
*/
|
||||||
|
Session() : _service(0), _donated_ram_quota(0) { }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend amount of ram attached to the session
|
||||||
|
*/
|
||||||
|
void upgrade_ram_quota(size_t ram_quota) {
|
||||||
|
_donated_ram_quota += ram_quota; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accessors
|
||||||
|
*/
|
||||||
|
Session_capability cap() const { return _cap; }
|
||||||
|
size_t donated_ram_quota() const { return _donated_ram_quota; }
|
||||||
|
bool valid() const { return _service != 0; }
|
||||||
|
Service *service() const { return _service; }
|
||||||
|
Server *server() const { return _server; }
|
||||||
|
const char *ident() const { return _ident; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/***********
|
||||||
|
** Child **
|
||||||
|
***********/
|
||||||
|
|
||||||
|
void Child::_add_session(Child::Session const &s)
|
||||||
|
{
|
||||||
|
Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store session information in a new child's meta data structure. The
|
||||||
|
* allocation from 'heap()' may throw a 'Ram_session::Quota_exceeded'
|
||||||
|
* exception.
|
||||||
|
*/
|
||||||
|
Session *session = 0;
|
||||||
|
try {
|
||||||
|
session = new (heap())
|
||||||
|
Session(s.cap(), s.service(),
|
||||||
|
s.donated_ram_quota(), s.ident()); }
|
||||||
|
catch (Allocator::Out_of_memory) {
|
||||||
|
throw Parent::Quota_exceeded(); }
|
||||||
|
|
||||||
|
/* these functions may also throw 'Ram_session::Quota_exceeded' */
|
||||||
|
_session_pool.insert(session);
|
||||||
|
_session_list.insert(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Child::_remove_session(Child::Session *s)
|
||||||
|
{
|
||||||
|
/* forget about this session */
|
||||||
|
_session_pool.remove(s);
|
||||||
|
_session_list.remove(s);
|
||||||
|
|
||||||
|
/* return session quota to the ram session of the child */
|
||||||
|
if (_policy->ref_ram_session()->transfer_quota(_ram, s->donated_ram_quota()))
|
||||||
|
PERR("We ran out of our own quota");
|
||||||
|
|
||||||
|
destroy(heap(), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Service *Child::_parent_service()
|
||||||
|
{
|
||||||
|
static Parent_service parent_service("");
|
||||||
|
return &parent_service;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Child::revoke_server(Server const *server)
|
||||||
|
{
|
||||||
|
Lock::Guard lock_guard(_lock);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
/* search session belonging to the specified server */
|
||||||
|
Session *s = _session_list.first();
|
||||||
|
for ( ; s && (s->server() != server); s = s->next());
|
||||||
|
|
||||||
|
/* if no matching session exists, we are done */
|
||||||
|
if (!s) return;
|
||||||
|
|
||||||
|
_remove_session(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Child::announce(Parent::Service_name const &name, Root_capability root)
|
||||||
|
{
|
||||||
|
if (!name.is_valid_string()) return;
|
||||||
|
|
||||||
|
_policy->announce_service(name.string(), root, heap(), &_server);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Session_capability Child::session(Parent::Service_name const &name,
|
||||||
|
Parent::Session_args const &args)
|
||||||
|
{
|
||||||
|
if (!name.is_valid_string() || !args.is_valid_string()) throw Unavailable();
|
||||||
|
|
||||||
|
/* return sessions that we created for the child */
|
||||||
|
if (!strcmp("Env::ram_session", name.string())) return _ram;
|
||||||
|
if (!strcmp("Env::cpu_session", name.string())) return _cpu;
|
||||||
|
if (!strcmp("Env::rm_session", name.string())) return _rm;
|
||||||
|
if (!strcmp("Env::pd_session", name.string())) return _process.pd_session_cap();
|
||||||
|
|
||||||
|
/* filter session arguments according to the child policy */
|
||||||
|
strncpy(_args, args.string(), sizeof(_args));
|
||||||
|
_policy->filter_session_args(name.string(), _args, sizeof(_args));
|
||||||
|
|
||||||
|
/* transfer the quota donation from the child's account to ourself */
|
||||||
|
size_t ram_quota = Arg_string::find_arg(_args, "ram_quota").long_value(0);
|
||||||
|
|
||||||
|
Transfer donation_from_child(ram_quota, _ram, env()->ram_session_cap());
|
||||||
|
|
||||||
|
Service *service = _policy->resolve_session_request(name.string(), _args);
|
||||||
|
|
||||||
|
/* raise an error if no matching service provider could be found */
|
||||||
|
if (!service)
|
||||||
|
throw Service_denied();
|
||||||
|
|
||||||
|
/* transfer session quota from ourself to the service provider */
|
||||||
|
Transfer donation_to_service(ram_quota, env()->ram_session_cap(),
|
||||||
|
service->ram_session_cap());
|
||||||
|
|
||||||
|
/* create session */
|
||||||
|
Session_capability cap;
|
||||||
|
try { cap = service->session(_args); }
|
||||||
|
catch (Service::Invalid_args) { throw Service_denied(); }
|
||||||
|
catch (Service::Unavailable) { throw Service_denied(); }
|
||||||
|
catch (Service::Quota_exceeded) { throw Quota_exceeded(); }
|
||||||
|
|
||||||
|
/* register session */
|
||||||
|
try { _add_session(Session(cap, service, ram_quota, name.string())); }
|
||||||
|
catch (Ram_session::Quota_exceeded) { throw Quota_exceeded(); }
|
||||||
|
|
||||||
|
/* finish transaction */
|
||||||
|
donation_from_child.acknowledge();
|
||||||
|
donation_to_service.acknowledge();
|
||||||
|
|
||||||
|
return cap;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Child::upgrade(Session_capability to_session, Parent::Upgrade_args const &args)
|
||||||
|
{
|
||||||
|
Service *targeted_service = 0;
|
||||||
|
|
||||||
|
/* check of upgrade refers to an Env:: resource */
|
||||||
|
if (to_session.local_name() == _ram.local_name())
|
||||||
|
targeted_service = &_ram_service;
|
||||||
|
if (to_session.local_name() == _cpu.local_name())
|
||||||
|
targeted_service = &_cpu_service;
|
||||||
|
if (to_session.local_name() == _rm.local_name())
|
||||||
|
targeted_service = &_rm_service;
|
||||||
|
|
||||||
|
/* check if upgrade refers to server */
|
||||||
|
Session * const session = _session_pool.obj_by_cap(to_session);
|
||||||
|
if (session)
|
||||||
|
targeted_service = session->service();
|
||||||
|
|
||||||
|
if (!targeted_service) {
|
||||||
|
PWRN("could not lookup service for session upgrade");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args.is_valid_string()) {
|
||||||
|
PWRN("no valid session-upgrade arguments");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t const ram_quota =
|
||||||
|
Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0);
|
||||||
|
|
||||||
|
/* transfer quota from client to ourself */
|
||||||
|
Transfer donation_from_child(ram_quota, _ram,
|
||||||
|
env()->ram_session_cap());
|
||||||
|
|
||||||
|
/* transfer session quota from ourself to the service provider */
|
||||||
|
Transfer donation_to_service(ram_quota, env()->ram_session_cap(),
|
||||||
|
targeted_service->ram_session_cap());
|
||||||
|
|
||||||
|
try { targeted_service->upgrade(to_session, args.string()); }
|
||||||
|
catch (Service::Quota_exceeded) { throw Quota_exceeded(); }
|
||||||
|
|
||||||
|
/* remember new amount attached to the session */
|
||||||
|
if (session)
|
||||||
|
session->upgrade_ram_quota(ram_quota);
|
||||||
|
|
||||||
|
/* finish transaction */
|
||||||
|
donation_from_child.acknowledge();
|
||||||
|
donation_to_service.acknowledge();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Child::close(Session_capability session_cap)
|
||||||
|
{
|
||||||
|
/* refuse to close the child's initial sessions */
|
||||||
|
if (session_cap.local_name() == _ram.local_name()
|
||||||
|
|| session_cap.local_name() == _cpu.local_name()
|
||||||
|
|| session_cap.local_name() == _rm.local_name()
|
||||||
|
|| session_cap.local_name() == _process.pd_session_cap().local_name())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Session *s = _session_pool.obj_by_cap(session_cap);
|
||||||
|
|
||||||
|
if (!s) {
|
||||||
|
PWRN("no session structure found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is a chance that the server is not responding to the 'close' call,
|
||||||
|
* making us block infinitely. However, by using core's cancel-blocking
|
||||||
|
* mechanism, we can cancel the 'close' call by another (watchdog) thread
|
||||||
|
* that invokes 'cancel_blocking' at our thread after a timeout. The
|
||||||
|
* unblocking is reflected at the API level as an 'Blocking_canceled'
|
||||||
|
* exception. We catch this exception to proceed with normal operation
|
||||||
|
* after being unblocked.
|
||||||
|
*/
|
||||||
|
try { s->service()->close(s->cap()); }
|
||||||
|
catch (Blocking_canceled) {
|
||||||
|
PDBG("Got Blocking_canceled exception during %s->close call\n",
|
||||||
|
s->ident()); }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the session was provided by a child of us,
|
||||||
|
* 'server()->ram_session_cap()' returns the RAM session of the
|
||||||
|
* corresponding child. Since the session to the server is closed now, we
|
||||||
|
* expect that the server released all donated resources and we can
|
||||||
|
* decrease the servers' quota.
|
||||||
|
*
|
||||||
|
* If this goes wrong, the server is misbehaving.
|
||||||
|
*/
|
||||||
|
if (s->service()->ram_session_cap().valid()) {
|
||||||
|
Ram_session_client server_ram(s->service()->ram_session_cap());
|
||||||
|
if (server_ram.transfer_quota(env()->ram_session_cap(),
|
||||||
|
s->donated_ram_quota())) {
|
||||||
|
PERR("Misbehaving server '%s'!", s->service()->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Lock::Guard lock_guard(_lock);
|
||||||
|
_remove_session(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Child::exit(int exit_value)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This function receives the hint from the child that now, its a good time
|
||||||
|
* to kill it. An inherited child class could use this hint to schedule the
|
||||||
|
* destruction of the child object.
|
||||||
|
*
|
||||||
|
* Note that the child object must not be destructed from by this function
|
||||||
|
* because it is executed by the thread contained in the child object.
|
||||||
|
*/
|
||||||
|
return _policy->exit(exit_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Child::Child(Dataspace_capability elf_ds,
|
||||||
|
Ram_session_capability ram,
|
||||||
|
Cpu_session_capability cpu,
|
||||||
|
Rm_session_capability rm,
|
||||||
|
Rpc_entrypoint *entrypoint,
|
||||||
|
Child_policy *policy,
|
||||||
|
Service &ram_service,
|
||||||
|
Service &cpu_service,
|
||||||
|
Service &rm_service)
|
||||||
|
:
|
||||||
|
_ram(ram), _ram_session_client(ram), _cpu(cpu), _rm(rm),
|
||||||
|
_ram_service(ram_service), _cpu_service(cpu_service),
|
||||||
|
_rm_service(rm_service),
|
||||||
|
_heap(&_ram_session_client, env()->rm_session()),
|
||||||
|
_entrypoint(entrypoint),
|
||||||
|
_parent_cap(_entrypoint->manage(this)),
|
||||||
|
_policy(policy),
|
||||||
|
_server(ram),
|
||||||
|
_process(elf_ds, ram, cpu, rm, _parent_cap, policy->name(), 0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
Child::~Child()
|
||||||
|
{
|
||||||
|
_entrypoint->dissolve(this);
|
||||||
|
_policy->unregister_services();
|
||||||
|
|
||||||
|
for (Session *s; (s = _session_pool.first()); )
|
||||||
|
close(s->cap());
|
||||||
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
TARGET = test-rmfault
|
TARGET = test-rmfault
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = cxx env server signal process
|
LIBS = cxx env server signal child
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
LIBS = process
|
LIBS = child
|
||||||
SRC_CC = launchpad.cc
|
SRC_CC = launchpad.cc
|
||||||
|
|
||||||
vpath launchpad.cc $(REP_DIR)/src/lib/launchpad
|
vpath launchpad.cc $(REP_DIR)/src/lib/launchpad
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
TARGET = d3m
|
TARGET = d3m
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = cxx env signal server process
|
LIBS = cxx env signal server child
|
||||||
INC_DIR += $(PRG_DIR)
|
INC_DIR += $(PRG_DIR)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
TARGET = acpi_drv
|
TARGET = acpi_drv
|
||||||
REQUIRES = x86_32
|
REQUIRES = x86_32
|
||||||
SRC_CC = main.cc acpi.cc
|
SRC_CC = main.cc acpi.cc
|
||||||
LIBS = cxx env server process
|
LIBS = cxx env server child
|
||||||
|
|
||||||
INC_DIR = $(PRG_DIR)/..
|
INC_DIR = $(PRG_DIR)/..
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
TARGET = init
|
TARGET = init
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = env cxx server process
|
LIBS = env cxx server child
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
TARGET = loader
|
TARGET = loader
|
||||||
LIBS = cxx env thread server process signal
|
LIBS = cxx env thread server child signal
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
INC_DIR += $(PRG_DIR)
|
INC_DIR += $(PRG_DIR)
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
TARGET = bomb
|
TARGET = bomb
|
||||||
LIBS = cxx env thread process server
|
LIBS = cxx env thread child server
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
TARGET = test-dynamic_config_master
|
TARGET = test-dynamic_config_master
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = env signal server process
|
LIBS = env signal server child
|
||||||
|
|
|
@ -10,7 +10,8 @@ INC_DIR += $(GDB_CONTRIB_DIR)/include \
|
||||||
$(PRG_DIR)/gdbserver \
|
$(PRG_DIR)/gdbserver \
|
||||||
$(PRG_DIR)
|
$(PRG_DIR)
|
||||||
|
|
||||||
LIBS = env signal libc libc_log libc_terminal libc_lock_pipe lock process server gdbserver_platform gdbserver_libc_support
|
LIBS = env signal libc libc_log libc_terminal libc_lock_pipe lock child \
|
||||||
|
server gdbserver_platform gdbserver_libc_support
|
||||||
|
|
||||||
SRC_C = event-loop.c \
|
SRC_C = event-loop.c \
|
||||||
i386-low.c \
|
i386-low.c \
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TARGET = noux
|
TARGET = noux
|
||||||
LIBS = cxx env server process signal thread alarm
|
LIBS = cxx env server child signal thread alarm
|
||||||
SRC_CC = main.cc dummy_net.cc
|
SRC_CC = main.cc dummy_net.cc
|
||||||
INC_DIR += $(PRG_DIR)
|
INC_DIR += $(PRG_DIR)
|
||||||
INC_DIR += $(PRG_DIR)/../
|
INC_DIR += $(PRG_DIR)/../
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
TARGET = noux_net
|
TARGET = noux_net
|
||||||
LIBS = cxx env server process signal lwip thread alarm
|
LIBS = cxx env server child signal lwip thread alarm
|
||||||
|
|
||||||
LIBS += libc libc_lwip
|
LIBS += libc libc_lwip
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user