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;
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)
{
_utcb = &utcb;
_ipc_rcv_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_alloc_recv_caps(starter._utcb->cap_cnt());
ipc_copy_msg(starter);
}
@ -66,20 +81,16 @@ void Thread::ipc_copy_msg(Thread &sender)
capid_t id = sender._utcb->cap_get(i);
/* if there is no capability to send, just free the pre-allocation */
if (i >= sender._utcb->cap_cnt()) {
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
continue;
}
/* if there is no capability to send, nothing to do */
if (i >= sender._utcb->cap_cnt()) { continue; }
/* lookup the capability id within the caller's cap space */
Reference *oir = (id == cap_id_invalid())
? 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) {
_utcb->cap_add(cap_id_invalid());
free_obj_id_ref(pd(), _obj_id_ref_ptr[i]);
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 (!dst_oir && (&pd() != &core_pd())) {
dst_oir = oir->factory(_obj_id_ref_ptr[i], pd());
if (!dst_oir)
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) _obj_id_ref_ptr[i] = nullptr;
}
if (dst_oir) dst_oir->add_to_utcb();
@ -405,12 +414,7 @@ void Thread::_call_delete_thread()
void Thread::_call_await_request_msg()
{
if (_ipc_node.can_await_request()) {
unsigned const rcv_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_alloc_recv_caps(user_arg_1());
_ipc_node.await_request();
if (_ipc_node.awaits_request()) {
_become_inactive(AWAITS_IPC);
@ -473,13 +477,8 @@ void Thread::_call_send_request_msg()
if (!_ipc_node.can_send_request()) {
Genode::raw("IPC send request: bad state");
} else {
unsigned const rcv_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_alloc_recv_caps(user_arg_2());
_ipc_capid = oir ? oir->capid() : cap_id_invalid();
_ipc_rcv_caps = rcv_caps;
_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) { }
Thread::~Thread() { _ipc_free_recv_caps(); }
void Thread::print(Genode::Output &out) const
{
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,
};
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;
capid_t _ipc_capid { cap_id_invalid() };
size_t _ipc_rcv_caps { 0 };
@ -269,6 +271,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
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);
public:
@ -294,6 +298,8 @@ class Kernel::Thread : private Kernel::Object, public Cpu_job, private Timeout
Thread(char const * const label)
: Thread(Cpu_priority::MIN, 0, label, true) { }
~Thread();
/**************************
** 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)
{
if (!_parent.valid() && parent.valid())

View File

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