mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 09:46:20 +00:00
base-hw: use signal context list for pending signals
'block_for_signal' and 'pending_signal' now set pending flag in signal context in order to determine pending signal. The context list is also used by the 'Signal_receiver' during destruction. Fixes #1738
This commit is contained in:
parent
18d24eec7b
commit
0c3dfbad65
@ -37,12 +37,11 @@ namespace Kernel
|
||||
constexpr Call_arg call_id_kill_signal_context() { return 6; }
|
||||
constexpr Call_arg call_id_submit_signal() { return 7; }
|
||||
constexpr Call_arg call_id_await_signal() { return 8; }
|
||||
constexpr Call_arg call_id_signal_pending() { return 9; }
|
||||
constexpr Call_arg call_id_ack_signal() { return 10; }
|
||||
constexpr Call_arg call_id_print_char() { return 11; }
|
||||
constexpr Call_arg call_id_update_data_region() { return 12; }
|
||||
constexpr Call_arg call_id_update_instr_region() { return 13; }
|
||||
constexpr Call_arg call_id_delete_cap() { return 14; }
|
||||
constexpr Call_arg call_id_ack_signal() { return 9; }
|
||||
constexpr Call_arg call_id_print_char() { return 10; }
|
||||
constexpr Call_arg call_id_update_data_region() { return 11; }
|
||||
constexpr Call_arg call_id_update_instr_region() { return 12; }
|
||||
constexpr Call_arg call_id_delete_cap() { return 13; }
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
@ -228,20 +227,6 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return wether any context of a receiver is pending
|
||||
*
|
||||
* \param receiver capability id of the targeted signal receiver
|
||||
*
|
||||
* \retval 0 none of the contexts is pending or the receiver doesn't exist
|
||||
* \retval 1 a context of the signal receiver is pending
|
||||
*/
|
||||
inline bool signal_pending(capid_t const receiver)
|
||||
{
|
||||
return call(call_id_signal_pending(), receiver);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Trigger a specific signal context
|
||||
*
|
||||
|
@ -21,67 +21,16 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/**
|
||||
* Provide one signal connection per program
|
||||
*/
|
||||
static Signal_connection * signal_connection()
|
||||
{
|
||||
static Signal_connection _object;
|
||||
return &_object;
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
** Signal **
|
||||
************/
|
||||
|
||||
void Signal::_dec_ref_and_unlock()
|
||||
{
|
||||
if (_data.context) {
|
||||
Lock::Guard lock_guard(_data.context->_lock);
|
||||
_data.context->_ref_cnt--;
|
||||
|
||||
/* acknowledge as soon as receipt is fully processed */
|
||||
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)
|
||||
{
|
||||
if (_data.context) { _data.context->_ref_cnt = 1; }
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Signal context **
|
||||
********************/
|
||||
|
||||
void Signal_context::submit(unsigned num)
|
||||
{
|
||||
Kernel::submit_signal(_cap.dst(), num);
|
||||
}
|
||||
|
||||
void Signal_context::submit(unsigned) { PERR("not implemented"); }
|
||||
|
||||
/************************
|
||||
** Signal transmitter **
|
||||
************************/
|
||||
|
||||
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
||||
|
||||
|
||||
void Signal_transmitter::submit(unsigned cnt)
|
||||
{
|
||||
{
|
||||
@ -127,22 +76,13 @@ void Signal_receiver::_platform_destructor()
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const c)
|
||||
void Signal_receiver::_platform_begin_dissolve(Signal_context * const c)
|
||||
{
|
||||
/* wait untill all context references disappear and put context to sleep */
|
||||
Kernel::kill_signal_context(c->_cap.dst());
|
||||
|
||||
/* release server resources of context */
|
||||
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);
|
||||
}
|
||||
|
||||
void Signal_receiver::_platform_finish_dissolve(Signal_context *) { }
|
||||
|
||||
|
||||
Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||
{
|
||||
@ -175,76 +115,27 @@ Signal_context_capability Signal_receiver::manage(Signal_context * const c)
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::dissolve(Signal_context * const 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()); }
|
||||
|
||||
|
||||
/*
|
||||
* Last signal received by 'block_for_signal'
|
||||
*/
|
||||
void Signal_receiver::block_for_signal()
|
||||
{
|
||||
/* await a signal */
|
||||
/* wait for a signal */
|
||||
if (Kernel::await_signal(_cap.dst())) {
|
||||
PERR("failed to receive signal");
|
||||
return;
|
||||
}
|
||||
|
||||
/* get signal */
|
||||
Signal::Data *data = (Signal::Data *)Thread_base::myself()->utcb()->base();
|
||||
Signal s(*data);
|
||||
|
||||
/* save signal data in context list */
|
||||
s.context()->_curr_signal = *data;
|
||||
_contexts.insert(&s.context()->_receiver_le);
|
||||
}
|
||||
|
||||
|
||||
Signal Signal_receiver::pending_signal()
|
||||
{
|
||||
List_element<Signal_context> *le = _contexts.first();
|
||||
if (!le)
|
||||
throw Signal_not_pending();
|
||||
|
||||
/* remove from context list */
|
||||
Signal_context *context = le->object();
|
||||
_contexts.remove(le);
|
||||
|
||||
return Signal(context->_curr_signal);
|
||||
}
|
||||
|
||||
|
||||
Signal Signal_receiver::wait_for_signal()
|
||||
{
|
||||
/* await a signal */
|
||||
if (Kernel::await_signal(_cap.dst())) {
|
||||
PERR("failed to receive signal");
|
||||
return Signal(Signal::Data());
|
||||
/* read signal data */
|
||||
const void * const utcb = Thread_base::myself()->utcb()->base();
|
||||
Signal::Data * const data = (Signal::Data *)utcb;
|
||||
Signal_context * const context = data->context;
|
||||
{
|
||||
/* update signal context */
|
||||
Lock::Guard lock_guard(context->_lock);
|
||||
unsigned const num = context->_curr_signal.num + data->num;
|
||||
context->_pending = true;
|
||||
context->_curr_signal = Signal::Data(context, num);
|
||||
}
|
||||
|
||||
/* get signal data */
|
||||
Signal s(*(Signal::Data *)Thread_base::myself()->utcb()->base());
|
||||
return s;
|
||||
/* end kernel-aided life-time management */
|
||||
Kernel::ack_signal(data->context->_cap.dst());
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::local_submit(Signal::Data signal)
|
||||
{
|
||||
PERR("not implemented");
|
||||
}
|
||||
void Signal_receiver::local_submit(Signal::Data) { PERR("not implemented"); }
|
||||
|
@ -339,11 +339,6 @@ class Kernel::Signal_receiver : public Kernel::Object
|
||||
*/
|
||||
int add_handler(Signal_handler * const h);
|
||||
|
||||
/**
|
||||
* Return wether any of the contexts of this receiver is deliverable
|
||||
*/
|
||||
bool deliverable();
|
||||
|
||||
/**
|
||||
* Syscall to create a signal receiver
|
||||
*
|
||||
|
@ -232,7 +232,6 @@ class Kernel::Thread
|
||||
void _call_update_instr_region();
|
||||
void _call_print_char();
|
||||
void _call_await_signal();
|
||||
void _call_signal_pending();
|
||||
void _call_submit_signal();
|
||||
void _call_ack_signal();
|
||||
void _call_kill_signal_context();
|
||||
|
@ -223,9 +223,6 @@ int Signal_receiver::add_handler(Signal_handler * const h)
|
||||
}
|
||||
|
||||
|
||||
bool Signal_receiver::deliverable() { return !_deliver.empty(); }
|
||||
|
||||
|
||||
Signal_receiver::~Signal_receiver()
|
||||
{
|
||||
/* destruct all attached contexts */
|
||||
|
@ -483,21 +483,6 @@ void Thread::_call_await_signal()
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_signal_pending()
|
||||
{
|
||||
/* lookup signal receiver */
|
||||
Signal_receiver * const r = pd()->cap_tree().find<Signal_receiver>(user_arg_1());
|
||||
if (!r) {
|
||||
PWRN("%s -> %s: no pending, unknown signal receiver",
|
||||
pd_label(), label());
|
||||
user_arg_0(0);
|
||||
return;
|
||||
}
|
||||
/* get pending state */
|
||||
user_arg_0(r->deliverable());
|
||||
}
|
||||
|
||||
|
||||
void Thread::_call_submit_signal()
|
||||
{
|
||||
/* lookup signal context */
|
||||
@ -625,7 +610,6 @@ void Thread::_call()
|
||||
case call_id_kill_signal_context(): _call_kill_signal_context(); return;
|
||||
case call_id_submit_signal(): _call_submit_signal(); return;
|
||||
case call_id_await_signal(): _call_await_signal(); return;
|
||||
case call_id_signal_pending(): _call_signal_pending(); return;
|
||||
case call_id_ack_signal(): _call_ack_signal(); return;
|
||||
case call_id_print_char(): _call_print_char(); return;
|
||||
case call_id_delete_cap(): _call_delete_cap(); return;
|
||||
|
@ -36,6 +36,7 @@ namespace Genode {
|
||||
class Signal_dispatcher_base;
|
||||
class Signal_connection;
|
||||
template <typename> class Signal_dispatcher;
|
||||
Signal_connection * signal_connection();
|
||||
}
|
||||
|
||||
|
||||
@ -200,6 +201,12 @@ class Genode::Signal_receiver : Noncopyable
|
||||
*/
|
||||
void _platform_destructor();
|
||||
|
||||
/**
|
||||
* Hooks to platform specific dissolve parts
|
||||
*/
|
||||
void _platform_begin_dissolve(Signal_context * const c);
|
||||
void _platform_finish_dissolve(Signal_context * const c);
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
|
@ -15,9 +15,19 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/signal.h>
|
||||
#include <signal_session/connection.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/**
|
||||
* Return process-wide signal session
|
||||
*/
|
||||
Signal_connection * Genode::signal_connection()
|
||||
{
|
||||
static Signal_connection sc;
|
||||
return ≻
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
** Signal **
|
||||
@ -52,6 +62,35 @@ Signal & Signal::operator=(Signal const &other)
|
||||
Signal::~Signal() { _dec_ref_and_unlock(); }
|
||||
|
||||
|
||||
void Signal::_dec_ref_and_unlock()
|
||||
{
|
||||
if (_data.context) {
|
||||
Lock::Guard lock_guard(_data.context->_lock);
|
||||
_data.context->_ref_cnt--;
|
||||
if (_data.context->_ref_cnt == 0)
|
||||
_data.context->_destroy_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (_data.context) {
|
||||
_data.context->_ref_cnt = 1;
|
||||
_data.context->_destroy_lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Signal_context **
|
||||
********************/
|
||||
@ -71,6 +110,9 @@ Signal_context::~Signal_context()
|
||||
** Signal_transmitter **
|
||||
************************/
|
||||
|
||||
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
||||
|
||||
|
||||
Signal_transmitter::Signal_transmitter(Signal_context_capability context)
|
||||
: _context(context) { }
|
||||
|
||||
@ -85,6 +127,63 @@ Signal_context_capability Signal_transmitter::context() { return _context; }
|
||||
** Signal_receiver **
|
||||
*********************/
|
||||
|
||||
Signal Signal_receiver::wait_for_signal()
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
/* block until the receiver has received a signal */
|
||||
block_for_signal();
|
||||
|
||||
try {
|
||||
return pending_signal();
|
||||
} catch (Signal_not_pending) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Signal Signal_receiver::pending_signal()
|
||||
{
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
|
||||
/* look up the contexts for the pending signal */
|
||||
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
||||
|
||||
Signal_context *context = le->object();
|
||||
|
||||
Lock::Guard lock_guard(context->_lock);
|
||||
|
||||
/* check if context has a pending signal */
|
||||
if (!context->_pending)
|
||||
continue;
|
||||
|
||||
context->_pending = false;
|
||||
Signal::Data result = context->_curr_signal;
|
||||
|
||||
/* invalidate current signal in context */
|
||||
context->_curr_signal = Signal::Data(0, 0);
|
||||
|
||||
if (result.num == 0)
|
||||
PWRN("returning signal with num == 0");
|
||||
|
||||
Trace::Signal_received trace_event(*context, result.num);
|
||||
|
||||
/* return last received signal */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Normally, we should never arrive at this point because that would
|
||||
* mean, the '_signal_available' semaphore was increased without
|
||||
* registering the signal in any context associated to the receiver.
|
||||
*
|
||||
* However, if a context gets dissolved right after submitting a
|
||||
* signal, we may have increased the semaphore already. In this case
|
||||
* the signal-causing context is absent from the list.
|
||||
*/
|
||||
throw Signal_not_pending();
|
||||
}
|
||||
|
||||
|
||||
Signal_receiver::~Signal_receiver()
|
||||
{
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
@ -95,3 +194,53 @@ Signal_receiver::~Signal_receiver()
|
||||
|
||||
_platform_destructor();
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context * const context)
|
||||
{
|
||||
_platform_begin_dissolve(context);
|
||||
|
||||
/* tell core to stop sending signals referring to the context */
|
||||
signal_connection()->free_context(context->_cap);
|
||||
|
||||
/* restore default initialization of signal context */
|
||||
context->_receiver = 0;
|
||||
context->_cap = Signal_context_capability();
|
||||
|
||||
/* remove context from context list */
|
||||
_contexts.remove(&context->_receiver_le);
|
||||
|
||||
_platform_finish_dissolve(context);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
Lock::Guard context_destroy_lock_guard(context->_destroy_lock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool Signal_receiver::pending()
|
||||
{
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
|
||||
/* look up the contexts for the pending signal */
|
||||
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
||||
|
||||
Signal_context *context = le->object();
|
||||
|
||||
Lock::Guard lock_guard(context->_lock);
|
||||
|
||||
if (context->_pending)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -18,21 +18,6 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/**
|
||||
* Return process-wide signal session used for signal allocation and submission
|
||||
*/
|
||||
static Signal_connection *signal_connection()
|
||||
{
|
||||
static Signal_connection sc;
|
||||
return ≻
|
||||
}
|
||||
|
||||
|
||||
/******************************************************
|
||||
** Process-wide connection to core's signal service **
|
||||
******************************************************/
|
||||
|
||||
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
|
||||
|
||||
class Signal_handler_thread : Thread<STACK_SIZE>, Lock
|
||||
@ -166,39 +151,6 @@ Genode::Signal_context_registry *signal_context_registry()
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
** Signal **
|
||||
************/
|
||||
|
||||
void Signal::_dec_ref_and_unlock()
|
||||
{
|
||||
if (_data.context) {
|
||||
Lock::Guard lock_guard(_data.context->_lock);
|
||||
_data.context->_ref_cnt--;
|
||||
if (_data.context->_ref_cnt == 0)
|
||||
_data.context->_destroy_lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
if (_data.context) {
|
||||
_data.context->_ref_cnt = 1;
|
||||
_data.context->_destroy_lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Signal context **
|
||||
********************/
|
||||
@ -224,33 +176,10 @@ void Signal_context::submit(unsigned num)
|
||||
}
|
||||
|
||||
|
||||
/************************
|
||||
** Signal transmitter **
|
||||
************************/
|
||||
|
||||
Signal_connection * Signal_transmitter::connection() { return signal_connection(); }
|
||||
|
||||
|
||||
/*********************
|
||||
** Signal receiver **
|
||||
*********************/
|
||||
|
||||
void Signal_receiver::_unsynchronized_dissolve(Signal_context *context)
|
||||
{
|
||||
/* tell core to stop sending signals referring to the context */
|
||||
signal_connection()->free_context(context->_cap);
|
||||
|
||||
/* restore default initialization of signal context */
|
||||
context->_receiver = 0;
|
||||
context->_cap = Signal_context_capability();
|
||||
|
||||
/* remove context from context list */
|
||||
_contexts.remove(&context->_receiver_le);
|
||||
|
||||
/* unregister context from process-wide registry */
|
||||
signal_context_registry()->remove(&context->_registry_le);
|
||||
}
|
||||
|
||||
|
||||
Signal_receiver::Signal_receiver()
|
||||
{
|
||||
@ -301,100 +230,12 @@ Signal_context_capability Signal_receiver::manage(Signal_context *context)
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
Lock::Guard context_destroy_lock_guard(context->_destroy_lock);
|
||||
}
|
||||
|
||||
|
||||
bool Signal_receiver::pending()
|
||||
{
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
|
||||
/* look up the contexts for the pending signal */
|
||||
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
||||
|
||||
Signal_context *context = le->object();
|
||||
|
||||
Lock::Guard lock_guard(context->_lock);
|
||||
|
||||
if (context->_pending)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Signal Signal_receiver::pending_signal()
|
||||
{
|
||||
Lock::Guard list_lock_guard(_contexts_lock);
|
||||
|
||||
/* look up the contexts for the pending signal */
|
||||
for (List_element<Signal_context> *le = _contexts.first(); le; le = le->next()) {
|
||||
|
||||
Signal_context *context = le->object();
|
||||
|
||||
Lock::Guard lock_guard(context->_lock);
|
||||
|
||||
/* check if context has a pending signal */
|
||||
if (!context->_pending)
|
||||
continue;
|
||||
|
||||
context->_pending = false;
|
||||
Signal::Data result = context->_curr_signal;
|
||||
|
||||
/* invalidate current signal in context */
|
||||
context->_curr_signal = Signal::Data(0, 0);
|
||||
|
||||
if (result.num == 0)
|
||||
PWRN("returning signal with num == 0");
|
||||
|
||||
Trace::Signal_received trace_event(*context, result.num);
|
||||
|
||||
/* return last received signal */
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Normally, we should never arrive at this point because that would
|
||||
* mean, the '_signal_available' semaphore was increased without
|
||||
* registering the signal in any context associated to the receiver.
|
||||
*
|
||||
* However, if a context gets dissolved right after submitting a
|
||||
* signal, we may have increased the semaphore already. In this case
|
||||
* the signal-causing context is absent from the list.
|
||||
*/
|
||||
throw Signal_not_pending();
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::block_for_signal()
|
||||
{
|
||||
_signal_available.down();
|
||||
}
|
||||
|
||||
|
||||
Signal Signal_receiver::wait_for_signal()
|
||||
{
|
||||
for (;;) {
|
||||
|
||||
/* block until the receiver has received a signal */
|
||||
block_for_signal();
|
||||
|
||||
try {
|
||||
return pending_signal();
|
||||
} catch (Signal_not_pending) { }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Signal_receiver::local_submit(Signal::Data ns)
|
||||
{
|
||||
Signal_context *context = ns.context;
|
||||
@ -437,5 +278,9 @@ void Signal_receiver::dispatch_signals(Signal_source *signal_source)
|
||||
}
|
||||
}
|
||||
|
||||
void Signal_receiver::_platform_begin_dissolve(Signal_context *) { }
|
||||
|
||||
void Signal_receiver::_platform_finish_dissolve(Signal_context * const c) {
|
||||
signal_context_registry()->remove(&c->_registry_le); }
|
||||
|
||||
void Signal_receiver::_platform_destructor() { }
|
||||
|
Loading…
x
Reference in New Issue
Block a user