genode/repos/base-hw/src/core/include/signal_session_component.h

221 lines
5.1 KiB
C++

/*
* \brief Server-sided implementation of a signal session
* \author Martin stein
* \date 2012-05-05
*/
/*
* Copyright (C) 2012-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 _CORE__INCLUDE__SIGNAL_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__SIGNAL_SESSION_COMPONENT_H_
/* Genode includes */
#include <signal_session/signal_session.h>
#include <base/rpc_server.h>
#include <base/slab.h>
#include <base/allocator_guard.h>
#include <base/object_pool.h>
/* core includes */
#include <kernel/signal_receiver.h>
#include <util.h>
namespace Genode
{
/**
* Combines kernel data and core data of an object a signal session manages
*
* \param T type of the kernel data
*/
template <typename T>
class Signal_session_object;
typedef Signal_session_object<Kernel::Signal_receiver>
Signal_session_receiver;
typedef Signal_session_object<Kernel::Signal_context>
Signal_session_context;
/**
* Traits that are used in signal session components
*
* FIXME: This class is merely necessary because GCC 4.7.2 appears to have
* a problem with using a static-constexpr method for the
* dimensioning of a member array within the same class.
*/
class Signal_session_traits;
/**
* Server-sided implementation of a signal session
*/
class Signal_session_component;
}
template <typename T>
class Genode::Signal_session_object
:
public Object_pool<Signal_session_object<T> >::Entry
{
public:
typedef Object_pool<Signal_session_object<T> > Pool;
/**
* Constructor
*/
Signal_session_object(Untyped_capability cap) : Pool::Entry(cap) { }
/**
* Kernel name of the object
*/
unsigned id() const { return Pool::Entry::cap().dst(); }
/**
* Size of the data starting at the base of this object
*/
static constexpr size_t size()
{
return sizeof(Signal_session_object<T>) + sizeof(T);
}
/**
* Base of the kernel donation associated with a specific SLAB address
*
* \param slab_addr SLAB address
*/
static constexpr addr_t kernel_donation(void * const slab_addr)
{
return (addr_t)slab_addr + sizeof(Signal_session_object<T>);
}
};
class Genode::Signal_session_traits
{
private:
/**
* Return the raw size of a slab
*/
static constexpr size_t _slab_raw() { return get_page_size(); }
/**
* Return the size of the static buffer for meta data per slab
*/
static constexpr size_t _slab_buffer() { return 128; }
/**
* Return the size available for allocations per slab
*/
static constexpr size_t _slab_avail() { return _slab_raw() - _slab_buffer(); }
/**
* Return the amount of allocatable slots per slab
*
* \param T object type of the slab
*/
template <typename T>
static constexpr size_t _slab_slots() { return _slab_avail() / T::size(); }
protected:
/**
* Return the size of allocatable space per slab
*
* \param T object type of the slab
*/
template <typename T>
static constexpr size_t _slab_size() { return _slab_slots<T>() * T::size(); }
};
class Genode::Signal_session_component
:
public Rpc_object<Signal_session>,
public Signal_session_traits
{
private:
typedef Signal_session_receiver Receiver;
typedef Signal_session_context Context;
typedef Signal_session_traits Traits;
Allocator_guard _allocator;
Slab _receivers_slab;
Receiver::Pool _receivers;
Slab _contexts_slab;
Context::Pool _contexts;
char _first_receivers_slab [Traits::_slab_size<Receiver>()];
char _first_contexts_slab [Traits::_slab_size<Context>()];
/**
* Destruct receiver 'r'
*/
void _destruct_receiver(Receiver * const r);
/**
* Destruct context 'c'
*/
void _destruct_context(Context * const c);
public:
/**
* Constructor
*
* \param allocator RAM allocator for meta data
* \param quota amount of RAM quota donated to this session
*/
Signal_session_component(Allocator * const allocator,
size_t const quota)
:
_allocator(allocator, quota),
_receivers_slab(Receiver::size(), Traits::_slab_size<Receiver>(),
(Slab_block *)&_first_receivers_slab, &_allocator),
_contexts_slab(Context::size(), Traits::_slab_size<Context>(),
(Slab_block *)&_first_contexts_slab, &_allocator)
{ }
/**
* Destructor
*/
~Signal_session_component()
{
while (1) {
Context * const c = _contexts.first_locked();
if (!c) { break; }
_destruct_context(c);
}
while (1) {
Receiver * const r = _receivers.first_locked();
if (!r) { break; }
_destruct_receiver(r);
}
}
/**
* Raise the quota of this session by 'q'
*/
void upgrade_ram_quota(size_t const q) { _allocator.upgrade(q); }
/******************************
** Signal_session interface **
******************************/
Signal_receiver_capability alloc_receiver();
Signal_context_capability
alloc_context(Signal_receiver_capability, unsigned const);
void free_receiver(Signal_receiver_capability);
void free_context(Signal_context_capability);
};
#endif /* _CORE__INCLUDE__SIGNAL_SESSION_COMPONENT_H_ */