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

View File

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