2012-05-30 20:13:09 +02:00
|
|
|
/*
|
|
|
|
* \brief Implementations of the signaling framework specific for HW-core
|
|
|
|
* \author Martin Stein
|
|
|
|
* \date 2012-05-05
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2013-01-10 21:44:47 +01:00
|
|
|
* Copyright (C) 2012-2013 Genode Labs GmbH
|
2012-05-30 20:13:09 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
|
|
* under the terms of the GNU General Public License version 2.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/thread.h>
|
|
|
|
#include <base/signal.h>
|
|
|
|
#include <signal_session/connection.h>
|
2013-11-14 17:29:34 +01:00
|
|
|
|
|
|
|
/* base-hw includes */
|
|
|
|
#include <kernel/interface.h>
|
2012-05-30 20:13:09 +02:00
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2013-09-12 21:13:22 +02:00
|
|
|
* Provide one signal connection per program
|
2012-05-30 20:13:09 +02:00
|
|
|
*/
|
|
|
|
static Signal_connection * signal_connection()
|
|
|
|
{
|
|
|
|
static Signal_connection _object;
|
|
|
|
return &_object;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-18 13:58:09 +01:00
|
|
|
/************
|
|
|
|
** Signal **
|
|
|
|
************/
|
|
|
|
|
|
|
|
void Signal::_dec_ref_and_unlock()
|
|
|
|
{
|
|
|
|
if (_data.context) {
|
|
|
|
Lock::Guard lock_guard(_data.context->_lock);
|
|
|
|
_data.context->_ref_cnt--;
|
|
|
|
|
2013-09-12 21:13:22 +02:00
|
|
|
/* acknowledge as soon as receipt is fully processed */
|
|
|
|
if (_data.context->_ref_cnt == 0) {
|
2013-02-18 13:58:09 +01:00
|
|
|
Kernel::ack_signal(_data.context->_cap.dst());
|
2013-09-12 21:13:22 +02:00
|
|
|
}
|
2013-02-18 13:58:09 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2013-09-12 21:13:22 +02:00
|
|
|
if (_data.context) { _data.context->_ref_cnt = 1; }
|
2013-02-18 13:58:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-27 14:47:58 +01:00
|
|
|
/********************
|
|
|
|
** Signal context **
|
|
|
|
********************/
|
|
|
|
|
|
|
|
void Signal_context::submit(unsigned num)
|
|
|
|
{
|
|
|
|
Kernel::submit_signal(_cap.dst(), num);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-02-18 13:58:09 +01:00
|
|
|
/************************
|
|
|
|
** Signal transmitter **
|
|
|
|
************************/
|
|
|
|
|
2015-03-17 11:51:00 +01:00
|
|
|
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
2013-02-18 13:58:09 +01:00
|
|
|
|
|
|
|
|
2015-06-22 14:04:28 +02:00
|
|
|
void Signal_transmitter::submit(unsigned cnt)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Trace::Signal_submit trace_event(cnt);
|
|
|
|
}
|
|
|
|
Kernel::submit_signal(_context.dst(), cnt);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
/*********************
|
|
|
|
** Signal_receiver **
|
|
|
|
*********************/
|
|
|
|
|
2012-11-23 16:47:42 +01:00
|
|
|
Signal_receiver::Signal_receiver()
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2012-11-23 16:47:42 +01:00
|
|
|
/* create a kernel object that corresponds to the receiver */
|
|
|
|
bool session_upgraded = 0;
|
|
|
|
Signal_connection * const s = signal_connection();
|
|
|
|
while (1) {
|
|
|
|
try {
|
|
|
|
_cap = s->alloc_receiver();
|
2013-08-08 20:18:41 +02:00
|
|
|
return;
|
2012-11-23 16:47:42 +01:00
|
|
|
} catch (Signal_session::Out_of_metadata)
|
|
|
|
{
|
|
|
|
/* upgrade session quota and try again, but only once */
|
|
|
|
if (session_upgraded) {
|
2013-08-08 20:18:41 +02:00
|
|
|
PERR("failed to alloc signal receiver");
|
|
|
|
_cap = Signal_receiver_capability();
|
|
|
|
return;
|
2012-11-23 16:47:42 +01:00
|
|
|
}
|
2013-08-08 20:18:41 +02:00
|
|
|
PINF("upgrading quota donation for SIGNAL session");
|
2015-05-19 14:18:40 +02:00
|
|
|
env()->parent()->upgrade(s->cap(), "ram_quota=8K");
|
2012-11-23 16:47:42 +01:00
|
|
|
session_upgraded = 1;
|
|
|
|
}
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
void Signal_receiver::_platform_destructor()
|
|
|
|
{
|
|
|
|
/* release server resources of receiver */
|
|
|
|
signal_connection()->free_receiver(_cap);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-12 21:13:22 +02:00
|
|
|
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c)
|
2012-05-30 20:13:09 +02:00
|
|
|
{
|
2013-12-06 00:12:43 +01:00
|
|
|
/* wait untill all context references disappear and put context to sleep */
|
|
|
|
Kernel::kill_signal_context(c->_cap.dst());
|
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
/* release server resources of context */
|
2013-02-18 13:58:09 +01:00
|
|
|
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);
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
|
|
|
{
|
2013-11-14 13:29:47 +01:00
|
|
|
/* ensure that the context isn't managed already */
|
2012-05-30 20:13:09 +02:00
|
|
|
Lock::Guard contexts_guard(_contexts_lock);
|
|
|
|
Lock::Guard context_guard(c->_lock);
|
2013-09-12 00:48:27 +02:00
|
|
|
if (c->_receiver) { throw Context_already_in_use(); }
|
2012-05-30 20:13:09 +02:00
|
|
|
|
2013-11-14 13:29:47 +01:00
|
|
|
/* create a context kernel-object at the receiver kernel-object */
|
2012-05-30 20:13:09 +02:00
|
|
|
bool session_upgraded = 0;
|
|
|
|
Signal_connection * const s = signal_connection();
|
|
|
|
while (1) {
|
|
|
|
try {
|
2015-02-06 17:23:41 +01:00
|
|
|
c->_cap = s->alloc_context(_cap, (unsigned long)c);
|
2013-08-08 20:18:41 +02:00
|
|
|
c->_receiver = this;
|
|
|
|
_contexts.insert(&c->_receiver_le);
|
|
|
|
return c->_cap;
|
2012-05-30 20:13:09 +02:00
|
|
|
} catch (Signal_session::Out_of_metadata)
|
|
|
|
{
|
|
|
|
/* upgrade session quota and try again, but only once */
|
2013-08-08 20:18:41 +02:00
|
|
|
if (session_upgraded) {
|
|
|
|
PERR("failed to alloc signal context");
|
|
|
|
return Signal_context_capability();
|
|
|
|
}
|
2013-11-14 13:29:47 +01:00
|
|
|
PINF("upgrading quota donation for signal session");
|
2015-05-19 14:18:40 +02:00
|
|
|
env()->parent()->upgrade(s->cap(), "ram_quota=8K");
|
2012-05-30 20:13:09 +02:00
|
|
|
session_upgraded = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
void Signal_receiver::dissolve(Signal_context * const context)
|
2013-02-18 13:58:09 +01:00
|
|
|
{
|
2013-09-12 00:48:27 +02:00
|
|
|
if (context->_receiver != this) { throw Context_not_associated(); }
|
2013-02-18 13:58:09 +01:00
|
|
|
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()); }
|
|
|
|
|
|
|
|
|
2012-05-30 20:13:09 +02:00
|
|
|
Signal Signal_receiver::wait_for_signal()
|
|
|
|
{
|
|
|
|
/* await a signal */
|
2015-03-17 15:41:47 +01:00
|
|
|
if (Kernel::await_signal(_cap.dst())) {
|
2013-09-12 00:48:27 +02:00
|
|
|
PERR("failed to receive signal");
|
2013-10-14 10:57:02 +02:00
|
|
|
return Signal(Signal::Data());
|
2012-05-30 20:13:09 +02:00
|
|
|
}
|
2015-05-19 14:18:40 +02:00
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
/* get signal data */
|
2015-05-19 14:18:40 +02:00
|
|
|
Signal s(*(Signal::Data *)Thread_base::myself()->utcb()->base());
|
2012-05-30 20:13:09 +02:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-12 00:48:27 +02:00
|
|
|
void Signal_receiver::local_submit(Signal::Data signal)
|
|
|
|
{
|
2013-11-27 14:47:58 +01:00
|
|
|
PERR("not implemented");
|
2013-09-12 00:48:27 +02:00
|
|
|
}
|