mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-30 16:14:13 +00:00
parent
e33d65aea0
commit
1d99e7ede9
@ -51,16 +51,7 @@ class Genode::Entrypoint : Genode::Noncopyable
|
|||||||
Entrypoint &ep;
|
Entrypoint &ep;
|
||||||
Signal_proxy_component(Entrypoint &ep) : ep(ep) { }
|
Signal_proxy_component(Entrypoint &ep) : ep(ep) { }
|
||||||
|
|
||||||
void signal()
|
void signal();
|
||||||
{
|
|
||||||
/* XXX introduce while-pending loop */
|
|
||||||
try {
|
|
||||||
Signal sig = ep._sig_rec->pending_signal();
|
|
||||||
ep._dispatch_signal(sig);
|
|
||||||
} catch (Signal_receiver::Signal_not_pending) { }
|
|
||||||
|
|
||||||
ep._execute_post_signal_hook();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Signal_proxy_thread : Thread
|
struct Signal_proxy_thread : Thread
|
||||||
@ -85,6 +76,12 @@ class Genode::Entrypoint : Genode::Noncopyable
|
|||||||
|
|
||||||
Reconstructible<Signal_receiver> _sig_rec;
|
Reconstructible<Signal_receiver> _sig_rec;
|
||||||
|
|
||||||
|
Lock _deferred_signals_mutex;
|
||||||
|
List<List_element<Signal_context>> _deferred_signals;
|
||||||
|
|
||||||
|
void _handle_deferred_signals() { }
|
||||||
|
Constructible<Signal_handler<Entrypoint>> _deferred_signal_handler;
|
||||||
|
|
||||||
bool _suspended = false;
|
bool _suspended = false;
|
||||||
void (*_suspended_callback) () = nullptr;
|
void (*_suspended_callback) () = nullptr;
|
||||||
void (*_resumed_callback) () = nullptr;
|
void (*_resumed_callback) () = nullptr;
|
||||||
@ -116,7 +113,8 @@ class Genode::Entrypoint : Genode::Noncopyable
|
|||||||
Constructible<Genode::Signal_handler<Entrypoint>> _suspend_dispatcher;
|
Constructible<Genode::Signal_handler<Entrypoint>> _suspend_dispatcher;
|
||||||
|
|
||||||
void _dispatch_signal(Signal &sig);
|
void _dispatch_signal(Signal &sig);
|
||||||
|
void _defer_signal(Signal &sig);
|
||||||
|
void _process_deferred_signals();
|
||||||
void _process_incoming_signals();
|
void _process_incoming_signals();
|
||||||
|
|
||||||
Constructible<Signal_proxy_thread> _signal_proxy_thread;
|
Constructible<Signal_proxy_thread> _signal_proxy_thread;
|
||||||
@ -168,15 +166,19 @@ class Genode::Entrypoint : Genode::Noncopyable
|
|||||||
void dissolve(Signal_dispatcher_base &);
|
void dissolve(Signal_dispatcher_base &);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block and dispatch a single signal, return afterwards
|
* Block and dispatch a single I/O-level signal, return afterwards
|
||||||
*
|
*
|
||||||
* \noapi
|
* \noapi
|
||||||
*
|
*
|
||||||
|
* Only I/O signals are dispatched by this function. If an
|
||||||
|
* application-level signal occurs the dispatching of the signal is
|
||||||
|
* deferred until the entrypoint would block for the next time.
|
||||||
|
*
|
||||||
* XXX Turn into static function that ensures that the used signal
|
* XXX Turn into static function that ensures that the used signal
|
||||||
* receiver belongs to the calling entrypoint. Alternatively,
|
* receiver belongs to the calling entrypoint. Alternatively,
|
||||||
* remove it.
|
* remove it.
|
||||||
*/
|
*/
|
||||||
void wait_and_dispatch_one_signal();
|
void wait_and_dispatch_one_io_signal();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return RPC entrypoint
|
* Return RPC entrypoint
|
||||||
|
@ -39,7 +39,9 @@ namespace Genode {
|
|||||||
class Signal_dispatcher_base;
|
class Signal_dispatcher_base;
|
||||||
|
|
||||||
template <typename> class Signal_dispatcher;
|
template <typename> class Signal_dispatcher;
|
||||||
|
template <typename> class Io_signal_dispatcher;
|
||||||
template <typename, typename> class Signal_handler;
|
template <typename, typename> class Signal_handler;
|
||||||
|
template <typename, typename> class Io_signal_handler;
|
||||||
|
|
||||||
typedef Capability<Signal_context> Signal_context_capability;
|
typedef Capability<Signal_context> Signal_context_capability;
|
||||||
}
|
}
|
||||||
@ -305,9 +307,18 @@ class Genode::Signal_receiver : Noncopyable
|
|||||||
* to multple contexts. If a signal arrives, the context is provided with the
|
* to multple contexts. If a signal arrives, the context is provided with the
|
||||||
* signal. This enables the receiver to distinguish different signal sources
|
* signal. This enables the receiver to distinguish different signal sources
|
||||||
* and dispatch incoming signals context-specific.
|
* and dispatch incoming signals context-specific.
|
||||||
|
*
|
||||||
|
* Signal contexts are classified to represent one of two levels: application
|
||||||
|
* and I/O. The signal level determines how a signal is handled by
|
||||||
|
* 'wait_and_dispatch_one_io_signal', which defers signals corresponding to
|
||||||
|
* application-level contexts and dispatches only I/O-level signals.
|
||||||
*/
|
*/
|
||||||
class Genode::Signal_context
|
class Genode::Signal_context
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
enum class Level { App, Io };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -320,6 +331,11 @@ class Genode::Signal_context
|
|||||||
*/
|
*/
|
||||||
List_element<Signal_context> _registry_le;
|
List_element<Signal_context> _registry_le;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List element in deferred application signal list
|
||||||
|
*/
|
||||||
|
List_element<Signal_context> _deferred_le;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receiver to which the context is associated with
|
* Receiver to which the context is associated with
|
||||||
*
|
*
|
||||||
@ -347,13 +363,17 @@ class Genode::Signal_context
|
|||||||
friend class Signal_receiver;
|
friend class Signal_receiver;
|
||||||
friend class Signal_context_registry;
|
friend class Signal_context_registry;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Level _level = Level::App;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
Signal_context()
|
Signal_context()
|
||||||
: _receiver_le(this), _registry_le(this),
|
: _receiver_le(this), _registry_le(this), _deferred_le(this),
|
||||||
_receiver(0), _pending(0), _ref_cnt(0) { }
|
_receiver(0), _pending(0), _ref_cnt(0) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -365,6 +385,10 @@ class Genode::Signal_context
|
|||||||
*/
|
*/
|
||||||
virtual ~Signal_context();
|
virtual ~Signal_context();
|
||||||
|
|
||||||
|
Level level() const { return _level; }
|
||||||
|
|
||||||
|
List_element<Signal_context> *deferred_le() { return &_deferred_le; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local signal submission (DEPRECATED)
|
* Local signal submission (DEPRECATED)
|
||||||
*
|
*
|
||||||
@ -441,6 +465,19 @@ class Genode::Signal_dispatcher : public Signal_dispatcher_base,
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal dispatcher for I/O-level signals
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
struct Genode::Io_signal_dispatcher : Signal_dispatcher<T>
|
||||||
|
{
|
||||||
|
Io_signal_dispatcher(Signal_receiver &sig_rec,
|
||||||
|
T &obj, void (T::*member)(unsigned))
|
||||||
|
: Signal_dispatcher<T>(sig_rec, obj, member)
|
||||||
|
{ Signal_context::_level = Signal_context::Level::Io; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal dispatcher for handling signals by an object method
|
* Signal dispatcher for handling signals by an object method
|
||||||
*
|
*
|
||||||
@ -479,4 +516,16 @@ struct Genode::Signal_handler : Genode::Signal_dispatcher_base,
|
|||||||
void dispatch(unsigned num) override { (obj.*member)(); }
|
void dispatch(unsigned num) override { (obj.*member)(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signal handler for I/O-level signals
|
||||||
|
*/
|
||||||
|
template <typename T, typename EP = Genode::Entrypoint>
|
||||||
|
struct Genode::Io_signal_handler : Signal_handler<T, EP>
|
||||||
|
{
|
||||||
|
Io_signal_handler(EP &ep, T &obj, void (T::*member)())
|
||||||
|
: Signal_handler<T, EP>(ep, obj, member)
|
||||||
|
{ Signal_context::_level = Signal_context::Level::Io; }
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__BASE__SIGNAL_H_ */
|
#endif /* _INCLUDE__BASE__SIGNAL_H_ */
|
||||||
|
@ -49,13 +49,14 @@ _Z22__ldso_raise_exceptionv T
|
|||||||
_ZN6Genode10Entrypoint16_dispatch_signalERNS_6SignalE T
|
_ZN6Genode10Entrypoint16_dispatch_signalERNS_6SignalE T
|
||||||
_ZN6Genode10Entrypoint16schedule_suspendEPFvvES2_ T
|
_ZN6Genode10Entrypoint16schedule_suspendEPFvvES2_ T
|
||||||
_ZN6Genode10Entrypoint25_process_incoming_signalsEv T
|
_ZN6Genode10Entrypoint25_process_incoming_signalsEv T
|
||||||
_ZN6Genode10Entrypoint28wait_and_dispatch_one_signalEv T
|
_ZN6Genode10Entrypoint31wait_and_dispatch_one_io_signalEv T
|
||||||
_ZN6Genode10Entrypoint6manageERNS_22Signal_dispatcher_baseE T
|
_ZN6Genode10Entrypoint6manageERNS_22Signal_dispatcher_baseE T
|
||||||
_ZN6Genode10Entrypoint8dissolveERNS_22Signal_dispatcher_baseE T
|
_ZN6Genode10Entrypoint8dissolveERNS_22Signal_dispatcher_baseE T
|
||||||
_ZN6Genode10EntrypointC1ERNS_3EnvE T
|
_ZN6Genode10EntrypointC1ERNS_3EnvE T
|
||||||
_ZN6Genode10EntrypointC1ERNS_3EnvEmPKc T
|
_ZN6Genode10EntrypointC1ERNS_3EnvEmPKc T
|
||||||
_ZN6Genode10EntrypointC2ERNS_3EnvE T
|
_ZN6Genode10EntrypointC2ERNS_3EnvE T
|
||||||
_ZN6Genode10EntrypointC2ERNS_3EnvEmPKc T
|
_ZN6Genode10EntrypointC2ERNS_3EnvEmPKc T
|
||||||
|
_ZN6Genode10Entrypoint22Signal_proxy_component6signalEv T
|
||||||
_ZN6Genode10Ipc_serverC1Ev T
|
_ZN6Genode10Ipc_serverC1Ev T
|
||||||
_ZN6Genode10Ipc_serverC2Ev T
|
_ZN6Genode10Ipc_serverC2Ev T
|
||||||
_ZN6Genode10Ipc_serverD1Ev T
|
_ZN6Genode10Ipc_serverD1Ev T
|
||||||
|
@ -46,6 +46,19 @@ namespace Genode {
|
|||||||
static char const *initial_ep_name() { return "ep"; }
|
static char const *initial_ep_name() { return "ep"; }
|
||||||
|
|
||||||
|
|
||||||
|
void Entrypoint::Signal_proxy_component::signal()
|
||||||
|
{
|
||||||
|
/* XXX introduce while-pending loop */
|
||||||
|
try {
|
||||||
|
Signal sig = ep._sig_rec->pending_signal();
|
||||||
|
ep._dispatch_signal(sig);
|
||||||
|
} catch (Signal_receiver::Signal_not_pending) { }
|
||||||
|
|
||||||
|
ep._execute_post_signal_hook();
|
||||||
|
ep._process_deferred_signals();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Entrypoint::_dispatch_signal(Signal &sig)
|
void Entrypoint::_dispatch_signal(Signal &sig)
|
||||||
{
|
{
|
||||||
Signal_dispatcher_base *dispatcher = 0;
|
Signal_dispatcher_base *dispatcher = 0;
|
||||||
@ -58,6 +71,35 @@ void Entrypoint::_dispatch_signal(Signal &sig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Entrypoint::_defer_signal(Signal &sig)
|
||||||
|
{
|
||||||
|
Signal_context *context = sig.context();
|
||||||
|
|
||||||
|
Lock::Guard guard(_deferred_signals_mutex);
|
||||||
|
_deferred_signals.remove(context->deferred_le());
|
||||||
|
_deferred_signals.insert(context->deferred_le());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Entrypoint::_process_deferred_signals()
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
Signal_context *context = nullptr;
|
||||||
|
{
|
||||||
|
Lock::Guard guard(_deferred_signals_mutex);
|
||||||
|
if (!_deferred_signals.first()) return;
|
||||||
|
|
||||||
|
context = _deferred_signals.first()->object();
|
||||||
|
_deferred_signals.remove(_deferred_signals.first());
|
||||||
|
}
|
||||||
|
|
||||||
|
Signal_dispatcher_base *dispatcher =
|
||||||
|
dynamic_cast<Signal_dispatcher_base *>(context);
|
||||||
|
if (dispatcher) dispatcher->dispatch(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Entrypoint::_process_incoming_signals()
|
void Entrypoint::_process_incoming_signals()
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -71,7 +113,7 @@ void Entrypoint::_process_incoming_signals()
|
|||||||
success = cmpxchg(&_signal_recipient, NONE, SIGNAL_PROXY);
|
success = cmpxchg(&_signal_recipient, NONE, SIGNAL_PROXY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* common case, entrypoint is not in 'wait_and_dispatch_one_signal' */
|
/* common case, entrypoint is not in 'wait_and_dispatch_one_io_signal' */
|
||||||
if (success) {
|
if (success) {
|
||||||
/*
|
/*
|
||||||
* It might happen that we try to forward a signal to the
|
* It might happen that we try to forward a signal to the
|
||||||
@ -86,7 +128,7 @@ void Entrypoint::_process_incoming_signals()
|
|||||||
cmpxchg(&_signal_recipient, SIGNAL_PROXY, NONE);
|
cmpxchg(&_signal_recipient, SIGNAL_PROXY, NONE);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Entrypoint is in 'wait_and_dispatch_one_signal', wakup it up and
|
* Entrypoint is in 'wait_and_dispatch_one_io_signal', wakup it up and
|
||||||
* block for next signal
|
* block for next signal
|
||||||
*/
|
*/
|
||||||
_sig_rec->unblock_signal_waiter(*_rpc_ep);
|
_sig_rec->unblock_signal_waiter(*_rpc_ep);
|
||||||
@ -98,6 +140,7 @@ void Entrypoint::_process_incoming_signals()
|
|||||||
}
|
}
|
||||||
} while (!_suspended);
|
} while (!_suspended);
|
||||||
|
|
||||||
|
_deferred_signal_handler.destruct();
|
||||||
_suspend_dispatcher.destruct();
|
_suspend_dispatcher.destruct();
|
||||||
_sig_rec.destruct();
|
_sig_rec.destruct();
|
||||||
dissolve(_signal_proxy);
|
dissolve(_signal_proxy);
|
||||||
@ -129,7 +172,7 @@ void Entrypoint::_process_incoming_signals()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Entrypoint::wait_and_dispatch_one_signal()
|
void Entrypoint::wait_and_dispatch_one_io_signal()
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
@ -144,6 +187,12 @@ void Entrypoint::wait_and_dispatch_one_signal()
|
|||||||
|
|
||||||
_signal_pending_ack_lock.unlock();
|
_signal_pending_ack_lock.unlock();
|
||||||
|
|
||||||
|
/* defer application-level signals */
|
||||||
|
if (sig.context()->level() == Signal_context::Level::App) {
|
||||||
|
_defer_signal(sig);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
_dispatch_signal(sig);
|
_dispatch_signal(sig);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -154,6 +203,15 @@ void Entrypoint::wait_and_dispatch_one_signal()
|
|||||||
}
|
}
|
||||||
|
|
||||||
_execute_post_signal_hook();
|
_execute_post_signal_hook();
|
||||||
|
|
||||||
|
/* initiate potential deferred-signal handling in entrypoint */
|
||||||
|
if (_deferred_signals.first()) {
|
||||||
|
/* construct the handler on demand (otherwise we break core) */
|
||||||
|
if (!_deferred_signal_handler.constructed())
|
||||||
|
_deferred_signal_handler.construct(*this, *this,
|
||||||
|
&Entrypoint::_handle_deferred_signals);
|
||||||
|
Signal_transmitter(*_deferred_signal_handler).submit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -186,6 +244,12 @@ void Genode::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher)
|
|||||||
/* _sig_rec is invalid for a small window in _process_incoming_signals */
|
/* _sig_rec is invalid for a small window in _process_incoming_signals */
|
||||||
if (_sig_rec.constructed())
|
if (_sig_rec.constructed())
|
||||||
_sig_rec->dissolve(&dispatcher);
|
_sig_rec->dissolve(&dispatcher);
|
||||||
|
|
||||||
|
/* also remove context from deferred signal list */
|
||||||
|
{
|
||||||
|
Lock::Guard guard(_deferred_signals_mutex);
|
||||||
|
_deferred_signals.remove(dispatcher.deferred_le());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ Signal::Signal(Signal::Data data) : _data(data)
|
|||||||
* Normally, the context can only have one 'Signal' in flight, which is
|
* Normally, the context can only have one 'Signal' in flight, which is
|
||||||
* destroyed before 'pending_signal' is called the next time. However,
|
* destroyed before 'pending_signal' is called the next time. However,
|
||||||
* one exception is a signal handler that unexpectedly calls
|
* one exception is a signal handler that unexpectedly calls
|
||||||
* 'pending_signal' itself (i.e., via 'wait_and_dispatch_one_signal').
|
* 'pending_signal' itself (i.e., via 'wait_and_dispatch_one_io_signal').
|
||||||
* As this is dangerous programming pattern (that should be fixed), we
|
* As this is dangerous programming pattern (that should be fixed), we
|
||||||
* print a warning.
|
* print a warning.
|
||||||
*
|
*
|
||||||
@ -221,7 +221,7 @@ void Signal_receiver::_unsynchronized_dissolve(Signal_context * const context)
|
|||||||
env_deprecated()->pd_session()->free_context(context->_cap);
|
env_deprecated()->pd_session()->free_context(context->_cap);
|
||||||
|
|
||||||
/* restore default initialization of signal context */
|
/* restore default initialization of signal context */
|
||||||
context->_receiver = 0;
|
context->_receiver = nullptr;
|
||||||
context->_cap = Signal_context_capability();
|
context->_cap = Signal_context_capability();
|
||||||
|
|
||||||
/* remove context from context list */
|
/* remove context from context list */
|
||||||
|
@ -305,7 +305,7 @@ void *memmove(void *d, const void *s, size_t n)
|
|||||||
** linux/sched.h **
|
** linux/sched.h **
|
||||||
*******************/
|
*******************/
|
||||||
|
|
||||||
struct Timeout : Genode::Signal_handler<Timeout>
|
struct Timeout : Genode::Io_signal_handler<Timeout>
|
||||||
{
|
{
|
||||||
Genode::Entrypoint &ep;
|
Genode::Entrypoint &ep;
|
||||||
Timer::Connection timer;
|
Timer::Connection timer;
|
||||||
@ -321,7 +321,7 @@ struct Timeout : Genode::Signal_handler<Timeout>
|
|||||||
|
|
||||||
Timeout(Genode::Env &env, Genode::Entrypoint &ep, void (*ticker)())
|
Timeout(Genode::Env &env, Genode::Entrypoint &ep, void (*ticker)())
|
||||||
:
|
:
|
||||||
Signal_handler<Timeout>(ep, *this, &Timeout::handle),
|
Io_signal_handler<Timeout>(ep, *this, &Timeout::handle),
|
||||||
ep(ep), timer(env), tick(ticker)
|
ep(ep), timer(env), tick(ticker)
|
||||||
{
|
{
|
||||||
timer.sigh(*this);
|
timer.sigh(*this);
|
||||||
@ -334,7 +334,7 @@ struct Timeout : Genode::Signal_handler<Timeout>
|
|||||||
|
|
||||||
void wait()
|
void wait()
|
||||||
{
|
{
|
||||||
ep.wait_and_dispatch_one_signal();
|
ep.wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,10 +35,10 @@ class Nic_client
|
|||||||
Nic::Packet_allocator _tx_block_alloc;
|
Nic::Packet_allocator _tx_block_alloc;
|
||||||
Nic::Connection _nic;
|
Nic::Connection _nic;
|
||||||
|
|
||||||
Genode::Signal_handler<Nic_client> _sink_ack;
|
Genode::Io_signal_handler<Nic_client> _sink_ack;
|
||||||
Genode::Signal_handler<Nic_client> _sink_submit;
|
Genode::Io_signal_handler<Nic_client> _sink_submit;
|
||||||
Genode::Signal_handler<Nic_client> _source_ack;
|
Genode::Io_signal_handler<Nic_client> _source_ack;
|
||||||
Genode::Signal_handler<Nic_client> _link_state_change;
|
Genode::Io_signal_handler<Nic_client> _link_state_change;
|
||||||
|
|
||||||
void (*_tick)();
|
void (*_tick)();
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ class Lx::Timer
|
|||||||
|
|
||||||
::Timer::Connection _timer_conn;
|
::Timer::Connection _timer_conn;
|
||||||
Lx_kit::List<Context> _list;
|
Lx_kit::List<Context> _list;
|
||||||
Genode::Signal_handler<Lx::Timer> _handler;
|
Genode::Io_signal_handler<Lx::Timer> _handler;
|
||||||
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
|
Genode::Tslab<Context, 32 * sizeof(Context)> _timer_alloc;
|
||||||
|
|
||||||
void (*_tick)();
|
void (*_tick)();
|
||||||
|
@ -533,8 +533,8 @@ class Usb::Session_component : public Session_rpc_object,
|
|||||||
long _dev = 0;
|
long _dev = 0;
|
||||||
Device *_device = nullptr;
|
Device *_device = nullptr;
|
||||||
Signal_context_capability _sigh_state_change;
|
Signal_context_capability _sigh_state_change;
|
||||||
Signal_handler<Session_component> _packet_avail;
|
Io_signal_handler<Session_component> _packet_avail;
|
||||||
Signal_handler<Session_component> _ready_ack;
|
Io_signal_handler<Session_component> _ready_ack;
|
||||||
Worker _worker;
|
Worker _worker;
|
||||||
Ram_dataspace_capability _tx_ds;
|
Ram_dataspace_capability _tx_ds;
|
||||||
|
|
||||||
|
@ -495,7 +495,7 @@ class Rump_factory : public Vfs::File_system_factory
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
Timer::Connection _timer;
|
Timer::Connection _timer;
|
||||||
Genode::Signal_handler<Rump_factory> _sync_handler;
|
Genode::Io_signal_handler<Rump_factory> _sync_handler;
|
||||||
|
|
||||||
void _sync() { _rump_sync(); }
|
void _sync() { _rump_sync(); }
|
||||||
|
|
||||||
|
@ -366,7 +366,7 @@ struct Libc::Kernel
|
|||||||
Env_implementation _libc_env { _env, _heap, _io_response_handler };
|
Env_implementation _libc_env { _env, _heap, _io_response_handler };
|
||||||
Vfs_plugin _vfs { _libc_env, _heap };
|
Vfs_plugin _vfs { _libc_env, _heap };
|
||||||
|
|
||||||
Genode::Reconstructible<Genode::Signal_handler<Kernel>> _resume_main_handler {
|
Genode::Reconstructible<Genode::Io_signal_handler<Kernel>> _resume_main_handler {
|
||||||
_env.ep(), *this, &Kernel::_resume_main };
|
_env.ep(), *this, &Kernel::_resume_main };
|
||||||
|
|
||||||
jmp_buf _kernel_context;
|
jmp_buf _kernel_context;
|
||||||
@ -605,7 +605,7 @@ struct Libc::Kernel
|
|||||||
/* _setjmp() returned after _longjmp() - user context suspended */
|
/* _setjmp() returned after _longjmp() - user context suspended */
|
||||||
|
|
||||||
while ((!_app_returned) && (!_suspend_scheduled)) {
|
while ((!_app_returned) && (!_suspend_scheduled)) {
|
||||||
_env.ep().wait_and_dispatch_one_signal();
|
_env.ep().wait_and_dispatch_one_io_signal();
|
||||||
|
|
||||||
if (_resume_main_once && !_setjmp(_kernel_context))
|
if (_resume_main_once && !_setjmp(_kernel_context))
|
||||||
_switch_to_user();
|
_switch_to_user();
|
||||||
@ -623,7 +623,7 @@ struct Libc::Kernel
|
|||||||
_switch_to_user();
|
_switch_to_user();
|
||||||
|
|
||||||
while ((!_app_returned) && (!_suspend_scheduled)) {
|
while ((!_app_returned) && (!_suspend_scheduled)) {
|
||||||
_env.ep().wait_and_dispatch_one_signal();
|
_env.ep().wait_and_dispatch_one_io_signal();
|
||||||
if (_resume_main_once && !_setjmp(_kernel_context))
|
if (_resume_main_once && !_setjmp(_kernel_context))
|
||||||
_switch_to_user();
|
_switch_to_user();
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,9 @@ class Nic_receiver_thread : public Genode::Thread_deprecated<8192>
|
|||||||
|
|
||||||
Genode::Signal_receiver _sig_rec;
|
Genode::Signal_receiver _sig_rec;
|
||||||
|
|
||||||
Genode::Signal_dispatcher<Nic_receiver_thread> _link_state_dispatcher;
|
Genode::Io_signal_dispatcher<Nic_receiver_thread> _link_state_dispatcher;
|
||||||
Genode::Signal_dispatcher<Nic_receiver_thread> _rx_packet_avail_dispatcher;
|
Genode::Io_signal_dispatcher<Nic_receiver_thread> _rx_packet_avail_dispatcher;
|
||||||
Genode::Signal_dispatcher<Nic_receiver_thread> _rx_ready_to_ack_dispatcher;
|
Genode::Io_signal_dispatcher<Nic_receiver_thread> _rx_ready_to_ack_dispatcher;
|
||||||
|
|
||||||
void _handle_rx_packet_avail(unsigned)
|
void _handle_rx_packet_avail(unsigned)
|
||||||
{
|
{
|
||||||
|
@ -55,28 +55,24 @@ struct Explicitly_nested : Test
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implicitly_nested test
|
* App_signal_deferred test
|
||||||
*
|
*
|
||||||
* Call with_libc from within a signal handler while being
|
* Application-level signals do not interrupt blocking libc calls but are
|
||||||
* suspended in a select() call.
|
* deferred until the component returns to the entrypoint event loop.
|
||||||
*/
|
*/
|
||||||
struct Implicitly_nested : Test
|
struct App_signal_deferred : Test
|
||||||
{
|
{
|
||||||
Env &_env;
|
Env &_env;
|
||||||
|
|
||||||
void _handle()
|
void _handle()
|
||||||
{
|
{
|
||||||
log("calling with_libc from signal handler");
|
error("application-level signal was dispatched during select()");
|
||||||
Libc::with_libc([&] () {
|
|
||||||
|
|
||||||
printf("Hello from with_libc in signal handler\n");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Signal_handler<Implicitly_nested> _dispatcher {
|
Signal_handler<App_signal_deferred> _dispatcher {
|
||||||
_env.ep(), *this, &Implicitly_nested::_handle };
|
_env.ep(), *this, &App_signal_deferred::_handle };
|
||||||
|
|
||||||
Implicitly_nested(Env &env, int id)
|
App_signal_deferred(Env &env, int id)
|
||||||
: Test(env, id), _env(env)
|
: Test(env, id), _env(env)
|
||||||
{
|
{
|
||||||
log("calling with_libc");
|
log("calling with_libc");
|
||||||
@ -124,7 +120,7 @@ struct Explicitly_triple_nested : Test
|
|||||||
struct Main
|
struct Main
|
||||||
{
|
{
|
||||||
Constructible<Explicitly_nested> test_1;
|
Constructible<Explicitly_nested> test_1;
|
||||||
Constructible<Implicitly_nested> test_2;
|
Constructible<App_signal_deferred> test_2;
|
||||||
Constructible<Explicitly_triple_nested> test_3;
|
Constructible<Explicitly_triple_nested> test_3;
|
||||||
|
|
||||||
Main(Env &env)
|
Main(Env &env)
|
||||||
|
@ -36,7 +36,7 @@ class Genode::Timer_time_source : public Genode::Time_source
|
|||||||
|
|
||||||
enum { MIN_TIMEOUT_US = 5000 };
|
enum { MIN_TIMEOUT_US = 5000 };
|
||||||
|
|
||||||
using Signal_handler = Genode::Signal_handler<Timer_time_source>;
|
using Signal_handler = Genode::Io_signal_handler<Timer_time_source>;
|
||||||
|
|
||||||
::Timer::Session &_session;
|
::Timer::Session &_session;
|
||||||
Signal_handler _signal_handler;
|
Signal_handler _signal_handler;
|
||||||
|
@ -26,11 +26,11 @@ class Usb::Packet_handler
|
|||||||
Usb::Connection &_connection;
|
Usb::Connection &_connection;
|
||||||
Genode::Entrypoint &_ep;
|
Genode::Entrypoint &_ep;
|
||||||
|
|
||||||
Signal_handler<Packet_handler> _rpc_ack_avail =
|
Io_signal_handler<Packet_handler> _rpc_ack_avail {
|
||||||
{_ep, *this, &Packet_handler::_packet_handler };
|
_ep, *this, &Packet_handler::_packet_handler };
|
||||||
|
|
||||||
Signal_handler<Packet_handler> _rpc_ready_submit =
|
Io_signal_handler<Packet_handler> _rpc_ready_submit {
|
||||||
{ _ep, *this, &Packet_handler::_ready_handler };
|
_ep, *this, &Packet_handler::_ready_handler };
|
||||||
|
|
||||||
bool _ready_submit = true;
|
bool _ready_submit = true;
|
||||||
|
|
||||||
@ -76,7 +76,7 @@ class Usb::Packet_handler
|
|||||||
|
|
||||||
void wait_for_packet()
|
void wait_for_packet()
|
||||||
{
|
{
|
||||||
packet_avail() ? _packet_handler() : _ep.wait_and_dispatch_one_signal();
|
packet_avail() ? _packet_handler() : _ep.wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet_descriptor alloc(size_t size)
|
Packet_descriptor alloc(size_t size)
|
||||||
@ -108,7 +108,7 @@ class Usb::Packet_handler
|
|||||||
|
|
||||||
/* wait for ready_to_submit signal */
|
/* wait for ready_to_submit signal */
|
||||||
while (!_ready_submit)
|
while (!_ready_submit)
|
||||||
_ep.wait_and_dispatch_one_signal();
|
_ep.wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
_connection.source()->submit_packet(p);
|
_connection.source()->submit_packet(p);
|
||||||
|
@ -33,3 +33,7 @@ build_boot_image "core ld.lib.so init timer test-signal"
|
|||||||
append qemu_args "-nographic -m 64"
|
append qemu_args "-nographic -m 64"
|
||||||
|
|
||||||
run_genode_until {.*--- Signalling test finished ---.*\n} 200
|
run_genode_until {.*--- Signalling test finished ---.*\n} 200
|
||||||
|
|
||||||
|
grep_output {Error: }
|
||||||
|
|
||||||
|
compare_output_to {}
|
||||||
|
@ -34,5 +34,5 @@ void Component::construct(Genode::Env &env)
|
|||||||
void Server::wait_and_dispatch_one_signal()
|
void Server::wait_and_dispatch_one_signal()
|
||||||
{
|
{
|
||||||
if (_env)
|
if (_env)
|
||||||
_env->ep().wait_and_dispatch_one_signal();
|
_env->ep().wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
|
@ -167,9 +167,8 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
/* pass packet to server side */
|
/* pass packet to server side */
|
||||||
source.submit_packet(packet_in);
|
source.submit_packet(packet_in);
|
||||||
|
|
||||||
while (handle.queued_read_state != Handle_state::Queued_state::ACK)
|
while (handle.queued_read_state != Handle_state::Queued_state::ACK) {
|
||||||
{
|
_env.ep().wait_and_dispatch_one_io_signal();
|
||||||
_env.ep().wait_and_dispatch_one_signal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain result packet descriptor with updated status info */
|
/* obtain result packet descriptor with updated status info */
|
||||||
@ -219,9 +218,8 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
/* pass packet to server side */
|
/* pass packet to server side */
|
||||||
source.submit_packet(packet_in);
|
source.submit_packet(packet_in);
|
||||||
|
|
||||||
while (handle.queued_write_state != Handle_state::Queued_state::ACK)
|
while (handle.queued_write_state != Handle_state::Queued_state::ACK) {
|
||||||
{
|
_env.ep().wait_and_dispatch_one_io_signal();
|
||||||
_env.ep().wait_and_dispatch_one_signal();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* obtain result packet descriptor with updated status info */
|
/* obtain result packet descriptor with updated status info */
|
||||||
@ -274,7 +272,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Genode::Signal_handler<Fs_file_system> _ack_handler {
|
Genode::Io_signal_handler<Fs_file_system> _ack_handler {
|
||||||
_env.ep(), *this, &Fs_file_system::_handle_ack };
|
_env.ep(), *this, &Fs_file_system::_handle_ack };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -74,7 +74,7 @@ class Vfs::Terminal_file_system : public Single_file_system
|
|||||||
|
|
||||||
Handle_registry _handle_registry;
|
Handle_registry _handle_registry;
|
||||||
|
|
||||||
Genode::Signal_handler<Terminal_file_system> _read_avail_handler {
|
Genode::Io_signal_handler<Terminal_file_system> _read_avail_handler {
|
||||||
_env.ep(), *this, &Terminal_file_system::_handle_read_avail };
|
_env.ep(), *this, &Terminal_file_system::_handle_read_avail };
|
||||||
|
|
||||||
void _handle_read_avail()
|
void _handle_read_avail()
|
||||||
|
@ -123,9 +123,9 @@ class Driver : public Block::Driver
|
|||||||
Genode::size_t _blk_sz; /* block size */
|
Genode::size_t _blk_sz; /* block size */
|
||||||
Block::sector_t _blk_cnt; /* block count */
|
Block::sector_t _blk_cnt; /* block count */
|
||||||
Chunk_level_0 _cache; /* chunk hierarchy */
|
Chunk_level_0 _cache; /* chunk hierarchy */
|
||||||
Genode::Signal_handler<Driver> _source_ack;
|
Genode::Io_signal_handler<Driver> _source_ack;
|
||||||
Genode::Signal_handler<Driver> _source_submit;
|
Genode::Io_signal_handler<Driver> _source_submit;
|
||||||
Genode::Signal_handler<Driver> _yield;
|
Genode::Io_signal_handler<Driver> _yield;
|
||||||
|
|
||||||
Driver(Driver const&); /* singleton pattern */
|
Driver(Driver const&); /* singleton pattern */
|
||||||
Driver& operator=(Driver const&); /* singleton pattern */
|
Driver& operator=(Driver const&); /* singleton pattern */
|
||||||
@ -279,7 +279,7 @@ class Driver : public Block::Driver
|
|||||||
*/
|
*/
|
||||||
off = e.off;
|
off = e.off;
|
||||||
len = _blk_sz * _blk_cnt - off;
|
len = _blk_sz * _blk_cnt - off;
|
||||||
_env.ep().wait_and_dispatch_one_signal();
|
_env.ep().wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,9 +68,9 @@ class Test
|
|||||||
Genode::Entrypoint &_ep;
|
Genode::Entrypoint &_ep;
|
||||||
Genode::Allocator_avl _alloc;
|
Genode::Allocator_avl _alloc;
|
||||||
Block::Connection _session;
|
Block::Connection _session;
|
||||||
Genode::Signal_handler<Test> _disp_ack;
|
Genode::Io_signal_handler<Test> _disp_ack;
|
||||||
Genode::Signal_handler<Test> _disp_submit;
|
Genode::Io_signal_handler<Test> _disp_submit;
|
||||||
Genode::Signal_handler<Test> _disp_timeout;
|
Genode::Io_signal_handler<Test> _disp_timeout;
|
||||||
Timer::Connection _timer;
|
Timer::Connection _timer;
|
||||||
bool _handle;
|
bool _handle;
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ class Test
|
|||||||
void _handle_signal()
|
void _handle_signal()
|
||||||
{
|
{
|
||||||
_handle = true;
|
_handle = true;
|
||||||
while (_handle) _ep.wait_and_dispatch_one_signal();
|
while (_handle) _ep.wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -434,77 +434,106 @@ struct Many_contexts_test : Signal_test
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test 'wait_and_dispatch_one_signal' implementation for entrypoints
|
* Test 'wait_and_dispatch_one_io_signal' implementation for entrypoints
|
||||||
*
|
*
|
||||||
* Normally Genode signals are delivered by a signal thread, which blocks for
|
* Normally Genode signals are delivered by a signal thread, which blocks for
|
||||||
* incoming signals and is woken up when a signals arrives, the thread then
|
* incoming signals and is woken up when a signals arrives, the thread then
|
||||||
* sends an RPC to an entrypoint that, in turn, processes the signal.
|
* sends an RPC to an entrypoint that, in turn, processes the signal.
|
||||||
* 'wait_and_dispatch_one_signal' allows an entrypoint to receive signals
|
* 'wait_and_dispatch_one_io_signal' allows an entrypoint to receive I/O-level
|
||||||
* directly, by taking advantage of the same code as the signal thread. This
|
* signals directly, by taking advantage of the same code as the signal thread.
|
||||||
* leaves the problem that at this point two entities (the signal thread and the
|
* This leaves the problem that at this point two entities (the signal thread
|
||||||
* entrypoint) may wait for signals to arrive. It is not decidable which entity
|
* and the entrypoint) may wait for signals to arrive. It is not decidable
|
||||||
* is woken up on signal arrival. If the signal thread is woken up and tries to
|
* which entity is woken up on signal arrival. If the signal thread is woken up
|
||||||
* deliver the signal RPC, system may dead lock when no additional signal
|
* and tries to deliver the signal RPC, system may dead lock when no additional
|
||||||
* arrives to pull the entrypoint out of the signal waiting code. This test
|
* signal arrives to pull the entrypoint out of the signal waiting code. This
|
||||||
* triggers this exact situation. We also test nesting with the same signal
|
* test triggers this exact situation. We also test nesting with the same
|
||||||
* context of 'wait_and_dispatch_one_signal' here, which also caused dead locks
|
* signal context of 'wait_and_dispatch_one_io_signal' here, which also caused
|
||||||
* in the past.
|
* dead locks in the past. Also, the test verifies application-level signals
|
||||||
|
* are deferred during 'wait_and_dispatch_one_io_signal'.
|
||||||
*/
|
*/
|
||||||
struct Nested_test : Signal_test
|
struct Nested_test : Signal_test
|
||||||
{
|
{
|
||||||
static constexpr char const *brief = "wait and dispatch signals at entrypoint";
|
static constexpr char const *brief = "wait and dispatch signals at entrypoint";
|
||||||
|
|
||||||
struct Wait_interface
|
struct Test_interface
|
||||||
{
|
{
|
||||||
GENODE_RPC(Rpc_dispatch_test, void, dispatch_test);
|
GENODE_RPC(Rpc_test_io_dispatch, void, test_io_dispatch);
|
||||||
GENODE_RPC_INTERFACE(Rpc_dispatch_test);
|
GENODE_RPC(Rpc_test_app_dispatch, void, test_app_dispatch);
|
||||||
|
GENODE_RPC_INTERFACE(Rpc_test_io_dispatch, Rpc_test_app_dispatch);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Wait_component :
|
struct Test_component : Rpc_object<Test_interface, Test_component>
|
||||||
Rpc_object<Wait_interface, Wait_component>
|
|
||||||
{
|
{
|
||||||
Entrypoint &ep;
|
Nested_test &test;
|
||||||
|
|
||||||
Wait_component(Entrypoint &ep) : ep(ep) { }
|
Test_component(Nested_test &test) : test(test) { }
|
||||||
|
|
||||||
void dispatch_test()
|
void test_io_dispatch()
|
||||||
{
|
{
|
||||||
log("1/5: [ep] wait for signal during RPC from [outside]");
|
log("1/8: [ep] wait for I/O-level signal during RPC from [outside]");
|
||||||
ep.wait_and_dispatch_one_signal();
|
while (!test.io_done) test.ep.wait_and_dispatch_one_io_signal();
|
||||||
log("5/5: [ep] success");
|
log("6/8: [ep] I/O completed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_app_dispatch()
|
||||||
|
{
|
||||||
|
if (!test.app_done)
|
||||||
|
error("8/8: [ep] application-level signal was not dispatched");
|
||||||
|
else
|
||||||
|
log("8/8: [ep] success");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Sender_thread : Thread
|
struct Sender_thread : Thread
|
||||||
{
|
{
|
||||||
Signal_context_capability cap;
|
Nested_test &test;
|
||||||
Timer::Connection timer;
|
Timer::Connection timer;
|
||||||
|
|
||||||
Sender_thread(Env &env, Signal_context_capability cap)
|
Sender_thread(Env &env, Nested_test &test)
|
||||||
: Thread(env, "sender_thread", 1024 * sizeof(long)), cap(cap), timer(env)
|
:
|
||||||
|
Thread(env, "sender_thread", 1024 * sizeof(long)),
|
||||||
|
test(test), timer(env)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void entry() {
|
void entry()
|
||||||
timer.msleep(500);
|
{
|
||||||
log("2/5: [outside] submit initial signal");
|
timer.msleep(1000);
|
||||||
Signal_transmitter(cap).submit();
|
|
||||||
|
log("2/8: [outside] submit application-level signal (should be deferred)");
|
||||||
|
Signal_transmitter(test.nop_handler).submit();
|
||||||
|
Signal_transmitter(test.app_handler).submit();
|
||||||
|
Signal_transmitter(test.nop_handler).submit();
|
||||||
|
|
||||||
|
log("3/8: [outside] submit I/O-level signal");
|
||||||
|
Signal_transmitter(test.io_handler).submit();
|
||||||
|
Signal_transmitter(test.nop_handler).submit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Env &env;
|
Env &env;
|
||||||
Entrypoint ep { env, 2048 * sizeof(long),
|
Entrypoint ep { env, 2048 * sizeof(long), "wait_dispatch_ep" };
|
||||||
"wait_dispatch_ep" };
|
|
||||||
Signal_handler<Nested_test> dispatcher { ep, *this,
|
Signal_handler<Nested_test> app_handler { ep, *this, &Nested_test::handle_app };
|
||||||
&Nested_test::handle };
|
Signal_handler<Nested_test> nop_handler { ep, *this, &Nested_test::handle_nop };
|
||||||
Wait_component wait { ep };
|
Io_signal_handler<Nested_test> io_handler { ep, *this, &Nested_test::handle_io };
|
||||||
Capability<Wait_interface> wait_cap = ep.manage(wait);
|
|
||||||
Sender_thread thread { env, dispatcher };
|
Test_component wait { *this };
|
||||||
|
Capability<Test_interface> wait_cap { ep.manage(wait) };
|
||||||
|
Sender_thread thread { env, *this };
|
||||||
bool nested { false };
|
bool nested { false };
|
||||||
|
bool volatile app_done { false };
|
||||||
|
bool volatile io_done { false };
|
||||||
|
|
||||||
|
Timer::Connection timer { env };
|
||||||
|
|
||||||
Nested_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
Nested_test(Env &env, int id) : Signal_test(id, brief), env(env)
|
||||||
{
|
{
|
||||||
thread.start();
|
thread.start();
|
||||||
wait_cap.call<Wait_interface::Rpc_dispatch_test>();
|
wait_cap.call<Test_interface::Rpc_test_io_dispatch>();
|
||||||
|
|
||||||
|
/* grant the ep some time for application-signal handling */
|
||||||
|
timer.msleep(1000);
|
||||||
|
wait_cap.call<Test_interface::Rpc_test_app_dispatch>();
|
||||||
}
|
}
|
||||||
|
|
||||||
~Nested_test()
|
~Nested_test()
|
||||||
@ -512,22 +541,35 @@ struct Nested_test : Signal_test
|
|||||||
ep.dissolve(wait);
|
ep.dissolve(wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle()
|
void handle_app()
|
||||||
|
{
|
||||||
|
if (!io_done)
|
||||||
|
error("7/8: [ep] application-level signal was not deferred");
|
||||||
|
else
|
||||||
|
log("7/8: [ep] application-level signal received");
|
||||||
|
|
||||||
|
app_done = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_nop() { }
|
||||||
|
|
||||||
|
void handle_io()
|
||||||
{
|
{
|
||||||
if (nested) {
|
if (nested) {
|
||||||
log("4/5: [ep] nested signal received");
|
log("5/8: [ep] nested I/O-level signal received");
|
||||||
|
io_done = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
log("3/5: [ep] signal received - sending nested signal");
|
log("4/8: [ep] I/O-level signal received - sending nested signal");
|
||||||
nested = true;
|
nested = true;
|
||||||
Signal_transmitter(dispatcher).submit();
|
Signal_transmitter(io_handler).submit();
|
||||||
ep.wait_and_dispatch_one_signal();
|
ep.wait_and_dispatch_one_io_signal();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stress-test 'wait_and_dispatch_one_signal' implementation for entrypoints
|
* Stress-test 'wait_and_dispatch_one_io_signal' implementation for entrypoints
|
||||||
*
|
*
|
||||||
* Let multiple entrypoints directly wait and dispatch signals in a
|
* Let multiple entrypoints directly wait and dispatch signals in a
|
||||||
* highly nested manner and with multiple stressful senders.
|
* highly nested manner and with multiple stressful senders.
|
||||||
@ -561,10 +603,11 @@ struct Nested_stress_test : Signal_test
|
|||||||
{
|
{
|
||||||
Entrypoint ep;
|
Entrypoint ep;
|
||||||
char const *name;
|
char const *name;
|
||||||
Signal_handler<Receiver> handler { ep, *this, &Receiver::handle };
|
|
||||||
unsigned count { 0 };
|
unsigned count { 0 };
|
||||||
bool destruct { false };
|
bool destruct { false };
|
||||||
|
|
||||||
|
Io_signal_handler<Receiver> handler { ep, *this, &Receiver::handle };
|
||||||
|
|
||||||
Receiver(Env &env, char const *name)
|
Receiver(Env &env, char const *name)
|
||||||
: ep(env, 3 * 1024 * sizeof(long), name), name(name) { }
|
: ep(env, 3 * 1024 * sizeof(long), name), name(name) { }
|
||||||
|
|
||||||
@ -574,8 +617,7 @@ struct Nested_stress_test : Signal_test
|
|||||||
* We have to get out of the nesting if the host wants to destroy
|
* We have to get out of the nesting if the host wants to destroy
|
||||||
* us to avoid a deadlock at the lock in the signal handler.
|
* us to avoid a deadlock at the lock in the signal handler.
|
||||||
*/
|
*/
|
||||||
if (destruct) {
|
if (destruct) { return; }
|
||||||
return; }
|
|
||||||
|
|
||||||
/* raise call counter */
|
/* raise call counter */
|
||||||
count++;
|
count++;
|
||||||
@ -585,7 +627,7 @@ struct Nested_stress_test : Signal_test
|
|||||||
* gives zero, then unwind the whole nesting and start afresh.
|
* gives zero, then unwind the whole nesting and start afresh.
|
||||||
*/
|
*/
|
||||||
if ((count & ((1 << UNWIND_COUNT_MOD_LOG2) - 1)) != 0) {
|
if ((count & ((1 << UNWIND_COUNT_MOD_LOG2) - 1)) != 0) {
|
||||||
ep.wait_and_dispatch_one_signal(); }
|
ep.wait_and_dispatch_one_io_signal(); }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -599,8 +641,8 @@ struct Nested_stress_test : Signal_test
|
|||||||
Sender sender_3 { env, "sender-3", receiver_3.handler };
|
Sender sender_3 { env, "sender-3", receiver_3.handler };
|
||||||
Signal_transmitter done;
|
Signal_transmitter done;
|
||||||
|
|
||||||
Signal_handler<Nested_stress_test> poll
|
Io_signal_handler<Nested_stress_test> poll {
|
||||||
{ env.ep(), *this, &Nested_stress_test::handle_poll };
|
env.ep(), *this, &Nested_stress_test::handle_poll };
|
||||||
|
|
||||||
Nested_stress_test(Env &env, int id, Signal_context_capability done)
|
Nested_stress_test(Env &env, int id, Signal_context_capability done)
|
||||||
: Signal_test(id, brief), env(env), done(done)
|
: Signal_test(id, brief), env(env), done(done)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user