mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
dde_rump: support blocking I/O operations from non-ep threads
Issue #4433
This commit is contained in:
parent
87c5f91a74
commit
88dec4cc94
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "sched.h"
|
#include "sched.h"
|
||||||
#include <base/allocator_avl.h>
|
#include <base/allocator_avl.h>
|
||||||
|
#include <base/registry.h>
|
||||||
#include <block_session/connection.h>
|
#include <block_session/connection.h>
|
||||||
#include <rump/env.h>
|
#include <rump/env.h>
|
||||||
#include <rump_fs/fs.h>
|
#include <rump_fs/fs.h>
|
||||||
@ -21,6 +22,60 @@ static const bool verbose = false;
|
|||||||
|
|
||||||
enum { GENODE_FD = 64 };
|
enum { GENODE_FD = 64 };
|
||||||
|
|
||||||
|
|
||||||
|
class Io_signal_blockade : public Genode::Io_signal_handler<Io_signal_blockade>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
Genode::Entrypoint &_ep;
|
||||||
|
|
||||||
|
Genode::Thread const *_ep_thread_ptr;
|
||||||
|
|
||||||
|
bool _signal_handler_called { false };
|
||||||
|
|
||||||
|
typedef Genode::Registered_no_delete<Genode::Blockade> Registered_blockade;
|
||||||
|
Genode::Registry<Registered_blockade> _blockades;
|
||||||
|
|
||||||
|
void _handle_io_signal()
|
||||||
|
{
|
||||||
|
/* unblock the ep thread */
|
||||||
|
_signal_handler_called = true;
|
||||||
|
|
||||||
|
/* unblock non-ep threads */
|
||||||
|
_blockades.for_each([] (Genode::Blockade &blockade) {
|
||||||
|
blockade.wakeup();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
Io_signal_blockade(Entrypoint &ep)
|
||||||
|
: Io_signal_handler(ep, *this,
|
||||||
|
&Io_signal_blockade::_handle_io_signal),
|
||||||
|
_ep(ep)
|
||||||
|
{
|
||||||
|
_ep_thread_ptr = Genode::Thread::myself();
|
||||||
|
}
|
||||||
|
|
||||||
|
void block_for_io()
|
||||||
|
{
|
||||||
|
if (Genode::Thread::myself() == _ep_thread_ptr) {
|
||||||
|
|
||||||
|
while (!_signal_handler_called)
|
||||||
|
_ep.wait_and_dispatch_one_io_signal();
|
||||||
|
|
||||||
|
_signal_handler_called = false;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Registered_blockade _blockade { _blockades };
|
||||||
|
_blockade.block();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Block session connection
|
* Block session connection
|
||||||
*/
|
*/
|
||||||
@ -46,14 +101,14 @@ class Backend
|
|||||||
Block::Connection<Job> _session { Rump::env().env(), &_alloc };
|
Block::Connection<Job> _session { Rump::env().env(), &_alloc };
|
||||||
Block::Session::Info _info { _session.info() };
|
Block::Session::Info _info { _session.info() };
|
||||||
Genode::Mutex _session_mutex;
|
Genode::Mutex _session_mutex;
|
||||||
|
Io_signal_blockade _io_signal_blockade { _ep };
|
||||||
|
|
||||||
bool _blocked_for_synchronous_io = false;
|
int _blocked_for_synchronous_io = 0;
|
||||||
|
|
||||||
Genode::Io_signal_handler<Backend> _signal_handler {
|
|
||||||
_ep, *this, &Backend::_update_jobs };
|
|
||||||
|
|
||||||
void _update_jobs()
|
void _update_jobs()
|
||||||
{
|
{
|
||||||
|
Genode::Mutex::Guard guard(_session_mutex);
|
||||||
|
|
||||||
struct Update_jobs_policy
|
struct Update_jobs_policy
|
||||||
{
|
{
|
||||||
void produce_write_content(Job &job, Block::seek_off_t offset,
|
void produce_write_content(Job &job, Block::seek_off_t offset,
|
||||||
@ -78,6 +133,17 @@ class Backend
|
|||||||
_session.update_jobs(policy);
|
_session.update_jobs(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function can be called by multiple threads
|
||||||
|
* (ep and 'pdaemon' have been observed so far in practice).
|
||||||
|
* A non-ep thread cannot dispatch signals and needs to block
|
||||||
|
* until the ep has processed the signal. Therefore it is
|
||||||
|
* important that the ep has the chance to process the signal
|
||||||
|
* even in the case that it calls this function while a non-ep
|
||||||
|
* thread is already blocking here. For this reason the
|
||||||
|
* '_session_mutex' cannot be held over the scope of the whole
|
||||||
|
* function.
|
||||||
|
*/
|
||||||
bool _synchronous_io(void *ptr, Block::Operation const &operation)
|
bool _synchronous_io(void *ptr, Block::Operation const &operation)
|
||||||
{
|
{
|
||||||
Genode::Constructible<Job> job { };
|
Genode::Constructible<Job> job { };
|
||||||
@ -85,20 +151,22 @@ class Backend
|
|||||||
{
|
{
|
||||||
Genode::Mutex::Guard guard(_session_mutex);
|
Genode::Mutex::Guard guard(_session_mutex);
|
||||||
job.construct(_session, ptr, operation);
|
job.construct(_session, ptr, operation);
|
||||||
_blocked_for_synchronous_io = true;
|
_blocked_for_synchronous_io++;
|
||||||
}
|
}
|
||||||
|
|
||||||
_update_jobs();
|
_update_jobs();
|
||||||
|
|
||||||
while (!job->completed())
|
while (!job->completed()) {
|
||||||
_ep.wait_and_dispatch_one_io_signal();
|
_io_signal_blockade.block_for_io();
|
||||||
|
_update_jobs();
|
||||||
|
}
|
||||||
|
|
||||||
bool const success = job->success;
|
bool const success = job->success;
|
||||||
|
|
||||||
{
|
{
|
||||||
Genode::Mutex::Guard guard(_session_mutex);
|
Genode::Mutex::Guard guard(_session_mutex);
|
||||||
job.destruct();
|
job.destruct();
|
||||||
_blocked_for_synchronous_io = false;
|
_blocked_for_synchronous_io--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
@ -108,7 +176,7 @@ class Backend
|
|||||||
|
|
||||||
Backend()
|
Backend()
|
||||||
{
|
{
|
||||||
_session.sigh(_signal_handler);
|
_session.sigh(_io_signal_blockade);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t block_count() const { return _info.block_count; }
|
uint64_t block_count() const { return _info.block_count; }
|
||||||
@ -142,7 +210,7 @@ class Backend
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool blocked_for_io() const { return _blocked_for_synchronous_io; }
|
bool blocked_for_io() const { return _blocked_for_synchronous_io > 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user