mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-20 06:07:59 +00:00
parent
bf37159eb9
commit
48f831af3c
@ -23,7 +23,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/signal.h>
|
|
||||||
#include <cpu/cpu_state.h>
|
#include <cpu/cpu_state.h>
|
||||||
#include <base/thread_state.h>
|
#include <base/thread_state.h>
|
||||||
|
|
||||||
@ -56,7 +55,7 @@ namespace Kernel
|
|||||||
{
|
{
|
||||||
/* import Genode types */
|
/* import Genode types */
|
||||||
typedef Genode::Thread_state Thread_state;
|
typedef Genode::Thread_state Thread_state;
|
||||||
typedef Genode::umword_t umword_t;
|
typedef Genode::umword_t umword_t;
|
||||||
|
|
||||||
class Schedule_context;
|
class Schedule_context;
|
||||||
|
|
||||||
@ -297,13 +296,6 @@ void Kernel::Thread::await_signal(Kernel::Signal_receiver * receiver)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::received_signal()
|
|
||||||
{
|
|
||||||
assert(_state == AWAIT_SIGNAL);
|
|
||||||
_schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::_received_irq()
|
void Kernel::Thread::_received_irq()
|
||||||
{
|
{
|
||||||
assert(_state == AWAIT_IRQ);
|
assert(_state == AWAIT_IRQ);
|
||||||
@ -361,145 +353,13 @@ void Kernel::Thread::_awaits_irq()
|
|||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
class Signal_receiver;
|
|
||||||
|
|
||||||
/**
|
void deliver_signal(Signal_handler * const dst,
|
||||||
* Specific signal type, owned by a receiver, can be triggered asynchr.
|
void * const base,
|
||||||
*/
|
size_t const size)
|
||||||
class Signal_context : public Object<Signal_context, MAX_SIGNAL_CONTEXTS>,
|
|
||||||
public Fifo<Signal_context>::Element
|
|
||||||
{
|
{
|
||||||
friend class Signal_receiver;
|
((Thread *)dst->id())->receive_signal(base, size);
|
||||||
|
}
|
||||||
Signal_receiver * const _receiver; /* the receiver that owns us */
|
|
||||||
unsigned const _imprint; /* every outgoing signals gets
|
|
||||||
* signed with this */
|
|
||||||
unsigned _submits; /* accumul. undelivered submits */
|
|
||||||
bool _await_ack; /* delivery ack pending */
|
|
||||||
Thread * _killer; /* awaits our destruction if >0 */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Utility to deliver all remaining submits
|
|
||||||
*/
|
|
||||||
void _deliver();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called by receiver when all submits have been delivered
|
|
||||||
*/
|
|
||||||
void _delivered()
|
|
||||||
{
|
|
||||||
_submits = 0;
|
|
||||||
_await_ack = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Signal_context(Signal_receiver * const r, unsigned const imprint) :
|
|
||||||
_receiver(r), _imprint(imprint),
|
|
||||||
_submits(0), _await_ack(0), _killer(0) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submit the signal
|
|
||||||
*
|
|
||||||
* \param n number of submits
|
|
||||||
*/
|
|
||||||
void submit(unsigned const n);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledge delivery of signal
|
|
||||||
*/
|
|
||||||
void ack();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destruct or prepare to do it at next call of 'ack'
|
|
||||||
*
|
|
||||||
* \return wether destruction is done
|
|
||||||
*/
|
|
||||||
bool kill(Thread * const killer)
|
|
||||||
{
|
|
||||||
assert(!_killer);
|
|
||||||
_killer = killer;
|
|
||||||
if (_await_ack) {
|
|
||||||
_killer->kill_signal_context_blocks();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
this->~Signal_context();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage signal contexts and enable threads to trigger and await them
|
|
||||||
*/
|
|
||||||
class Signal_receiver :
|
|
||||||
public Object<Signal_receiver, MAX_SIGNAL_RECEIVERS>
|
|
||||||
{
|
|
||||||
Fifo<Thread> _listeners;
|
|
||||||
Fifo<Signal_context> _pending_contexts;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deliver as much submitted signals to listening threads as possible
|
|
||||||
*/
|
|
||||||
void _listen()
|
|
||||||
{
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
/* any pending context? */
|
|
||||||
if (_pending_contexts.empty()) return;
|
|
||||||
Signal_context * const c = _pending_contexts.dequeue();
|
|
||||||
|
|
||||||
/* if there is no listener, enqueue context again and return */
|
|
||||||
if (_listeners.empty()) {
|
|
||||||
_pending_contexts.enqueue(c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* awake a listener and transmit signal info to it */
|
|
||||||
Thread * const t = _listeners.dequeue();
|
|
||||||
Signal::Data data((Genode::Signal_context *)c->_imprint,
|
|
||||||
c->_submits);
|
|
||||||
*(Signal::Data *)t->phys_utcb()->base() = data;
|
|
||||||
t->received_signal();
|
|
||||||
c->_delivered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Let a thread listen to our contexts
|
|
||||||
*/
|
|
||||||
void add_listener(Thread * const t)
|
|
||||||
{
|
|
||||||
t->await_signal(this);
|
|
||||||
_listeners.enqueue(t);
|
|
||||||
_listen();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stop a thread from listening to our contexts
|
|
||||||
*/
|
|
||||||
void remove_listener(Thread * const t) {
|
|
||||||
_listeners.remove(t); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If any of our contexts is pending
|
|
||||||
*/
|
|
||||||
bool pending() { return !_pending_contexts.empty(); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recognize that 'c' wants to deliver
|
|
||||||
*/
|
|
||||||
void deliver(Signal_context * const c)
|
|
||||||
{
|
|
||||||
assert(c->_receiver == this);
|
|
||||||
if (!c->is_enqueued()) _pending_contexts.enqueue(c);
|
|
||||||
_listen();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class Vm : public Object<Vm, MAX_VMS>,
|
class Vm : public Object<Vm, MAX_VMS>,
|
||||||
public Schedule_context
|
public Schedule_context
|
||||||
@ -1053,7 +913,8 @@ namespace Kernel
|
|||||||
assert(r);
|
assert(r);
|
||||||
|
|
||||||
/* let user listen to receiver */
|
/* let user listen to receiver */
|
||||||
r->add_listener(user);
|
user->await_signal(r);
|
||||||
|
r->add_handler(user->signal_handler());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1068,7 +929,7 @@ namespace Kernel
|
|||||||
assert(r);
|
assert(r);
|
||||||
|
|
||||||
/* set return value */
|
/* set return value */
|
||||||
user->user_arg_0(r->pending());
|
user->user_arg_0(r->deliverable());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1094,10 +955,11 @@ namespace Kernel
|
|||||||
*/
|
*/
|
||||||
void do_ack_signal(Thread * const user)
|
void do_ack_signal(Thread * const user)
|
||||||
{
|
{
|
||||||
Signal_context * const c =
|
unsigned id = user->user_arg_1();
|
||||||
Signal_context::pool()->object(user->user_arg_1());
|
Signal_context * const c = Signal_context::pool()->object(id);
|
||||||
assert(c);
|
if (!c) return;
|
||||||
c->ack();
|
Thread * const t = (Thread *)c->ack();
|
||||||
|
if (t) { t->kill_signal_context_done(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1106,10 +968,11 @@ namespace Kernel
|
|||||||
*/
|
*/
|
||||||
void do_kill_signal_context(Thread * const user)
|
void do_kill_signal_context(Thread * const user)
|
||||||
{
|
{
|
||||||
Signal_context * const c =
|
unsigned id = user->user_arg_1();
|
||||||
Signal_context::pool()->object(user->user_arg_1());
|
Signal_context * const c = Signal_context::pool()->object(id);
|
||||||
assert(c);
|
if (!c) { return; }
|
||||||
user->user_arg_0(c->kill(user));
|
if (c->kill((unsigned)user)) { return; }
|
||||||
|
user->kill_signal_context_blocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1319,7 +1182,7 @@ int Kernel::Thread::resume()
|
|||||||
return 0;
|
return 0;
|
||||||
case AWAIT_SIGNAL:
|
case AWAIT_SIGNAL:
|
||||||
PDBG("cancel signal receipt");
|
PDBG("cancel signal receipt");
|
||||||
_signal_receiver->remove_listener(this);
|
_signal_receiver->remove_handler(signal_handler());
|
||||||
_schedule();
|
_schedule();
|
||||||
return 0;
|
return 0;
|
||||||
case AWAIT_SIGNAL_CONTEXT_DESTRUCT:
|
case AWAIT_SIGNAL_CONTEXT_DESTRUCT:
|
||||||
@ -1409,38 +1272,3 @@ void Thread::kill_signal_context_done()
|
|||||||
user_arg_0(1);
|
user_arg_0(1);
|
||||||
_schedule();
|
_schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************
|
|
||||||
** Kernel::Signal_context **
|
|
||||||
****************************/
|
|
||||||
|
|
||||||
void Signal_context::_deliver()
|
|
||||||
{
|
|
||||||
if (!_submits) return;
|
|
||||||
_receiver->deliver(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Signal_context::ack()
|
|
||||||
{
|
|
||||||
assert(_await_ack);
|
|
||||||
_await_ack = 0;
|
|
||||||
if (!_killer) {
|
|
||||||
_deliver();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_killer->kill_signal_context_done();
|
|
||||||
this->~Signal_context();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Signal_context::submit(unsigned const n)
|
|
||||||
{
|
|
||||||
assert(_submits < (unsigned)~0 - n);
|
|
||||||
if (_killer) return;
|
|
||||||
_submits += n;
|
|
||||||
if (_await_ack) return;
|
|
||||||
_deliver();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -21,48 +21,83 @@
|
|||||||
/* core include */
|
/* core include */
|
||||||
#include <kernel/configuration.h>
|
#include <kernel/configuration.h>
|
||||||
#include <kernel/object.h>
|
#include <kernel/object.h>
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
typedef Genode::Signal Signal;
|
/**
|
||||||
|
* Enables external components to act as a signal handler
|
||||||
class Signal_receiver;
|
*/
|
||||||
|
class Signal_handler;
|
||||||
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
|
||||||
|
|
||||||
class Signal_listener : public Fifo<Signal_listener>::Element
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
virtual void receive_signal(void * const signal_base,
|
|
||||||
size_t const signal_size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specific signal type, owned by a receiver, can be triggered asynchr.
|
* Signal types that are assigned to a signal receiver each
|
||||||
*/
|
*/
|
||||||
class Signal_context : public Object<Signal_context, MAX_SIGNAL_CONTEXTS>,
|
class Signal_context;
|
||||||
public Fifo<Signal_context>::Element
|
|
||||||
{
|
|
||||||
friend class Signal_receiver;
|
|
||||||
|
|
||||||
Signal_receiver * const _receiver; /* the receiver that owns us */
|
/**
|
||||||
unsigned const _imprint; /* every outgoing signals gets
|
* Combines signal contexts to an entity that handlers can listen to
|
||||||
* signed with this */
|
*/
|
||||||
unsigned _submits; /* accumul. undelivered submits */
|
class Signal_receiver;
|
||||||
bool _await_ack; /* delivery ack pending */
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* if not zero, _killer_id holds the ID of the actor
|
* Signal delivery backend
|
||||||
* that awaits the destruction of the signal context
|
*
|
||||||
*/
|
* \param dst destination
|
||||||
unsigned _killer_id;
|
* \param base signal-data base
|
||||||
|
* \param size signal-data size
|
||||||
|
*/
|
||||||
|
void deliver_signal(Signal_handler * const dst,
|
||||||
|
void * const base,
|
||||||
|
size_t const size);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Kernel::Signal_handler
|
||||||
|
{
|
||||||
|
friend class Signal_receiver;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef Genode::Fifo_element<Signal_handler> Fifo_element;
|
||||||
|
|
||||||
|
Fifo_element _fe;
|
||||||
|
unsigned const _id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility to deliver all remaining submits
|
* Constructor
|
||||||
*/
|
*/
|
||||||
inline void _deliver();
|
Signal_handler(unsigned id) : _fe(this), _id(id) { }
|
||||||
|
|
||||||
|
|
||||||
|
/***************
|
||||||
|
** Accessors **
|
||||||
|
***************/
|
||||||
|
|
||||||
|
unsigned id() { return _id; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class Kernel::Signal_context
|
||||||
|
:
|
||||||
|
public Object<Signal_context, MAX_SIGNAL_CONTEXTS>
|
||||||
|
{
|
||||||
|
friend class Signal_receiver;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef Genode::Fifo_element<Signal_context> Fifo_element;
|
||||||
|
|
||||||
|
Fifo_element _fe;
|
||||||
|
Signal_receiver * const _receiver;
|
||||||
|
unsigned const _imprint;
|
||||||
|
unsigned _submits;
|
||||||
|
bool _ack;
|
||||||
|
unsigned _killer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell receiver about the submits of the context if any
|
||||||
|
*/
|
||||||
|
inline void _deliverable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by receiver when all submits have been delivered
|
* Called by receiver when all submits have been delivered
|
||||||
@ -70,139 +105,162 @@ namespace Kernel
|
|||||||
void _delivered()
|
void _delivered()
|
||||||
{
|
{
|
||||||
_submits = 0;
|
_submits = 0;
|
||||||
_await_ack = 1;
|
_ack = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*/
|
|
||||||
Signal_context(Signal_receiver * const r, unsigned const imprint) :
|
|
||||||
_receiver(r), _imprint(imprint),
|
|
||||||
_submits(0), _await_ack(0), _killer_id(0) { }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submit the signal
|
|
||||||
*
|
|
||||||
* \param n number of submits
|
|
||||||
*/
|
|
||||||
void submit(unsigned const n)
|
|
||||||
{
|
|
||||||
assert(_submits < (unsigned)~0 - n);
|
|
||||||
if (_killer_id) { return; }
|
|
||||||
_submits += n;
|
|
||||||
if (_await_ack) { return; }
|
|
||||||
_deliver();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Acknowledge delivery of signal
|
|
||||||
*
|
|
||||||
* \retval 0 no kill request finished
|
|
||||||
* \retval > 0 name of finished kill request
|
|
||||||
*/
|
|
||||||
unsigned ack()
|
|
||||||
{
|
|
||||||
assert(_await_ack);
|
|
||||||
_await_ack = 0;
|
|
||||||
if (!_killer_id) {
|
|
||||||
_deliver();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
this->~Signal_context();
|
|
||||||
return _killer_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destruct or prepare to do it at next call of 'ack'
|
|
||||||
*
|
|
||||||
* \param killer_id name of the kill request
|
|
||||||
*
|
|
||||||
* \return wether destruction is done
|
|
||||||
*/
|
|
||||||
bool kill(unsigned const killer_id)
|
|
||||||
{
|
|
||||||
assert(!_killer_id);
|
|
||||||
_killer_id = killer_id;
|
|
||||||
if (_await_ack) { return 0; }
|
|
||||||
this->~Signal_context();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Manage signal contexts & enable external actors to trigger & await them
|
|
||||||
*/
|
|
||||||
class Signal_receiver :
|
|
||||||
public Object<Signal_receiver, MAX_SIGNAL_RECEIVERS>
|
|
||||||
{
|
|
||||||
Fifo<Signal_listener> _listeners;
|
|
||||||
Fifo<Signal_context> _pending_contexts;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deliver as much submitted signals to listeners as possible
|
* Constructor
|
||||||
|
*/
|
||||||
|
Signal_context(Signal_receiver * const r, unsigned const imprint)
|
||||||
|
:
|
||||||
|
_fe(this), _receiver(r), _imprint(imprint), _submits(0), _ack(1),
|
||||||
|
_killer(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit the signal
|
||||||
|
*
|
||||||
|
* \param n number of submits
|
||||||
|
*/
|
||||||
|
void submit(unsigned const n)
|
||||||
|
{
|
||||||
|
if (_submits >= (unsigned)~0 - n) {
|
||||||
|
PERR("overflow at signal-submit count");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_killer) {
|
||||||
|
PERR("signal context already in destruction");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_submits += n;
|
||||||
|
if (!_ack) { return; }
|
||||||
|
_deliverable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge delivery of signal
|
||||||
|
*
|
||||||
|
* \retval 0 no kill request finished
|
||||||
|
* \retval > 0 name of finished kill request
|
||||||
|
*/
|
||||||
|
unsigned ack()
|
||||||
|
{
|
||||||
|
if (_ack) {
|
||||||
|
PERR("unexpected signal acknowledgment");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!_killer) {
|
||||||
|
_ack = 1;
|
||||||
|
_deliverable();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
this->~Signal_context();
|
||||||
|
return _killer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destruct context or prepare to do it as soon as delivery is done
|
||||||
|
*
|
||||||
|
* \param killer name of the kill request
|
||||||
|
*
|
||||||
|
* \retval 1 destruction is done
|
||||||
|
* \retval 0 destruction is initiated, will be done with the next ack
|
||||||
|
*/
|
||||||
|
bool kill(unsigned const killer)
|
||||||
|
{
|
||||||
|
/* FIXME: aggregate or avoid multiple kill requests */
|
||||||
|
if (_killer) {
|
||||||
|
PERR("multiple kill requests");
|
||||||
|
while (1) { }
|
||||||
|
}
|
||||||
|
_killer = killer;
|
||||||
|
if (!_ack) { return 0; }
|
||||||
|
this->~Signal_context();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Kernel::Signal_receiver
|
||||||
|
:
|
||||||
|
public Object<Signal_receiver, MAX_SIGNAL_RECEIVERS>
|
||||||
|
{
|
||||||
|
friend class Signal_context;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
typedef Genode::Signal Signal;
|
||||||
|
|
||||||
|
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
||||||
|
|
||||||
|
Fifo<Signal_handler::Fifo_element> _handlers;
|
||||||
|
Fifo<Signal_context::Fifo_element> _deliverable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recognize that context 'c' has submits to deliver
|
||||||
|
*/
|
||||||
|
void _add_deliverable(Signal_context * const c)
|
||||||
|
{
|
||||||
|
if (!c->_fe.is_enqueued()) _deliverable.enqueue(&c->_fe);
|
||||||
|
_listen();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deliver as much submits as possible
|
||||||
*/
|
*/
|
||||||
void _listen()
|
void _listen()
|
||||||
{
|
{
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
/* any pending context? */
|
/* check if there are deliverable signal */
|
||||||
if (_pending_contexts.empty()) return;
|
if (_deliverable.empty()) return;
|
||||||
Signal_context * const c = _pending_contexts.dequeue();
|
Signal_context * const c = _deliverable.dequeue()->object();
|
||||||
|
|
||||||
/* if there is no listener, enqueue context again and return */
|
/* if there is no handler re-enqueue context and exit */
|
||||||
if (_listeners.empty()) {
|
if (_handlers.empty()) {
|
||||||
_pending_contexts.enqueue(c);
|
_deliverable.enqueue(&c->_fe);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* awake a listener and transmit signal info to it */
|
/* delivery from context to handler */
|
||||||
Signal_listener * const l = _listeners.dequeue();
|
Signal_handler * const h = _handlers.dequeue()->object();
|
||||||
Signal::Data data((Genode::Signal_context *)c->_imprint,
|
Signal::Data data((Genode::Signal_context *)c->_imprint,
|
||||||
c->_submits);
|
c->_submits);
|
||||||
l->receive_signal(&data, sizeof(data));
|
deliver_signal(h, &data, sizeof(data));
|
||||||
c->_delivered();
|
c->_delivered();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Let a listener listen to the contexts of the receiver
|
* Let a handler wait for signals of the receiver
|
||||||
*/
|
*/
|
||||||
void add_listener(Signal_listener * const l)
|
void add_handler(Signal_handler * const h)
|
||||||
{
|
{
|
||||||
_listeners.enqueue(l);
|
_handlers.enqueue(&h->_fe);
|
||||||
_listen();
|
_listen();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop a listener from listen to the contexts of the receiver
|
* Stop a handler from waiting for signals of the receiver
|
||||||
*/
|
*/
|
||||||
void remove_listener(Signal_listener * const l) { _listeners.remove(l); }
|
void remove_handler(Signal_handler * const h)
|
||||||
|
{
|
||||||
|
_handlers.remove(&h->_fe);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return wether any of the contexts of this receiver is pending
|
* Return wether any of the contexts of this receiver is deliverable
|
||||||
*/
|
*/
|
||||||
bool pending() { return !_pending_contexts.empty(); }
|
bool deliverable() { return !_deliverable.empty(); }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Recognize that context 'c' wants to be delivered
|
|
||||||
*/
|
|
||||||
void deliver(Signal_context * const c)
|
|
||||||
{
|
|
||||||
assert(c->_receiver == this);
|
|
||||||
if (!c->is_enqueued()) _pending_contexts.enqueue(c);
|
|
||||||
_listen();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Kernel::Signal_context::_deliver()
|
void Kernel::Signal_context::_deliverable()
|
||||||
{
|
{
|
||||||
if (!_submits) return;
|
if (!_submits) return;
|
||||||
_receiver->deliver(this);
|
_receiver->_add_deliverable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* _KERNEL__SIGNAL_RECEIVER_ */
|
#endif /* _KERNEL__SIGNAL_RECEIVER_ */
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#define _CORE__KERNEL__THREAD_H_
|
#define _CORE__KERNEL__THREAD_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/signal_receiver.h>
|
||||||
#include <kernel/ipc_node.h>
|
#include <kernel/ipc_node.h>
|
||||||
#include <kernel/configuration.h>
|
#include <kernel/configuration.h>
|
||||||
#include <kernel/scheduler.h>
|
#include <kernel/scheduler.h>
|
||||||
@ -34,7 +35,6 @@ namespace Kernel
|
|||||||
typedef Genode::Cpu Cpu;
|
typedef Genode::Cpu Cpu;
|
||||||
typedef Genode::Page_flags Page_flags;
|
typedef Genode::Page_flags Page_flags;
|
||||||
typedef Genode::Core_tlb Core_tlb;
|
typedef Genode::Core_tlb Core_tlb;
|
||||||
typedef Genode::Signal Signal;
|
|
||||||
typedef Genode::Pagefault Pagefault;
|
typedef Genode::Pagefault Pagefault;
|
||||||
typedef Genode::Native_utcb Native_utcb;
|
typedef Genode::Native_utcb Native_utcb;
|
||||||
|
|
||||||
@ -52,15 +52,12 @@ namespace Kernel
|
|||||||
virtual void proceed() = 0;
|
virtual void proceed() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> class Fifo : public Genode::Fifo<T> { };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kernel representation of a user thread
|
* Kernel representation of a user thread
|
||||||
*/
|
*/
|
||||||
class Thread : public Cpu::User_context,
|
class Thread : public Cpu::User_context,
|
||||||
public Object<Thread, MAX_THREADS>,
|
public Object<Thread, MAX_THREADS>,
|
||||||
public Schedule_context,
|
public Schedule_context,
|
||||||
public Fifo<Thread>::Element,
|
|
||||||
public Ipc_node,
|
public Ipc_node,
|
||||||
public Irq_receiver
|
public Irq_receiver
|
||||||
{
|
{
|
||||||
@ -84,8 +81,8 @@ namespace Kernel
|
|||||||
unsigned _pd_id; /* ID of the PD this thread runs on */
|
unsigned _pd_id; /* ID of the PD this thread runs on */
|
||||||
Native_utcb * _phys_utcb; /* physical UTCB base */
|
Native_utcb * _phys_utcb; /* physical UTCB base */
|
||||||
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
Native_utcb * _virt_utcb; /* virtual UTCB base */
|
||||||
Signal_receiver * _signal_receiver; /* receiver we are currently
|
Signal_receiver * _signal_receiver;
|
||||||
* listen to */
|
Signal_handler _signal_handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resume execution
|
* Resume execution
|
||||||
@ -112,15 +109,24 @@ namespace Kernel
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
void receive_signal(void * const base, size_t const size)
|
||||||
|
{
|
||||||
|
assert(_state == AWAIT_SIGNAL);
|
||||||
|
assert(size <= phys_utcb()->size())
|
||||||
|
Genode::memcpy(phys_utcb()->base(), base, size);
|
||||||
|
_schedule();
|
||||||
|
}
|
||||||
|
|
||||||
void * operator new (size_t, void * p) { return p; }
|
void * operator new (size_t, void * p) { return p; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Thread(Platform_thread * const platform_thread) :
|
Thread(Platform_thread * const platform_thread)
|
||||||
_platform_thread(platform_thread),
|
:
|
||||||
_state(AWAIT_START), _pager(0), _pd_id(0),
|
_platform_thread(platform_thread), _state(AWAIT_START),
|
||||||
_phys_utcb(0), _virt_utcb(0), _signal_receiver(0)
|
_pager(0), _pd_id(0), _phys_utcb(0), _virt_utcb(0),
|
||||||
|
_signal_receiver(0), _signal_handler((unsigned)this)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -210,11 +216,6 @@ namespace Kernel
|
|||||||
*/
|
*/
|
||||||
void await_signal(Kernel::Signal_receiver * receiver);
|
void await_signal(Kernel::Signal_receiver * receiver);
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets called when we have received a signal at a signal receiver
|
|
||||||
*/
|
|
||||||
void received_signal();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle the exception that currently blocks this thread
|
* Handle the exception that currently blocks this thread
|
||||||
*/
|
*/
|
||||||
@ -241,6 +242,8 @@ namespace Kernel
|
|||||||
unsigned pd_id() const { return _pd_id; }
|
unsigned pd_id() const { return _pd_id; }
|
||||||
|
|
||||||
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
Native_utcb * phys_utcb() const { return _phys_utcb; }
|
||||||
|
|
||||||
|
Signal_handler * signal_handler() { return &_signal_handler; }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user