From 70e0514a026cfddb9402e4e296a7af30e178e3c7 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Tue, 7 May 2019 20:12:31 +0200 Subject: [PATCH] seoul: handle late timeouts either - due to poor signal performance of base platform - due to being to less prioritized - due to schedule overload - due to using time sources of different physical CPUs Issue #3111 --- repos/ports/src/app/seoul/component.cc | 45 +++++++++---- repos/ports/src/app/seoul/timeout_late.h | 81 ++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 repos/ports/src/app/seoul/timeout_late.h diff --git a/repos/ports/src/app/seoul/component.cc b/repos/ports/src/app/seoul/component.cc index 237a4f0dc..e24dcf967 100644 --- a/repos/ports/src/app/seoul/component.cc +++ b/repos/ports/src/app/seoul/component.cc @@ -59,6 +59,7 @@ #include "disk.h" #include "state.h" #include "guest_memory.h" +#include "timeout_late.h" enum { verbose_debug = false }; @@ -74,31 +75,45 @@ class Timeouts { private: - Timer::Connection _timer; + Timer::Connection _timer; + Synced_motherboard &_motherboard; + Synced_timeout_list &_timeouts; + Genode::Signal_handler _timeout_sigh; + Late_timeout _late { }; - Synced_motherboard &_motherboard; - Synced_timeout_list &_timeouts; - - Genode::Signal_handler _timeout_sigh; - - void check_timeouts() + Genode::uint64_t _check_and_wakeup() { + Late_timeout::Remote const timeout_remote = _late.reset(); + timevalue const now = _motherboard()->clock()->time(); - unsigned nr; + unsigned timer_nr; + unsigned timeout_count = 0; - while ((nr = _timeouts()->trigger(now))) { + while ((timer_nr = _timeouts()->trigger(now))) { - MessageTimeout msg(nr, _timeouts()->timeout()); + if (timeout_count == 0 && _late.apply(timeout_remote, + timer_nr, now)) + { + return _motherboard()->clock()->abstime(1, 1000); + } - if (_timeouts()->cancel(nr) < 0) + MessageTimeout msg(timer_nr, _timeouts()->timeout()); + + if (_timeouts()->cancel(timer_nr) < 0) Logging::printf("Timeout not cancelled.\n"); _motherboard()->bus_timeout.send(msg); + + timeout_count++; } + return _timeouts()->timeout(); + } - unsigned long long next = _timeouts()->timeout(); + void check_timeouts() + { + Genode::uint64_t const next = _check_and_wakeup(); if (next == ~0ULL) return; @@ -112,8 +127,9 @@ class Timeouts public: - void reprogram() + void reprogram(Clock &clock, MessageTimer const &msg) { + _late.timeout(clock, msg); Genode::Signal_transmitter(_timeout_sigh).submit(); } @@ -1069,8 +1085,9 @@ class Machine : public StaticReceiver case MessageTimer::TIMER_REQUEST_TIMEOUT: { int res = _timeouts()->request(msg.nr, msg.abstime); + if (res == 0) - _alarm_thread.reprogram(); + _alarm_thread.reprogram(_clock, msg); else if (res < 0) Logging::printf("Could not program timeout.\n"); diff --git a/repos/ports/src/app/seoul/timeout_late.h b/repos/ports/src/app/seoul/timeout_late.h new file mode 100644 index 000000000..d097aad45 --- /dev/null +++ b/repos/ports/src/app/seoul/timeout_late.h @@ -0,0 +1,81 @@ +/* + * \brief Handle timeouts which are late due to poor signal performance or + * due to scheduling overload + * \author Alexander Boettcher + * \date 2019-05-07 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + * + * The code is partially based on the Seoul/Vancouver VMM, which is distributed + * under the terms of the GNU General Public License version 2. + * + * Modifications by Intel Corporation are contributed under the terms and + * conditions of the GNU General Public License version 2. + */ + +#ifndef _TIMEOUT_LATE_H_ +#define _TIMEOUT_LATE_H_ + +class Late_timeout +{ + public: + + struct Remote + { + timevalue _now { 0 }; + timevalue _timeout { 0 }; + unsigned _timer_nr { ~0U }; + + bool valid() const { return _timer_nr != ~0U; }; + }; + + private: + + Genode::Lock _lock { }; + Remote _remote { }; + + public: + + Late_timeout() { } + + void timeout(Clock &clock, MessageTimer const &msg) + { + Genode::Lock_guard guard(_lock); + + Genode::uint64_t const now = clock.time(); + + if (!_remote._now || now < _remote._now) { + _remote._now = now; + _remote._timeout = msg.abstime; + _remote._timer_nr = msg.nr; + } + } + + Remote reset() + { + Genode::Lock_guard guard(_lock); + + Remote last = _remote; + + _remote._now = 0; + _remote._timeout = 0; + _remote._timer_nr = ~0U; + + return last; + } + + bool apply(Remote const &remote, + unsigned const timer_nr, + Genode::uint64_t now) + { + return (timer_nr == remote._timer_nr) && + ((remote._timeout - remote._now) < (now - _remote._now)); + } +}; + +#endif /* _TIMEOUT_LATE_H_ */