libc: cleanup monitor implementation

- Explicit types for function and monitor execution results
- Remove pending flag and mutex (pending flag was moved to kernel)
This commit is contained in:
Christian Helmuth 2020-07-13 09:16:32 +02:00 committed by Norman Feske
parent 420ed91480
commit 257b3b6775
2 changed files with 31 additions and 32 deletions

View File

@ -271,13 +271,16 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
Pthread_pool _pthreads { _timer_accessor };
Monitor::Pool _monitors { };
Monitor::Pool _monitors { *this };
Reconstructible<Io_signal_handler<Kernel>> _execute_monitors {
_env.ep(), *this, &Kernel::_monitors_handler };
bool _execute_monitors_pending { false };
void _monitors_handler()
{
_execute_monitors_pending = false;
_monitors.execute_monitors();
}
@ -532,26 +535,30 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
/**
* Monitor interface
*/
bool _monitor(Mutex &mutex, Function &fn, uint64_t timeout_ms) override
Monitor::Result _monitor(Mutex &mutex, Function &fn, uint64_t timeout_ms) override
{
if (_main_context()) {
Main_job job { fn, timeout_ms };
_monitors.monitor(mutex, job);
return job.completed();
return job.completed() ? Monitor::Result::COMPLETE
: Monitor::Result::TIMEOUT;
} else {
Pthread_job job { fn, _timer_accessor, timeout_ms };
_monitors.monitor(mutex, job);
return job.completed();
return job.completed() ? Monitor::Result::COMPLETE
: Monitor::Result::TIMEOUT;
}
}
void _charge_monitors() override
{
if (_monitors.charge_monitors())
if (!_execute_monitors_pending) {
_execute_monitors_pending = true;
Signal_transmitter(*_execute_monitors).submit();
}
}
/**

View File

@ -48,20 +48,24 @@ class Libc::Monitor : Interface
{
public:
enum class Result { COMPLETE, TIMEOUT };
struct Job;
struct Pool;
struct Function : Interface { virtual bool execute() = 0; };
enum class Function_result { COMPLETE, INCOMPLETE };
struct Function : Interface { virtual Function_result execute() = 0; };
protected:
virtual bool _monitor(Mutex &, Function &, uint64_t) = 0;
virtual Result _monitor(Mutex &, Function &, uint64_t) = 0;
virtual void _charge_monitors() = 0;
public:
/**
* Block until monitored execution succeeds or timeout expires
* Block until monitored execution completed or timeout expires
*
* The mutex must be locked when calling the monitor. It is released
* during wait for completion and re-aquired before the function
@ -70,15 +74,16 @@ class Libc::Monitor : Interface
* Returns true if execution completed, false on timeout.
*/
template <typename FN>
bool monitor(Mutex &mutex, FN const &fn, uint64_t timeout_ms = 0)
Result monitor(Mutex &mutex, FN const &fn, uint64_t timeout_ms = 0)
{
struct _Function : Function
{
FN const &fn;
bool execute() override { return fn(); }
Function_result execute() override { return fn(); }
_Function(FN const &fn) : fn(fn) { }
} function { fn };
_charge_monitors();
return _monitor(mutex, function, timeout_ms);
}
@ -103,7 +108,7 @@ struct Libc::Monitor::Job
virtual ~Job() { }
bool execute() { return _fn.execute(); }
bool execute() { return _fn.execute() == Function_result::COMPLETE; }
bool completed() const { return _blockade.woken_up(); }
bool expired() const { return _blockade.expired(); }
@ -117,43 +122,30 @@ struct Libc::Monitor::Pool
{
private:
Registry<Job> _jobs;
Mutex _mutex;
bool _execution_pending { false };
Monitor &_monitor;
Registry<Job> _jobs;
public:
Pool(Monitor &monitor) : _monitor(monitor) { }
/* called by monitor-user context */
void monitor(Mutex &mutex, Job &job)
{
Registry<Job>::Element element { _jobs, job };
mutex.release();
_monitor.charge_monitors();
job.wait_for_completion();
mutex.acquire();
}
bool charge_monitors()
{
Mutex::Guard guard { _mutex };
bool const charged = !_execution_pending;
_execution_pending = true;
return charged;
}
/* called by the monitor context itself */
void execute_monitors()
{
{
Mutex::Guard guard { _mutex };
if (!_execution_pending) return;
_execution_pending = false;
}
_jobs.for_each([&] (Job &job) {
if (!job.completed() && !job.expired() && job.execute()) {
job.complete();