hw: optimize ipc capability allocation

In preparation of ipc receive, by now a bunch of capabilities got
allocated to be ready iin case of capability receiption. After that
unuse slots were freed again. This overhead of senseless (de-)allocations
is replaced in this commit by just restock capability slots that got
used by the last receive.

Fix #3640
This commit is contained in:
Stefan Kalkowski 2020-02-05 16:42:39 +01:00 committed by Christian Helmuth
parent e42a205a51
commit 725d16e18e
4 changed files with 38 additions and 39 deletions

View File

@ -35,19 +35,34 @@ extern "C" void _core_start(void);
using namespace Kernel; using namespace Kernel;
static inline void free_obj_id_ref(Pd &pd, void *ptr)
void Thread::_ipc_alloc_recv_caps(unsigned cap_count)
{ {
pd.platform_pd().capability_slab().free(ptr, sizeof(Object_identity_reference)); Genode::Allocator &slab = pd().platform_pd().capability_slab();
for (unsigned i = 0; i < cap_count; i++) {
if (_obj_id_ref_ptr[i] == nullptr)
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
}
_ipc_rcv_caps = cap_count;
}
void Thread::_ipc_free_recv_caps()
{
for (unsigned i = 0; i < _ipc_rcv_caps; i++) {
if (_obj_id_ref_ptr[i]) {
Genode::Allocator &slab = pd().platform_pd().capability_slab();
slab.free(_obj_id_ref_ptr[i], sizeof(Object_identity_reference));
}
}
_ipc_rcv_caps = 0;
} }
void Thread::_ipc_init(Genode::Native_utcb &utcb, Thread &starter) void Thread::_ipc_init(Genode::Native_utcb &utcb, Thread &starter)
{ {
_utcb = &utcb; _utcb = &utcb;
_ipc_rcv_caps = starter._utcb->cap_cnt(); _ipc_alloc_recv_caps(starter._utcb->cap_cnt());
Genode::Allocator &slab = pd().platform_pd().capability_slab();
for (unsigned i = 0; i < _ipc_rcv_caps; i++)
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
ipc_copy_msg(starter); ipc_copy_msg(starter);
} }
@ -66,20 +81,16 @@ void Thread::ipc_copy_msg(Thread &sender)
capid_t id = sender._utcb->cap_get(i); capid_t id = sender._utcb->cap_get(i);
/* if there is no capability to send, just free the pre-allocation */ /* if there is no capability to send, nothing to do */
if (i >= sender._utcb->cap_cnt()) { if (i >= sender._utcb->cap_cnt()) { continue; }
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
continue;
}
/* lookup the capability id within the caller's cap space */ /* lookup the capability id within the caller's cap space */
Reference *oir = (id == cap_id_invalid()) Reference *oir = (id == cap_id_invalid())
? nullptr : sender.pd().cap_tree().find(id); ? nullptr : sender.pd().cap_tree().find(id);
/* if the caller's capability is invalid, free the pre-allocation */ /* if the caller's capability is invalid, continue */
if (!oir) { if (!oir) {
_utcb->cap_add(cap_id_invalid()); _utcb->cap_add(cap_id_invalid());
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
continue; continue;
} }
@ -89,10 +100,8 @@ void Thread::ipc_copy_msg(Thread &sender)
/* if it is not found, and the target is not core, create a reference */ /* if it is not found, and the target is not core, create a reference */
if (!dst_oir && (&pd() != &core_pd())) { if (!dst_oir && (&pd() != &core_pd())) {
dst_oir = oir->factory(_obj_id_ref_ptr[i], pd()); dst_oir = oir->factory(_obj_id_ref_ptr[i], pd());
if (!dst_oir) if (dst_oir) _obj_id_ref_ptr[i] = nullptr;
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]); }
} else /* otherwise free the pre-allocation */
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
if (dst_oir) dst_oir->add_to_utcb(); if (dst_oir) dst_oir->add_to_utcb();
@ -405,12 +414,7 @@ void Thread::_call_delete_thread()
void Thread::_call_await_request_msg() void Thread::_call_await_request_msg()
{ {
if (_ipc_node.can_await_request()) { if (_ipc_node.can_await_request()) {
unsigned const rcv_caps = user_arg_1(); _ipc_alloc_recv_caps(user_arg_1());
Genode::Allocator &slab = pd().platform_pd().capability_slab();
for (unsigned i = 0; i < rcv_caps; i++)
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
_ipc_rcv_caps = rcv_caps;
_ipc_node.await_request(); _ipc_node.await_request();
if (_ipc_node.awaits_request()) { if (_ipc_node.awaits_request()) {
_become_inactive(AWAITS_IPC); _become_inactive(AWAITS_IPC);
@ -473,13 +477,8 @@ void Thread::_call_send_request_msg()
if (!_ipc_node.can_send_request()) { if (!_ipc_node.can_send_request()) {
Genode::raw("IPC send request: bad state"); Genode::raw("IPC send request: bad state");
} else { } else {
unsigned const rcv_caps = user_arg_2(); _ipc_alloc_recv_caps(user_arg_2());
Genode::Allocator &slab = pd().platform_pd().capability_slab();
for (unsigned i = 0; i < rcv_caps; i++)
_obj_id_ref_ptr[i] = slab.alloc(sizeof(Object_identity_reference));
_ipc_capid = oir ? oir->capid() : cap_id_invalid(); _ipc_capid = oir ? oir->capid() : cap_id_invalid();
_ipc_rcv_caps = rcv_caps;
_ipc_node.send_request(dst->_ipc_node, help); _ipc_node.send_request(dst->_ipc_node, help);
} }
@ -832,6 +831,9 @@ Thread::Thread(unsigned const priority, unsigned const quota,
_label(label), _core(core), regs(core) { } _label(label), _core(core), regs(core) { }
Thread::~Thread() { _ipc_free_recv_caps(); }
void Thread::print(Genode::Output &out) const void Thread::print(Genode::Output &out) const
{ {
Genode::print(out, _pd ? _pd->platform_pd().label() : "?"); Genode::print(out, _pd ? _pd->platform_pd().label() : "?");

View File

@ -125,7 +125,9 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
DEAD = 7, DEAD = 7,
}; };
void *_obj_id_ref_ptr[Genode::Msgbuf_base::MAX_CAPS_PER_MSG]; enum { MAX_RCV_CAPS = Genode::Msgbuf_base::MAX_CAPS_PER_MSG };
void *_obj_id_ref_ptr[MAX_RCV_CAPS] { nullptr };
Ipc_node _ipc_node; Ipc_node _ipc_node;
capid_t _ipc_capid { cap_id_invalid() }; capid_t _ipc_capid { cap_id_invalid() };
size_t _ipc_rcv_caps { 0 }; size_t _ipc_rcv_caps { 0 };
@ -269,6 +271,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
kobj.destruct(); kobj.destruct();
} }
void _ipc_alloc_recv_caps(unsigned rcv_cap_count);
void _ipc_free_recv_caps();
void _ipc_init(Genode::Native_utcb &utcb, Thread &callee); void _ipc_init(Genode::Native_utcb &utcb, Thread &callee);
public: public:
@ -294,6 +298,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
Thread(char const * const label) Thread(char const * const label)
: Thread(Cpu_priority::MIN, 0, label, true) { } : Thread(Cpu_priority::MIN, 0, label, true) { }
~Thread();
/************************** /**************************
** Support for syscalls ** ** Support for syscalls **

View File

@ -132,10 +132,6 @@ bool Platform_pd::bind_thread(Platform_thread &t)
} }
void Platform_pd::unbind_thread(Platform_thread &t) {
t.join_pd(nullptr, false, Address_space::weak_ptr()); }
void Platform_pd::assign_parent(Native_capability parent) void Platform_pd::assign_parent(Native_capability parent)
{ {
if (!_parent.valid() && parent.valid()) if (!_parent.valid() && parent.valid())

View File

@ -209,11 +209,6 @@ class Genode::Platform_pd : public Hw::Address_space,
*/ */
bool bind_thread(Platform_thread &); bool bind_thread(Platform_thread &);
/**
* Unbind thread from protection domain
*/
void unbind_thread(Platform_thread &);
/** /**
* Assign parent interface to protection domain * Assign parent interface to protection domain
*/ */