Unify 'Signal_dispatcher' interfaces

Several users of the signal API used custom convenience classes to
invoke signal-handling functions on the reception of incoming signals.
The 'Signal_dispatcher' pattern turned out to be particularly useful. To
avoid the duplication of this code across the code base, this patch
adds the interface to 'base/signal.h'.

Furthermore, the patch changes the 'Signal::num()' return type from int
to unsigned because negative numbers are meaningless here.

Fixes #511
This commit is contained in:
Norman Feske 2013-01-10 20:56:48 +01:00
parent 277af91376
commit 13d4108fea
19 changed files with 119 additions and 317 deletions

View File

@ -52,7 +52,7 @@ namespace Genode {
friend class Signal_context; friend class Signal_context;
Signal_context *_context; Signal_context *_context;
int _num; unsigned _num;
/** /**
* Constructor * Constructor
@ -63,7 +63,7 @@ namespace Genode {
* *
* Signal objects are constructed only by signal receivers. * Signal objects are constructed only by signal receivers.
*/ */
Signal(Signal_context *context, int num) Signal(Signal_context *context, unsigned num)
: _context(context), _num(num) : _context(context), _num(num)
{ } { }
@ -82,7 +82,7 @@ namespace Genode {
/** /**
* Return number of signals received from the same transmitter * Return number of signals received from the same transmitter
*/ */
int num() { return _num; } unsigned num() const { return _num; }
}; };
/** /**
@ -191,7 +191,7 @@ namespace Genode {
* *
* \param cnt number of signals to submit at once * \param cnt number of signals to submit at once
*/ */
void submit(int cnt = 1); void submit(unsigned cnt = 1);
}; };
@ -282,6 +282,61 @@ namespace Genode {
*/ */
static void dispatch_signals(Signal_source *signal_source); static void dispatch_signals(Signal_source *signal_source);
}; };
/**
* Abstract interface to be implemented by signal dispatchers
*/
struct Signal_dispatcher_base : Signal_context
{
virtual void dispatch(unsigned num) = 0;
};
/**
* Adapter for directing signals to member functions
*
* This utility associates member functions with signals. It is intended to
* be used as a member variable of the class that handles incoming signals
* of a certain type. The constructor takes a pointer-to-member to the
* signal handling function as argument. If a signal is received at the
* common signal reception code, this function will be invoked by calling
* 'Signal_dispatcher_base::dispatch'.
*
* \param T type of signal-handling class
*/
template <typename T>
class Signal_dispatcher : private Signal_dispatcher_base,
public Signal_context_capability
{
private:
T &obj;
void (T::*member) (unsigned);
Signal_receiver &sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Signal_receiver &sig_rec,
T &obj, void (T::*member)(unsigned))
:
Signal_context_capability(sig_rec.manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec.dissolve(this); }
void dispatch(unsigned num) { (obj.*member)(num); }
};
} }
#endif /* _INCLUDE__BASE__SIGNAL_H__ */ #endif /* _INCLUDE__BASE__SIGNAL_H__ */

View File

@ -179,7 +179,7 @@ void Signal_transmitter::context(Signal_context_capability context)
} }
void Signal_transmitter::submit(int cnt) void Signal_transmitter::submit(unsigned cnt)
{ {
signal_connection()->submit(_context, cnt); signal_connection()->submit(_context, cnt);
} }
@ -347,7 +347,7 @@ void Signal_receiver::local_submit(Signal ns)
* counters. In the common case, the current signal is an invalid * counters. In the common case, the current signal is an invalid
* signal with a counter value of zero. * signal with a counter value of zero.
*/ */
int num = context->_curr_signal.num() + ns.num(); unsigned num = context->_curr_signal.num() + ns.num();
context->_curr_signal = Signal(context, num); context->_curr_signal = Signal(context, num);
/* wake up the receiver if the context becomes pending */ /* wake up the receiver if the context becomes pending */

View File

