genode/repos/base/include/base/signal.h

401 lines
9.9 KiB
C++

/*
* \brief Delivery and reception of asynchronous notifications
* \author Norman Feske
* \date 2008-09-05
*
* Each transmitter sends signals to one fixed destination.
* A receiver can receive signals from multiple sources.
*/
/*
* Copyright (C) 2008-2013 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 _INCLUDE__BASE__SIGNAL_H__
#define _INCLUDE__BASE__SIGNAL_H__
#include <util/noncopyable.h>
#include <util/list.h>
#include <base/semaphore.h>
#include <signal_session/signal_session.h>
/* only needed for base-hw */
namespace Kernel { struct Signal_receiver; }
namespace Genode {
class Signal_source;
class Signal_receiver;
class Signal_context;
class Signal_context_registry;
class Signal_transmitter;
class Signal;
class Signal_dispatcher_base;
template <typename> class Signal_dispatcher;
}
/**
* Signal
*
* A signal represents a number of asynchronous notifications produced by
* one transmitter. If notifications are generated at a higher rate than as
* they can be processed at the receiver, the transmitter counts the
* notifications and delivers the total amount with the next signal
* transmission. This way, the total number of notifications gets properly
* communicated to the receiver even if the receiver is not highly
* responsive.
*
* Asynchronous notifications do not carry any payload because this payload
* would need to be queued at the transmitter. However, each transmitter
* imprints a signal-context reference into each signal. This context
* can be used by the receiver to distinguish signals coming from different
* transmitters.
*/
class Genode::Signal
{
private:
struct Data
{
Signal_context *context;
unsigned num;
/**
* Constructor
*
* \param context signal context specific for the
* signal-receiver capability used for signal
* transmission
* \param num number of signals received from the same
* transmitter
*/
Data(Signal_context *context, unsigned num)
: context(context), num(num) { }
/**
* Default constructor, representing an invalid signal
*/
Data() : context(0), num(0) { }
} _data;
/**
* Constructor
*
* Signal objects are constructed by signal receivers only.
*/
Signal(Data data);
friend class Kernel::Signal_receiver;
friend class Signal_receiver;
friend class Signal_context;
void _dec_ref_and_unlock();
void _inc_ref();
public:
Signal(Signal const &other);
Signal &operator=(Signal const &other);
~Signal();
Signal_context *context() { return _data.context; }
unsigned num() const { return _data.num; }
};
/**
* Signal transmitter
*
* Each signal-transmitter instance acts on behalf the context specified
* as constructor argument. Therefore, the resources needed for the
* transmitter such as the consumed memory 'sizeof(Signal_transmitter)'
* should be accounted to the owner of the context.
*/
class Genode::Signal_transmitter
{
private:
Signal_context_capability _context; /* destination */
public:
/**
* Constructor
*
* \param context capability to signal context that is going to
* receive signals produced by the transmitter
*/
Signal_transmitter(Signal_context_capability context = Signal_context_capability());
/**
* Set signal context
*/
void context(Signal_context_capability context);
/**
* Return signal context
*/
Signal_context_capability context();
/**
* Trigger signal submission to context
*
* \param cnt number of signals to submit at once
*/
void submit(unsigned cnt = 1);
};
/**
* Signal receiver
*/
class Genode::Signal_receiver : Noncopyable
{
private:
/**
* Semaphore used to indicate that signal(s) are ready to be picked
* up. This is needed for platforms other than 'base-hw' only.
*/
Semaphore _signal_available;
/**
* Provides the kernel-object name via the 'dst' method. This is
* needed for 'base-hw' only.
*/
Signal_receiver_capability _cap;
/**
* List of associated contexts
*/
Lock _contexts_lock;
List<List_element<Signal_context> > _contexts;
/**
* Helper to dissolve given context
*
* This function prevents duplicated code in '~Signal_receiver'
* and 'dissolve'. Note that '_contexts_lock' must be held when
* calling this function.
*/
void _unsynchronized_dissolve(Signal_context *context);
/**
* Hook to platform specific destructor parts
*/
void _platform_destructor();
public:
/**
* Exception class
*/
class Context_already_in_use { };
class Context_not_associated { };
/**
* Constructor
*/
Signal_receiver();
/**
* Destructor
*/
~Signal_receiver();
/**
* Manage signal context and return new signal-context capability
*
* \param context context associated with signals delivered to the
* receiver
* \throw 'Context_already_in_use'
* \return new signal-context capability that can be
* passed to a signal transmitter
*/
Signal_context_capability manage(Signal_context *context);
/**
* Dissolve signal context from receiver
*
* \param context context to remove from receiver
* \throw 'Context_not_associated'
*/
void dissolve(Signal_context *context);
/**
* Return true if signal was received
*/
bool pending();
/**
* Block until a signal is received
*
* \return received signal
*/
Signal wait_for_signal();
/**
* Locally submit signal to the receiver
*/
void local_submit(Signal::Data signal);
/**
* Framework-internal signal-dispatcher
*
* This function is called from the thread that monitors the signal
* source associated with the process. It must not be used for other
* purposes.
*/
static void dispatch_signals(Signal_source *signal_source);
};
/**
* Signal context
*
* A signal context is a destination for signals. One receiver can listen
* to multple contexts. If a signal arrives, the context is provided with the
* signel. This enables the receiver to distinguish different signal sources
* and dispatch incoming signals context-specific.
*/
class Genode::Signal_context
{
private:
/**
* List element in 'Signal_receiver'
*/
List_element<Signal_context> _receiver_le;
/**
* List element in process-global registry
*/
List_element<Signal_context> _registry_le;
/**
* Receiver to which the context is associated with
*
* This member is initialized by the receiver when associating
* the context with the receiver via the 'cap' function.
*/
Signal_receiver *_receiver;
Lock _lock; /* protect '_curr_signal' */
Signal::Data _curr_signal; /* most-currently received signal */
bool _pending; /* current signal is valid */
unsigned int _ref_cnt; /* number of references to this context */
Lock _destroy_lock; /* prevent destruction while the
context is in use */
/**
* Capability assigned to this context after being assocated with
* a 'Signal_receiver' via the 'manage' function. We store this
* capability in the 'Signal_context' for the mere reason to
* properly destruct the context (see '_unsynchronized_dissolve').
*/
Signal_context_capability _cap;
friend class Signal;
friend class Signal_receiver;
friend class Signal_context_registry;
public:
/**
* Constructor
*/
Signal_context()
: _receiver_le(this), _registry_le(this),
_receiver(0), _pending(0), _ref_cnt(0) { }
/**
* Destructor
*
* The virtual destructor is just there to generate a vtable for
* signal-context objects such that signal contexts can be dynamically
* casted.
*/
virtual ~Signal_context();
/**
* Local signal submission (DEPRECATED)
*
* Trigger local signal submission (within the same address space), the
* context has to be bound to a sginal receiver beforehand.
*
* \param num number of pending signals
*/
void submit(unsigned num);
/*
* Signal contexts are never invoked but only used as arguments for
* 'Signal_session' functions. Hence, there exists a capability
* type for it but no real RPC interface.
*/
GENODE_RPC_INTERFACE();
};
/**
* Abstract interface to be implemented by signal dispatchers
*/
struct Genode::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 Genode::Signal_dispatcher : public 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__ */