mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-23 09:15:36 +00:00
committed by
Norman Feske
parent
0f8803245a
commit
438b8be2fa
@ -30,11 +30,60 @@ static Signal_connection * signal_connection()
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
** Signal **
|
||||
************/
|
||||
|
||||
void Signal::_dec_ref_and_unlock()
|
||||
{
|
||||
if (_data.context) {
|
||||
Lock::Guard lock_guard(_data.context->_lock);
|
||||
_data.context->_ref_cnt--;
|
||||
|
||||
/*
|
||||
* We must ack a signal context to receive the next one,
|
||||
* so new signals are received only when ref_cnt = 0.
|
||||
*/
|
||||
if (_data.context->_ref_cnt == 0)
|
||||
Kernel::ack_signal(_data.context->_cap.dst());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Signal::_inc_ref()
|
||||
{
|
||||
if (_data.context) {
|
||||
Lock::Guard lock_guard(_data.context->_lock);
|
||||
_data.context->_ref_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Signal::Signal(Signal::Data data) : _data(data)
|
||||
{
|
||||
/*
|
||||
* We assume that a kernel signal-context doesn't deliver
|
||||
* multiple signals simultaneously.
|
||||
*/
|
||||
if (_data.context) _data.context->_ref_cnt = 1;
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
** Signal transmitter **
|
||||
************************/
|
||||
|
||||
void Signal_transmitter::submit(unsigned cnt)
|
||||
{
|
||||
/* submits to invalid signal contexts get ignored */
|
||||
Kernel::submit_signal(_context.dst(), cnt);
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** Signal_receiver **
|
||||
*********************/
|
||||
|
||||
|
||||
Signal_receiver::Signal_receiver()
|
||||
{
|
||||
/* create a kernel object that corresponds to the receiver */
|
||||
@ -59,16 +108,27 @@ Signal_receiver::Signal_receiver()
|
||||
}
|
||||
|
||||
|
||||
Signal_receiver::~Signal_receiver()
|
||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context * c)
|
||||
{
|
||||
/* dissolve all contexts that are managed by us */
|
||||
Lock::Guard contexts_guard(_contexts_lock);
|
||||
while (1) {
|
||||
Signal_context * const c = _contexts.first();
|
||||
if (!c) break;
|
||||
Lock::Guard context_guard(c->_lock);
|
||||
_unsync_dissolve(c);
|
||||
}
|
||||
/*
|
||||
* We first destroy the kernel object. This also ensures
|
||||
* that no delivered but unacked signals of this context exist
|
||||
* in userland anymore.
|
||||
*/
|
||||
Kernel::kill_signal_context(c->_cap.dst());
|
||||
|
||||
/*
|
||||
* Now we can tell core to regain the memory of the
|
||||
* destructed kernel object.
|
||||
*/
|
||||
signal_connection()->free_context(c->_cap);
|
||||
|
||||
/* reset the context */
|
||||
c->_receiver = 0;
|
||||
c->_cap = Signal_context_capability();
|
||||
|
||||
/* forget the context */
|
||||
_contexts.remove(&c->_receiver_le);
|
||||
}
|
||||
|
||||
|
||||
@ -97,17 +157,40 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||
}
|
||||
/* assign the context to us */
|
||||
c->_receiver = this;
|
||||
_contexts.insert(c);
|
||||
_contexts.insert(&c->_receiver_le);
|
||||
return c->_cap;
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::dissolve(Signal_context *context)
|
||||
{
|
||||
if (context->_receiver != this)
|
||||
throw Context_not_associated();
|
||||
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
|
||||
_unsynchronized_dissolve(context);
|
||||
|
||||
/*
|
||||
* We assume that dissolve is always called before the context destructor.
|
||||
* On other platforms a 'context->_destroy_lock' is locked and unlocked at
|
||||
* this point to block until all remaining signals of this context get
|
||||
* destructed and prevent the context from beeing destructed to early.
|
||||
* However on this platform we don't have to wait because
|
||||
* 'kill_signal_context' in '_unsynchronized_dissolve' already does it.
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
|
||||
|
||||
|
||||
Signal Signal_receiver::wait_for_signal()
|
||||
{
|
||||
/* await a signal */
|
||||
Kernel::await_signal(_cap.dst());
|
||||
Signal s = *(Signal *)Thread_base::myself()->utcb();
|
||||
Signal_context * c = s.context();
|
||||
Signal s(*(Signal::Data *)Thread_base::myself()->utcb());
|
||||
Signal_context * const c = s.context();
|
||||
|
||||
/* check if the context of the signal is managed by us */
|
||||
Lock::Guard context_guard(c->_lock);
|
||||
@ -121,28 +204,6 @@ Signal Signal_receiver::wait_for_signal()
|
||||
}
|
||||
|
||||
|
||||
bool Signal_receiver::pending() { return Kernel::signal_pending(_cap.dst()); }
|
||||
|
||||
|
||||
void Signal_receiver::dissolve(Signal_context * const c)
|
||||
{
|
||||
/* check if the context is managed by us */
|
||||
Lock::Guard contexts_guard(_contexts_lock);
|
||||
Lock::Guard context_guard(c->_lock);
|
||||
if (c->_receiver != this) throw Context_not_associated();
|
||||
|
||||
/* unassign the context */
|
||||
_unsync_dissolve(c);
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::_unsync_dissolve(Signal_context * const c)
|
||||
{
|
||||
/* reset the context */
|
||||
c->_receiver = 0;
|
||||
c->_cap = Signal_context_capability();
|
||||
|
||||
/* forget the context */
|
||||
_contexts.remove(c);
|
||||
}
|
||||
void Signal_receiver::local_submit(Signal::Data signal) {
|
||||
PDBG("Not implemented"); };
|
||||
|
||||
|
@ -61,6 +61,7 @@ namespace Genode
|
||||
Signal_context_capability
|
||||
alloc_context(Signal_receiver_capability const r,
|
||||
unsigned const imprint);
|
||||
void free_context(Signal_context_capability context_cap);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -487,9 +487,9 @@ void Kernel::Thread::await_signal()
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::receive_signal(Signal const s)
|
||||
void Kernel::Thread::received_signal()
|
||||
{
|
||||
*(Signal *)phys_utcb()->base() = s;
|
||||
assert(_state == AWAIT_IRQ);
|
||||
_activate();
|
||||
}
|
||||
|
||||
@ -554,25 +554,52 @@ namespace Kernel
|
||||
{
|
||||
friend class Signal_receiver;
|
||||
|
||||
Signal_receiver * const _receiver; /* the receiver that owns us */
|
||||
unsigned const _imprint; /* every of our signals gets signed with */
|
||||
unsigned _number; /* how often we got triggered */
|
||||
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();
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Signal_context(Signal_receiver * const r,
|
||||
unsigned const imprint)
|
||||
: _receiver(r), _imprint(imprint), _number(0) { }
|
||||
Signal_context(Signal_receiver * const r, unsigned const imprint) :
|
||||
_receiver(r), _imprint(imprint),
|
||||
_submits(0), _await_ack(0), _killer(0) { }
|
||||
|
||||
/**
|
||||
* Trigger this context
|
||||
* Submit the signal
|
||||
*
|
||||
* \param number how often this call triggers us at once
|
||||
* \param n number of submits
|
||||
*/
|
||||
void trigger_signal(unsigned const number);
|
||||
void submit(unsigned const n);
|
||||
|
||||
/**
|
||||
* Acknowledge delivery of signal
|
||||
*/
|
||||
void ack();
|
||||
|
||||
/**
|
||||
* Destruct or prepare to do it at next call of 'ack'
|
||||
*/
|
||||
void kill(Thread * const killer)
|
||||
{
|
||||
assert(!_killer);
|
||||
_killer = killer;
|
||||
if (_await_ack) {
|
||||
_killer->kill_signal_context_blocks();
|
||||
return;
|
||||
}
|
||||
this->~Signal_context();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -602,10 +629,13 @@ namespace Kernel
|
||||
}
|
||||
/* awake a listener and transmit signal info to it */
|
||||
Thread * const t = _listeners.dequeue();
|
||||
t->receive_signal(Signal(c->_imprint, c->_number));
|
||||
Signal::Data data((Genode::Signal_context *)c->_imprint,
|
||||
c->_submits);
|
||||
*(Signal::Data *)t->phys_utcb()->base() = data;
|
||||
t->received_signal();
|
||||
|
||||
/* reset context */
|
||||
c->_number = 0;
|
||||
c->_submits = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -627,12 +657,12 @@ namespace Kernel
|
||||
bool pending() { return !_pending_contexts.empty(); }
|
||||
|
||||
/**
|
||||
* Recognize that one of our contexts was triggered
|
||||
* Recognize that 'c' wants to deliver
|
||||
*/
|
||||
void add_pending_context(Signal_context * const c)
|
||||
void deliver(Signal_context * const c)
|
||||
{
|
||||
assert(c->_receiver == this);
|
||||
if(!c->is_enqueued()) _pending_contexts.enqueue(c);
|
||||
if (!c->is_enqueued()) _pending_contexts.enqueue(c);
|
||||
_listen();
|
||||
}
|
||||
};
|
||||
@ -674,7 +704,7 @@ namespace Kernel
|
||||
return;
|
||||
default:
|
||||
cpu_scheduler()->remove(this);
|
||||
_context->trigger_signal(1);
|
||||
_context->submit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1193,13 +1223,38 @@ namespace Kernel
|
||||
/* lookup context */
|
||||
Signal_context * const c =
|
||||
Signal_context::pool()->object(user->user_arg_1());
|
||||
assert(c);
|
||||
|
||||
if(!c) {
|
||||
PDBG("invalid signal-context capability");
|
||||
return;
|
||||
}
|
||||
/* trigger signal at context */
|
||||
c->trigger_signal(user->user_arg_2());
|
||||
c->submit(user->user_arg_2());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do specific syscall for 'user', for details see 'syscall.h'
|
||||
*/
|
||||
void do_ack_signal(Thread * const user)
|
||||
{
|
||||
Signal_context * const c =
|
||||
Signal_context::pool()->object(user->user_arg_1());
|
||||
assert(c);
|
||||
c->ack();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Do specific syscall for 'user', for details see 'syscall.h'
|
||||
*/
|
||||
void do_kill_signal_context(Thread * const user)
|
||||
{
|
||||
Signal_context * const c =
|
||||
Signal_context::pool()->object(user->user_arg_1());
|
||||
assert(c);
|
||||
c->kill(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do specific syscall for 'user', for details see 'syscall.h'
|
||||
*/
|
||||
@ -1283,6 +1338,8 @@ namespace Kernel
|
||||
/* 26 */ do_delete_thread,
|
||||
/* 27 */ do_signal_pending,
|
||||
/* 28 */ do_resume_faulter,
|
||||
/* 29 */ do_ack_signal,
|
||||
/* 30 */ do_kill_signal_context,
|
||||
};
|
||||
enum { MAX_SYSCALL = sizeof(handle_sysc)/sizeof(handle_sysc[0]) - 1 };
|
||||
|
||||
@ -1385,8 +1442,7 @@ int Thread::start(void *ip, void *sp, unsigned cpu_no,
|
||||
user_arg_0((unsigned)_virt_utcb);
|
||||
|
||||
/* start thread */
|
||||
cpu_scheduler()->insert(this);
|
||||
_state = ACTIVE;
|
||||
_activate();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1420,19 +1476,50 @@ void Thread::pagefault(addr_t const va, bool const w)
|
||||
}
|
||||
|
||||
|
||||
void Thread::kill_signal_context_blocks()
|
||||
{
|
||||
cpu_scheduler()->remove(this);
|
||||
_state = KILL_SIGNAL_CONTEXT_BLOCKS;
|
||||
}
|
||||
|
||||
|
||||
void Thread::kill_signal_context_done()
|
||||
{
|
||||
assert(_state == KILL_SIGNAL_CONTEXT_BLOCKS)
|
||||
_activate();
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
** Kernel::Signal_context **
|
||||
****************************/
|
||||
|
||||
|
||||
void Signal_context::trigger_signal(unsigned const number)
|
||||
void Signal_context::_deliver()
|
||||
{
|
||||
/* raise our number */
|
||||
unsigned const old_nr = _number;
|
||||
_number += number;
|
||||
assert(old_nr <= _number);
|
||||
|
||||
/* notify our receiver */
|
||||
if (_number) _receiver->add_pending_context(this);
|
||||
if (!_submits) return;
|
||||
_receiver->deliver(this);
|
||||
_await_ack = 1;
|
||||
}
|
||||
|
||||
|
||||
void Signal_context::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 < -1 - n);
|
||||
if (_killer) return;
|
||||
_submits += n;
|
||||
if (_await_ack) return;
|
||||
_deliver();
|
||||
}
|
||||
|
||||
|
@ -775,7 +775,7 @@ namespace Kernel
|
||||
public Irq_owner
|
||||
{
|
||||
enum State { STOPPED, ACTIVE, AWAIT_IPC, AWAIT_RESUMPTION,
|
||||
AWAIT_IRQ, AWAIT_SIGNAL };
|
||||
AWAIT_IRQ, AWAIT_SIGNAL, KILL_SIGNAL_CONTEXT_BLOCKS };
|
||||
|
||||
Platform_thread * const _platform_thread; /* userland object wich
|
||||
* addresses this thread */
|
||||
@ -897,7 +897,7 @@ namespace Kernel
|
||||
/**
|
||||
* Gets called when we have received a signal at a signal receiver
|
||||
*/
|
||||
void receive_signal(Signal const s);
|
||||
void received_signal();
|
||||
|
||||
/**
|
||||
* Handle the exception that currently blocks this thread
|
||||
@ -909,6 +909,9 @@ namespace Kernel
|
||||
*/
|
||||
void scheduled_next();
|
||||
|
||||
void kill_signal_context_blocks();
|
||||
|
||||
void kill_signal_context_done();
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
|
@ -77,3 +77,9 @@ Signal_session_component::alloc_context(Signal_receiver_capability r,
|
||||
return reinterpret_cap_cast<Signal_context>(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME should regain the kernel-object memory from kernel
|
||||
*/
|
||||
void Signal_session_component::free_context(Signal_context_capability cap) {
|
||||
PDBG("Not implemented"); }
|
||||
|
||||
|
Reference in New Issue
Block a user