@ -75,8 +75,8 @@ class Local_fault_handler : public Thread<4096>
while (true) { while (true) {
printf("fault handler: waiting for fault signal\n"); printf("fault handler: waiting for fault signal\n");
Signal signal = _receiver->wait_for_signal(); Signal signal = _receiver->wait_for_signal();
printf("received %d fault signals\n", signal.num()); printf("received %u fault signals\n", signal.num());
for (int i = 0; i < signal.num(); i++) for (unsigned i = 0; i < signal.num(); i++)
handle_fault(); handle_fault();
} }
} }

View File

@ -128,7 +128,7 @@ namespace Nic {
protected: protected:
void _process_packets() void _process_packets(unsigned)
{ {
static sk_buff work_skb; /* dummy skb for fixup calls */ static sk_buff work_skb; /* dummy skb for fixup calls */
static Counter counter("TX"); static Counter counter("TX");

View File

@ -17,40 +17,6 @@
#include "signal.h" #include "signal.h"
template <typename T>
class Signal_dispatcher : public Driver_context,
public Genode::Signal_context_capability
{
private:
T &obj;
void (T::*member) ();
Genode::Signal_receiver *sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Genode::Signal_receiver *sig_rec,
T &obj, void (T::*member)())
:
Genode::Signal_context_capability(sig_rec->manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec->dissolve(this); }
void handle() { (obj.*member)(); }
char const *debug() { return "Signal_dispatcher"; }
};
/** /**
* Session components that overrides signal handlers * Session components that overrides signal handlers
@ -60,11 +26,11 @@ class Packet_session_component : public RPC
{ {
private: private:
Signal_dispatcher<Packet_session_component> _process_packet_dispatcher; Genode::Signal_dispatcher<Packet_session_component> _process_packet_dispatcher;
protected: protected:
virtual void _process_packets() = 0; virtual void _process_packets(unsigned) = 0;
public: public:
@ -73,7 +39,7 @@ class Packet_session_component : public RPC
Genode::Signal_receiver *sig_rec) Genode::Signal_receiver *sig_rec)
: :
RPC(tx_ds, ep), RPC(tx_ds, ep),
_process_packet_dispatcher(sig_rec, *this, _process_packet_dispatcher(*sig_rec, *this,
&Packet_session_component::_process_packets) &Packet_session_component::_process_packets)
{ {
/* /*
@ -91,7 +57,7 @@ class Packet_session_component : public RPC
Genode::Signal_receiver *sig_rec) Genode::Signal_receiver *sig_rec)
: :
RPC(tx_ds, rx_ds, rx_buffer_alloc, ep), RPC(tx_ds, rx_ds, rx_buffer_alloc, ep),
_process_packet_dispatcher(sig_rec, *this, _process_packet_dispatcher(*sig_rec, *this,
&Packet_session_component::_process_packets) &Packet_session_component::_process_packets)
{ {
/* /*

View File

@ -51,7 +51,7 @@ namespace Block {
protected: protected:
void _process_packets() void _process_packets(unsigned)
{ {
while (tx_sink()->packet_avail()) while (tx_sink()->packet_avail())
{ {

View File

@ -31,46 +31,6 @@ static const bool verbose = false;
static bool audio_out_active = false; static bool audio_out_active = false;
/**
* Packet-stream signal dispatcher
*
* TODO: Move to generic code
*/
template <typename T>
class Signal_dispatcher : public Driver_context,
public Genode::Signal_context_capability
{
private:
T &obj;
void (T::*member) ();
Genode::Signal_receiver *sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Genode::Signal_receiver *sig_rec,
T &obj, void (T::*member)())
:
Genode::Signal_context_capability(sig_rec->manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec->dissolve(this); }
void handle() { (obj.*member)(); }
char const *debug() { return "Signal_dispatcher"; }
};
namespace Audio_out { namespace Audio_out {
class Session_component; class Session_component;
@ -94,7 +54,7 @@ namespace Audio_out {
return _ds; return _ds;
} }
void _process_packets() void _process_packets(unsigned)
{ {
/* handle audio-out packets */ /* handle audio-out packets */
Session_component *left = channel_acquired[LEFT], Session_component *left = channel_acquired[LEFT],
@ -137,7 +97,7 @@ namespace Audio_out {
public: public:
Session_component(Channel_number channel, size_t buffer_size, Session_component(Channel_number channel, size_t buffer_size,
Rpc_entrypoint &ep, Signal_receiver *sig_rec) Rpc_entrypoint &ep, Signal_receiver &sig_rec)
: Session_rpc_object(_alloc_dataspace(buffer_size), ep), _channel(channel), : Session_rpc_object(_alloc_dataspace(buffer_size), ep), _channel(channel),
_process_packet_dispatcher(sig_rec, *this, _process_packet_dispatcher(sig_rec, *this,
&Session_component::_process_packets) &Session_component::_process_packets)
@ -233,7 +193,7 @@ namespace Audio_out {
private: private:
Rpc_entrypoint &_channel_ep; Rpc_entrypoint &_channel_ep;
Signal_receiver *_sig_rec; Signal_receiver &_sig_rec;
protected: protected:
@ -258,8 +218,8 @@ namespace Audio_out {
public: public:
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc, Signal_receiver *sig_rec) Root(Rpc_entrypoint &session_ep, Allocator *md_alloc, Signal_receiver &sig_rec)
: Root_component(session_ep, md_alloc), _channel_ep(*session_ep), _sig_rec(sig_rec) : Root_component(&session_ep, md_alloc), _channel_ep(session_ep), _sig_rec(sig_rec)
{ } { }
}; };
} }
@ -282,7 +242,7 @@ int main()
audio_out_active = audio_init() ? false : true; audio_out_active = audio_init() ? false : true;
if (audio_out_active) { if (audio_out_active) {
static Audio_out::Root audio_root(&ep, env()->heap(), &recv); static Audio_out::Root audio_root(ep, env()->heap(), recv);
env()->parent()->announce(ep.manage(&audio_root)); env()->parent()->announce(ep.manage(&audio_root));
} }

View File

@ -49,53 +49,6 @@ static bool const verbose = false;
#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__) #define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
/*************************************
** Helpers for dispatching signals **
*************************************/
namespace Genode {
struct Signal_dispatcher_base : Signal_context
{
virtual void dispatch(int num) = 0;
};
template <typename T>
class Signal_dispatcher : private Signal_dispatcher_base,
public Signal_context_capability
{
private:
T &obj;
void (T::*member) (int);
Signal_receiver &sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Signal_receiver &sig_rec,
T &obj, void (T::*member)(int))
:
Signal_context_capability(sig_rec.manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec.dissolve(this); }
void dispatch(int num) { (obj.*member)(num); }
};
}
/************************* /*************************
** File-system service ** ** File-system service **
*************************/ *************************/
@ -180,7 +133,7 @@ namespace File_system {
* Called by signal dispatcher, executed in the context of the main * Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions) * thread (not serialized with the RPC functions)
*/ */
void _process_packets(int) void _process_packets(unsigned)
{ {
while (tx_sink()->packet_avail()) { while (tx_sink()->packet_avail()) {
@ -255,7 +208,7 @@ namespace File_system {
Mode mode, bool create) Mode mode, bool create)
{ {
PDBGV("_root = %s, dir_name = %s, name = %s, create = %d", PDBGV("_root = %s, dir_name = %s, name = %s, create = %d",
_root.name(), _root.name(),
_handle_registry.lookup(dir_handle)->name(), _handle_registry.lookup(dir_handle)->name(),
name.string(), name.string(),
create); create);

View File

@ -225,7 +225,7 @@ namespace Iso {
try { try {
Signal signal = _receiver.wait_for_signal(); Signal signal = _receiver.wait_for_signal();
for (int i = 0; i < signal.num(); i++) for (unsigned i = 0; i < signal.num(); i++)
static_cast<File *>(signal.context())->handle_fault(); static_cast<File *>(signal.context())->handle_fault();
} catch (...) { } catch (...) {
PDBG("unexpected error while waiting for signal"); PDBG("unexpected error while waiting for signal");

View File

@ -26,53 +26,6 @@
#include <node_handle_registry.h> #include <node_handle_registry.h>
/*************************************
** Helpers for dispatching signals **
*************************************/
namespace Genode {
struct Signal_dispatcher_base : Signal_context
{
virtual void dispatch(int num) = 0;
};
template <typename T>
class Signal_dispatcher : private Signal_dispatcher_base,
public Signal_context_capability
{
private:
T &obj;
void (T::*member) (int);
Signal_receiver &sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Signal_receiver &sig_rec,
T &obj, void (T::*member)(int))
:
Signal_context_capability(sig_rec.manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec.dissolve(this); }
void dispatch(int num) { (obj.*member)(num); }
};
}
/************************* /*************************
** File-system service ** ** File-system service **
*************************/ *************************/
@ -155,7 +108,7 @@ namespace File_system {
* Called by signal dispatcher, executed in the context of the main * Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions) * thread (not serialized with the RPC functions)
*/ */
void _process_packets(int) void _process_packets(unsigned)
{ {
while (tx_sink()->packet_avail()) { while (tx_sink()->packet_avail()) {

View File

@ -36,53 +36,6 @@ static bool const verbose = false;
#define PDBGV(...) if (verbose) PDBG(__VA_ARGS__) #define PDBGV(...) if (verbose) PDBG(__VA_ARGS__)
/*************************************
** Helpers for dispatching signals **
*************************************/
namespace Genode {
struct Signal_dispatcher_base : Signal_context
{
virtual void dispatch(int num) = 0;
};
template <typename T>
class Signal_dispatcher : private Signal_dispatcher_base,
public Signal_context_capability
{
private:
T &obj;
void (T::*member) (int);
Signal_receiver &sig_rec;
public:
/**
* Constructor
*
* \param sig_rec signal receiver to associate the signal
* handler with
* \param obj,member object and member function to call when
* the signal occurs
*/
Signal_dispatcher(Signal_receiver &sig_rec,
T &obj, void (T::*member)(int))
:
Signal_context_capability(sig_rec.manage(this)),
obj(obj), member(member),
sig_rec(sig_rec)
{ }
~Signal_dispatcher() { sig_rec.dissolve(this); }
void dispatch(int num) { (obj.*member)(num); }
};
}
/************************* /*************************
** File-system service ** ** File-system service **
*************************/ *************************/
@ -167,7 +120,7 @@ namespace File_system {
* Called by signal dispatcher, executed in the context of the main * Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions) * thread (not serialized with the RPC functions)
*/ */
void _process_packets(int) void _process_packets(unsigned)
{ {
while (tx_sink()->packet_avail()) { while (tx_sink()->packet_avail()) {
@ -241,7 +194,7 @@ namespace File_system {
Mode mode, bool create) Mode mode, bool create)
{ {
PDBGV("_root = %s, dir_name = %s, name = %s, create = %d", PDBGV("_root = %s, dir_name = %s, name = %s, create = %d",
_root.record()->name(), _root.record()->name(),
_handle_registry.lookup(dir_handle)->record()->name(), _handle_registry.lookup(dir_handle)->record()->name(),
name.string(), name.string(),
create); create);

View File

@ -32,31 +32,22 @@ int main(int, char **)
{ {
parse_config(); parse_config();
struct Signal_dispatcher : public Genode::Signal_context
{
void dispatch()
{
try {
Genode::config()->reload();
parse_config();
} catch (Genode::Config::Invalid) {
PERR("Error: reloading config failed");
}
}
} signal_dispatcher;
static Genode::Signal_receiver sig_rec;
/* register signal handler for config changes */ /* register signal handler for config changes */
Genode::config()->sigh(sig_rec.manage(&signal_dispatcher)); Genode::Signal_receiver sig_rec;
Genode::Signal_context sig_ctx;
Genode::config()->sigh(sig_rec.manage(&sig_ctx));
for (;;) { for (;;) {
/* wait for config change */ /* wait for config change */
Genode::Signal signal = sig_rec.wait_for_signal(); sig_rec.wait_for_signal();
for (int i = 0; i < signal.num(); i++) try {
static_cast<Signal_dispatcher *>(signal.context())->dispatch(); Genode::config()->reload();
parse_config();
} catch (Genode::Config::Invalid) {
PERR("Error: reloading config failed");
}
} }
return 0; return 0;
} }

View File

@ -55,7 +55,7 @@ class Pager : public Thread<8192>
while (true) { while (true) {
Signal signal = _receiver.wait_for_signal(); Signal signal = _receiver.wait_for_signal();
for (int i = 0; i < signal.num(); i++) for (unsigned i = 0; i < signal.num(); i++)
handle_fault(); handle_fault();
} }
} }

View File

@ -133,7 +133,7 @@ class Handler : Thread<4096>
Signal signal = _receiver->wait_for_signal(); Signal signal = _receiver->wait_for_signal();
if (_verbose) if (_verbose)
printf("handler %d got %d signal%s with context %p\n", printf("handler %d got %u signal%s with context %p\n",
_id, _id,
signal.num(), signal.num(),
signal.num() == 1 ? "" : "s", signal.num() == 1 ? "" : "s",
@ -191,12 +191,12 @@ class Handler : Thread<4096>
/** /**
* Return total number of received notifications * Return total number of received notifications
*/ */
unsigned receive_cnt() { return _receive_cnt; } unsigned receive_cnt() const { return _receive_cnt; }
/** /**
* Return total number of signal-handler activations * Return total number of signal-handler activations
*/ */
unsigned activation_cnt() { return _activation_cnt; } unsigned activation_cnt() const { return _activation_cnt; }
}; };
@ -242,7 +242,7 @@ class Id_signal_context : public Signal_context
Id_signal_context(int id) : _id(id) { } Id_signal_context(int id) : _id(id) { }
int id() { return _id; } int id() const { return _id; }
}; };

View File

@ -23,7 +23,6 @@
/* Noux includes */ /* Noux includes */
#include <file_descriptor_registry.h> #include <file_descriptor_registry.h>
#include <dir_file_system.h> #include <dir_file_system.h>
#include <signal_dispatcher.h>
#include <noux_session/capability.h> #include <noux_session/capability.h>
#include <args.h> #include <args.h>
#include <environment.h> #include <environment.h>
@ -88,7 +87,7 @@ namespace Noux {
/** /**
* Signal context used for child exit * Signal context used for child exit
*/ */
class Child_exit_dispatcher : public Signal_dispatcher class Child_exit_dispatcher : public Signal_dispatcher_base
{ {
private: private:
@ -98,7 +97,7 @@ namespace Noux {
Child_exit_dispatcher(Child *child) : _child(child) { } Child_exit_dispatcher(Child *child) : _child(child) { }
void dispatch() void dispatch(unsigned)
{ {
if (is_init_process(_child)) { if (is_init_process(_child)) {
PINF("init process exited"); PINF("init process exited");
@ -121,7 +120,7 @@ namespace Noux {
/** /**
* Signal context used for removing the child after having executed 'execve' * Signal context used for removing the child after having executed 'execve'
*/ */
class Child_execve_cleanup_dispatcher : public Signal_dispatcher class Child_execve_cleanup_dispatcher : public Signal_dispatcher_base
{ {
private: private:
@ -131,7 +130,7 @@ namespace Noux {
Child_execve_cleanup_dispatcher(Child *child) : _child(child) { } Child_execve_cleanup_dispatcher(Child *child) : _child(child) { }
void dispatch() void dispatch(unsigned)
{ {
destroy(env()->heap(), _child); destroy(env()->heap(), _child);
} }

View File

@ -897,11 +897,11 @@ int main(int argc, char **argv)
Genode::Signal signal = sig_rec.wait_for_signal(); Genode::Signal signal = sig_rec.wait_for_signal();
Signal_dispatcher *dispatcher = Signal_dispatcher_base *dispatcher =
static_cast<Signal_dispatcher *>(signal.context()); static_cast<Signal_dispatcher_base *>(signal.context());
for (int i = 0; i < signal.num(); i++) for (unsigned i = 0; i < signal.num(); i++)
dispatcher->dispatch(); dispatcher->dispatch(1);
} }
PINF("-- exiting noux ---"); PINF("-- exiting noux ---");

View File

@ -207,7 +207,7 @@ namespace Noux {
}; };
class Pipe_sink_io_channel : public Io_channel, public Signal_dispatcher class Pipe_sink_io_channel : public Io_channel, public Signal_dispatcher_base
{ {
private: private:
@ -258,21 +258,21 @@ namespace Noux {
return true; return true;
} }
/********************************* /**************************************
** Signal_dispatcher interface ** ** Signal_dispatcher_base interface **
*********************************/ **************************************/
/** /**
* Called by Noux main loop on the occurrence of new STDIN input * Called by Noux main loop on the occurrence of new STDIN input
*/ */
void dispatch() void dispatch(unsigned)
{ {
Io_channel::invoke_all_notifiers(); Io_channel::invoke_all_notifiers();
} }
}; };
class Pipe_source_io_channel : public Io_channel, public Signal_dispatcher class Pipe_source_io_channel : public Io_channel, public Signal_dispatcher_base
{ {
private: private:
@ -320,14 +320,14 @@ namespace Noux {
return true; return true;
} }
/********************************* /**************************************
** Signal_dispatcher interface ** ** Signal_dispatcher_base interface **
*********************************/ **************************************/
/** /**
* Called by Noux main loop on the occurrence of new STDIN input * Called by Noux main loop on the occurrence of new STDIN input
*/ */
void dispatch() void dispatch(unsigned)
{ {
Io_channel::invoke_all_notifiers(); Io_channel::invoke_all_notifiers();
} }

View File

@ -1,28 +0,0 @@
/*
* \brief Abstract interface for dispatching signals
* \author Norman Feske
* \date 2011-02-17
*/
/*
* Copyright (C) 2011-2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _NOUX__SIGNAL_DISPATCHER_H_
#define _NOUX__SIGNAL_DISPATCHER_H_
/* Genode includes */
#include <base/signal.h>
namespace Noux {
struct Signal_dispatcher : public Signal_context
{
virtual void dispatch() = 0;
};
}
#endif /* _NOUX__SIGNAL_DISPATCHER_H_ */

View File

@ -25,7 +25,7 @@
namespace Noux { namespace Noux {
struct Terminal_io_channel : Io_channel, Signal_dispatcher struct Terminal_io_channel : Io_channel, Signal_dispatcher_base
{ {
Terminal::Session &terminal; Terminal::Session &terminal;
Signal_receiver &sig_rec; Signal_receiver &sig_rec;
@ -185,14 +185,14 @@ namespace Noux {
} }
/********************************* /**************************************
** Signal_dispatcher interface ** ** Signal_dispatcher_base interface **
*********************************/ **************************************/
/** /**
* Called by Noux main loop on the occurrence of new STDIN input * Called by Noux main loop on the occurrence of new STDIN input
*/ */
void dispatch() void dispatch(unsigned)
{ {
Io_channel::invoke_all_notifiers(); Io_channel::invoke_all_notifiers();
} }