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;
Signal_context *_context;
int _num;
unsigned _num;
/**
* Constructor
@ -63,7 +63,7 @@ namespace Genode {
*
* Signal objects are constructed only by signal receivers.
*/
Signal(Signal_context *context, int num)
Signal(Signal_context *context, unsigned num)
: _context(context), _num(num)
{ }
@ -82,7 +82,7 @@ namespace Genode {
/**
* 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
*/
void submit(int cnt = 1);
void submit(unsigned cnt = 1);
};
@ -282,6 +282,61 @@ namespace Genode {
*/
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__ */

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);
}
@ -347,7 +347,7 @@ void Signal_receiver::local_submit(Signal ns)
* counters. In the common case, the current signal is an invalid
* 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);
/* wake up the receiver if the context becomes pending */

View File

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

View File

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

View File

@ -17,40 +17,6 @@
#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
@ -60,11 +26,11 @@ class Packet_session_component : public RPC
{
private:
Signal_dispatcher<Packet_session_component> _process_packet_dispatcher;
Genode::Signal_dispatcher<Packet_session_component> _process_packet_dispatcher;
protected:
virtual void _process_packets() = 0;
virtual void _process_packets(unsigned) = 0;
public:
@ -73,7 +39,7 @@ class Packet_session_component : public RPC
Genode::Signal_receiver *sig_rec)
:
RPC(tx_ds, ep),
_process_packet_dispatcher(sig_rec, *this,
_process_packet_dispatcher(*sig_rec, *this,
&Packet_session_component::_process_packets)
{
/*
@ -91,7 +57,7 @@ class Packet_session_component : public RPC
Genode::Signal_receiver *sig_rec)
:
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)
{
/*

View File

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

View File

@ -31,46 +31,6 @@ static const bool verbose = 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 {
class Session_component;
@ -94,7 +54,7 @@ namespace Audio_out {
return _ds;
}
void _process_packets()
void _process_packets(unsigned)
{
/* handle audio-out packets */
Session_component *left = channel_acquired[LEFT],
@ -137,7 +97,7 @@ namespace Audio_out {
public:
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),
_process_packet_dispatcher(sig_rec, *this,
&Session_component::_process_packets)
@ -233,7 +193,7 @@ namespace Audio_out {
private:
Rpc_entrypoint &_channel_ep;
Signal_receiver *_sig_rec;
Signal_receiver &_sig_rec;
protected:
@ -258,8 +218,8 @@ namespace Audio_out {
public:
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(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)
{ }
};
}
@ -282,7 +242,7 @@ int main()
audio_out_active = audio_init() ? false : true;
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));
}

View File

@ -49,53 +49,6 @@ static bool const verbose = false;
#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 **
*************************/
@ -180,7 +133,7 @@ namespace File_system {
* Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions)
*/
void _process_packets(int)
void _process_packets(unsigned)
{
while (tx_sink()->packet_avail()) {
@ -255,7 +208,7 @@ namespace File_system {
Mode mode, bool create)
{
PDBGV("_root = %s, dir_name = %s, name = %s, create = %d",
_root.name(),
_root.name(),
_handle_registry.lookup(dir_handle)->name(),
name.string(),
create);

View File

@ -225,7 +225,7 @@ namespace Iso {
try {
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();
} catch (...) {
PDBG("unexpected error while waiting for signal");

View File

@ -26,53 +26,6 @@
#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 **
*************************/
@ -155,7 +108,7 @@ namespace File_system {
* Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions)
*/
void _process_packets(int)
void _process_packets(unsigned)
{
while (tx_sink()->packet_avail()) {

View File

@ -36,53 +36,6 @@ static bool const verbose = false;
#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 **
*************************/
@ -167,7 +120,7 @@ namespace File_system {
* Called by signal dispatcher, executed in the context of the main
* thread (not serialized with the RPC functions)
*/
void _process_packets(int)
void _process_packets(unsigned)
{
while (tx_sink()->packet_avail()) {
@ -241,7 +194,7 @@ namespace File_system {
Mode mode, bool create)
{
PDBGV("_root = %s, dir_name = %s, name = %s, create = %d",
_root.record()->name(),
_root.record()->name(),
_handle_registry.lookup(dir_handle)->record()->name(),
name.string(),
create);

View File

@ -32,31 +32,22 @@ int main(int, char **)
{
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 */
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 (;;) {
/* 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++)
static_cast<Signal_dispatcher *>(signal.context())->dispatch();
try {
Genode::config()->reload();
parse_config();
} catch (Genode::Config::Invalid) {
PERR("Error: reloading config failed");
}
}
return 0;
}

View File

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

View File

@ -133,7 +133,7 @@ class Handler : Thread<4096>
Signal signal = _receiver->wait_for_signal();
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,
signal.num(),
signal.num() == 1 ? "" : "s",
@ -191,12 +191,12 @@ class Handler : Thread<4096>
/**
* 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
*/
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) { }
int id() { return _id; }
int id() const { return _id; }
};

View File

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

View File

@ -897,11 +897,11 @@ int main(int argc, char **argv)
Genode::Signal signal = sig_rec.wait_for_signal();
Signal_dispatcher *dispatcher =
static_cast<Signal_dispatcher *>(signal.context());
Signal_dispatcher_base *dispatcher =
static_cast<Signal_dispatcher_base *>(signal.context());
for (int i = 0; i < signal.num(); i++)
dispatcher->dispatch();
for (unsigned i = 0; i < signal.num(); i++)
dispatcher->dispatch(1);
}
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:
@ -258,21 +258,21 @@ namespace Noux {
return true;
}
/*********************************
** Signal_dispatcher interface **
*********************************/
/**************************************
** Signal_dispatcher_base interface **
**************************************/
/**
* Called by Noux main loop on the occurrence of new STDIN input
*/
void dispatch()
void dispatch(unsigned)
{
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:
@ -320,14 +320,14 @@ namespace Noux {
return true;
}
/*********************************
** Signal_dispatcher interface **
*********************************/
/**************************************
** Signal_dispatcher_base interface **
**************************************/
/**
* Called by Noux main loop on the occurrence of new STDIN input
*/
void dispatch()
void dispatch(unsigned)
{
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 {
struct Terminal_io_channel : Io_channel, Signal_dispatcher
struct Terminal_io_channel : Io_channel, Signal_dispatcher_base
{
Terminal::Session &terminal;
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
*/
void dispatch()
void dispatch(unsigned)
{
Io_channel::invoke_all_notifiers();
}