diff --git a/repos/os/src/drivers/timer/include/signalled_time_source.h b/repos/os/src/drivers/timer/include/signalled_time_source.h index 2e7c30d05a..c99661d868 100644 --- a/repos/os/src/drivers/timer/include/signalled_time_source.h +++ b/repos/os/src/drivers/timer/include/signalled_time_source.h @@ -30,11 +30,16 @@ class Genode::Signalled_time_source : public Time_source Signal_handler _signal_handler; Timeout_handler *_handler = nullptr; + bool _irq = false; void _handle_timeout() { if (_handler) { - _handler->handle_timeout(curr_time()); } + _irq = true; + Duration time(curr_time()); + _irq = false; + _handler->handle_timeout(time); + } } public: diff --git a/repos/os/src/drivers/timer/pit/time_source.cc b/repos/os/src/drivers/timer/pit/time_source.cc index c304a67555..60644a6752 100644 --- a/repos/os/src/drivers/timer/pit/time_source.cc +++ b/repos/os/src/drivers/timer/pit/time_source.cc @@ -53,19 +53,27 @@ void Timer::Time_source::schedule_timeout(Microseconds duration, Timeout_handler &handler) { _handler = &handler; - _timer_irq.ack_irq(); unsigned long duration_us = duration.value; - /* limit timer-interrupt rate */ - enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 }; - if (duration_us < 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND) - duration_us = 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND; - - if (duration_us > max_timeout().value) + /* timeout '0' is trigger to cancel the current pending, if required */ + if (!duration.value) { duration_us = max_timeout().value; + Signal_transmitter(_signal_handler).submit(); + } else { + /* limit timer-interrupt rate */ + enum { MAX_TIMER_IRQS_PER_SECOND = 4*1000 }; + if (duration_us < 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND) + duration_us = 1000 * 1000 / MAX_TIMER_IRQS_PER_SECOND; + + if (duration_us > max_timeout().value) + duration_us = max_timeout().value; + } _counter_init_value = (PIT_TICKS_PER_MSEC * duration_us) / 1000; _set_counter(_counter_init_value); + + if (duration.value) + _timer_irq.ack_irq(); } @@ -93,6 +101,16 @@ uint32_t Timer::Time_source::_ticks_since_update_one_wrap(uint16_t curr_counter) Duration Timer::Time_source::curr_time() +{ + /* read out and update curr time solely if running in context of irq */ + if (_irq) + _curr_time(); + + return Duration(Microseconds(_curr_time_us)); +} + + +Duration Timer::Time_source::_curr_time() { /* read PIT counter and wrapped status */ uint32_t ticks; diff --git a/repos/os/src/drivers/timer/pit/time_source.h b/repos/os/src/drivers/timer/pit/time_source.h index c616b6f554..6b7e84b1b6 100644 --- a/repos/os/src/drivers/timer/pit/time_source.h +++ b/repos/os/src/drivers/timer/pit/time_source.h @@ -82,6 +82,8 @@ class Timer::Time_source : public Genode::Signalled_time_source Genode::uint32_t _ticks_since_update_no_wrap(Genode::uint16_t curr_counter); + Duration _curr_time(); + public: Time_source(Genode::Env &env);