genode/repos/base-hw/src/core/signal_broker.h

151 lines
3.5 KiB
C++

/*
* \brief Base-hw-specific signal-delivery mechanism
* \author Norman Feske
* \date 2016-01-04
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _CORE__SIGNAL_BROKER_H_
#define _CORE__SIGNAL_BROKER_H_
/* Genode includes */
#include <base/tslab.h>
/* core-local includes */
#include <signal_source_component.h>
namespace Genode { class Signal_broker; }
class Genode::Signal_broker
{
private:
template <typename T, size_t BLOCK_SIZE = get_page_size()>
class Slab : public Tslab<T, BLOCK_SIZE>
{
private:
uint8_t _first_block[BLOCK_SIZE];
public:
Slab(Allocator * const allocator)
: Tslab<T, BLOCK_SIZE>(allocator, &_first_block) { }
};
Allocator &_md_alloc;
Slab<Signal_source_component> _sources_slab { &_md_alloc };
Signal_source_pool _sources { };
Slab<Signal_context_component> _contexts_slab { &_md_alloc };
Signal_context_pool _contexts { };
public:
class Invalid_signal_source : public Exception { };
Signal_broker(Allocator &md_alloc, Rpc_entrypoint &, Rpc_entrypoint &)
:
_md_alloc(md_alloc)
{ }
~Signal_broker()
{
_contexts.remove_all([this] (Signal_context_component *c) {
destroy(&_contexts_slab, c);});
_sources.remove_all([this] (Signal_source_component *s) {
destroy(&_sources_slab, s);});
}
/*
* \throw Allocator::Out_of_memory
*/
Capability<Signal_source> alloc_signal_source()
{
/* the _sources_slab may throw Allocator::Out_of_memory */
Signal_source_component *s = new (_sources_slab) Signal_source_component();
_sources.insert(s);
return reinterpret_cap_cast<Signal_source>(s->cap());
}
void free_signal_source(Capability<Signal_source> cap)
{
Signal_source_component *source = nullptr;
auto lambda = [&] (Signal_source_component *s) {
if (!s) {
error("unknown signal source");
return;
}
source = s;
_sources.remove(source);
};
_sources.apply(cap, lambda);
/* destruct signal source outside the lambda to prevent deadlock */
if (source)
destroy(&_sources_slab, source);
}
/*
* \throw Allocator::Out_of_memory
* \throw Invalid_signal_source
*/
Signal_context_capability
alloc_context(Capability<Signal_source> source, addr_t imprint)
{
auto lambda = [&] (Signal_source_component *s) {
if (!s) {
error("unknown signal source");
throw Invalid_signal_source();
}
/* the _contexts_slab may throw Allocator::Out_of_memory */
Signal_context_component *c = new (_contexts_slab)
Signal_context_component(*s, imprint);
_contexts.insert(c);
return reinterpret_cap_cast<Signal_context>(c->cap());
};
return _sources.apply(source, lambda);
}
void free_context(Signal_context_capability context_cap)
{
Signal_context_component *context = nullptr;
auto lambda = [&] (Signal_context_component *c) {
if (!c) {
error("unknown signal context");
return;
}
context = c;
_contexts.remove(context);
};
_contexts.apply(context_cap, lambda);
/* destruct context outside the lambda to prevent deadlock */
if (context)
destroy(&_contexts_slab, context);
}
void submit(Signal_context_capability, unsigned)
{
/*
* This function is never called as base-hw delivers signals
* directly via the kernel.
*/
}
};
#endif /* _CORE__SIGNAL_BROKER_H_ */