diff --git a/repos/base-fiasco/lib/mk/base-fiasco.mk b/repos/base-fiasco/lib/mk/base-fiasco.mk
index dfca0008e..6a594d41a 100644
--- a/repos/base-fiasco/lib/mk/base-fiasco.mk
+++ b/repos/base-fiasco/lib/mk/base-fiasco.mk
@@ -1,6 +1,6 @@
include $(BASE_DIR)/lib/mk/base.inc
-LIBS += syscall-fiasco
+LIBS += syscall-fiasco timeout
SRC_CC += thread_start.cc
SRC_CC += cache.cc
diff --git a/repos/base-foc/lib/mk/base-foc.inc b/repos/base-foc/lib/mk/base-foc.inc
index 37538f73f..3ad06fce1 100644
--- a/repos/base-foc/lib/mk/base-foc.inc
+++ b/repos/base-foc/lib/mk/base-foc.inc
@@ -1,6 +1,6 @@
include $(BASE_DIR)/lib/mk/base.inc
-LIBS += base-foc-common syscall-foc cxx
+LIBS += base-foc-common syscall-foc cxx timeout
SRC_CC += cap_map_remove.cc cap_alloc.cc
SRC_CC += thread_start.cc
diff --git a/repos/base-hw/include/kernel/interface.h b/repos/base-hw/include/kernel/interface.h
index dcd8befcb..a99db6997 100644
--- a/repos/base-hw/include/kernel/interface.h
+++ b/repos/base-hw/include/kernel/interface.h
@@ -42,6 +42,7 @@ namespace Kernel
constexpr Call_arg call_id_timeout() { return 16; }
constexpr Call_arg call_id_timeout_age_us() { return 17; }
constexpr Call_arg call_id_timeout_max_us() { return 18; }
+ constexpr Call_arg call_id_time() { return 19; }
/*****************************************************************
@@ -106,6 +107,18 @@ namespace Kernel
}
+ /**
+ * Return value of a free-running, uniform counter
+ *
+ * The counter has a constant frequency and does not wrap twice during
+ * a time period of 'timeout_max_us()' microseconds.
+ */
+ inline time_t time()
+ {
+ return call(call_id_time());
+ }
+
+
/**
* Return the constant maximum installable timeout in microseconds
*
diff --git a/repos/base-hw/lib/mk/base-hw.mk b/repos/base-hw/lib/mk/base-hw.mk
index dae3cbdfc..c861eadcd 100644
--- a/repos/base-hw/lib/mk/base-hw.mk
+++ b/repos/base-hw/lib/mk/base-hw.mk
@@ -6,4 +6,4 @@ SRC_CC += capability.cc
SRC_CC += cache.cc
SRC_CC += raw_write_string.cc
-LIBS += startup-hw base-hw-common
+LIBS += startup-hw base-hw-common timeout-hw
diff --git a/repos/base-hw/lib/mk/timeout-hw.mk b/repos/base-hw/lib/mk/timeout-hw.mk
new file mode 100644
index 000000000..235f50ec7
--- /dev/null
+++ b/repos/base-hw/lib/mk/timeout-hw.mk
@@ -0,0 +1,10 @@
+SRC_CC += timeout.cc
+SRC_CC += timer_connection.cc
+SRC_CC += hw/timer_connection_timestamp.cc
+SRC_CC += duration.cc
+
+LIBS += alarm
+
+INC_DIR += $(BASE_DIR)/src/include
+
+vpath % $(BASE_DIR)/../os/src/lib/timeout
diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc
index f66bfd43b..6efe8aba3 100644
--- a/repos/base-hw/src/core/kernel/cpu.cc
+++ b/repos/base-hw/src/core/kernel/cpu.cc
@@ -42,6 +42,9 @@ time_t Cpu_job::timeout_age_us(Timeout const * const timeout) const
}
+time_t Cpu_job::time() const { return _cpu->time(); }
+
+
time_t Cpu_job::timeout_max_us() const
{
return _cpu->timeout_max_us();
diff --git a/repos/base-hw/src/core/kernel/cpu.h b/repos/base-hw/src/core/kernel/cpu.h
index e81f78c63..5f052217e 100644
--- a/repos/base-hw/src/core/kernel/cpu.h
+++ b/repos/base-hw/src/core/kernel/cpu.h
@@ -196,6 +196,8 @@ class Kernel::Cpu_job : public Genode::Cpu::User_context, public Cpu_share
time_t timeout_max_us() const;
+ time_t time() const;
+
/***************
** Accessors **
***************/
@@ -323,6 +325,8 @@ class Kernel::Cpu : public Genode::Cpu, public Irq::Pool, private Timeout
time_t timeout_max_us() const;
+ time_t time() const { return _timer.time(); }
+
/***************
** Accessors **
***************/
diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc
index 1fde96c25..0cc20312b 100644
--- a/repos/base-hw/src/core/kernel/thread.cc
+++ b/repos/base-hw/src/core/kernel/thread.cc
@@ -564,6 +564,7 @@ void Thread::_call()
case call_id_timeout(): _call_timeout(); return;
case call_id_timeout_age_us(): _call_timeout_age_us(); return;
case call_id_timeout_max_us(): _call_timeout_max_us(); return;
+ case call_id_time(): user_arg_0(Cpu_job::time()); return;
default:
/* check wether this is a core thread */
if (!_core()) {
diff --git a/repos/base-hw/src/core/kernel/timer.h b/repos/base-hw/src/core/kernel/timer.h
index d3c0e45c8..f51c5aeac 100644
--- a/repos/base-hw/src/core/kernel/timer.h
+++ b/repos/base-hw/src/core/kernel/timer.h
@@ -99,6 +99,8 @@ class Kernel::Timer
unsigned interrupt_id() const;
static void init_cpu_local();
+
+ time_t time() const { return _time; }
};
#endif /* _CORE__KERNEL__TIMER_H_ */
diff --git a/repos/base-linux/lib/mk/base-linux.mk b/repos/base-linux/lib/mk/base-linux.mk
index f020b24ae..767921c27 100644
--- a/repos/base-linux/lib/mk/base-linux.mk
+++ b/repos/base-linux/lib/mk/base-linux.mk
@@ -6,7 +6,7 @@
include $(REP_DIR)/lib/mk/base-linux.inc
-LIBS += startup-linux base-linux-common
+LIBS += startup-linux base-linux-common timeout
SRC_CC += thread.cc thread_myself.cc thread_linux.cc
SRC_CC += capability_space.cc capability_raw.cc
SRC_CC += attach_stack_area.cc
diff --git a/repos/base-linux/lib/mk/lx_hybrid.mk b/repos/base-linux/lib/mk/lx_hybrid.mk
index 2ffba5194..5e2907de7 100644
--- a/repos/base-linux/lib/mk/lx_hybrid.mk
+++ b/repos/base-linux/lib/mk/lx_hybrid.mk
@@ -4,7 +4,7 @@ vpath new_delete.cc $(BASE_DIR)/src/lib/cxx
vpath lx_hybrid.cc $(REP_DIR)/src/lib/lx_hybrid
# add parts of the base library that are shared with core
-LIBS += base-linux-common
+LIBS += base-linux-common timeout
# non-core parts of the base library (except for the startup code)
include $(REP_DIR)/lib/mk/base-linux.inc
diff --git a/repos/base-nova/lib/mk/base-nova.mk b/repos/base-nova/lib/mk/base-nova.mk
index d8ebb9f4d..45aa1d988 100644
--- a/repos/base-nova/lib/mk/base-nova.mk
+++ b/repos/base-nova/lib/mk/base-nova.mk
@@ -1,5 +1,5 @@
include $(BASE_DIR)/lib/mk/base.inc
-LIBS += base-nova-common cxx
+LIBS += base-nova-common cxx timeout
SRC_CC += thread_start.cc
SRC_CC += cache.cc
diff --git a/repos/base-okl4/lib/mk/base-okl4.mk b/repos/base-okl4/lib/mk/base-okl4.mk
index b2b05fccb..4d6223e9c 100644
--- a/repos/base-okl4/lib/mk/base-okl4.mk
+++ b/repos/base-okl4/lib/mk/base-okl4.mk
@@ -1,6 +1,6 @@
include $(BASE_DIR)/lib/mk/base.inc
-LIBS += base-okl4-common syscall-okl4
+LIBS += base-okl4-common syscall-okl4 timeout
SRC_CC += thread_start.cc
SRC_CC += cache.cc
SRC_CC += capability_space.cc
diff --git a/repos/base-pistachio/lib/mk/base-pistachio.mk b/repos/base-pistachio/lib/mk/base-pistachio.mk
index 7ceb8bd9e..37a55542d 100644
--- a/repos/base-pistachio/lib/mk/base-pistachio.mk
+++ b/repos/base-pistachio/lib/mk/base-pistachio.mk
@@ -1,6 +1,6 @@
include $(BASE_DIR)/lib/mk/base.inc
-LIBS += base-pistachio-common syscall-pistachio cxx
+LIBS += base-pistachio-common syscall-pistachio cxx timeout
SRC_CC += thread_start.cc
SRC_CC += cache.cc
diff --git a/repos/base-sel4/lib/mk/base-sel4.mk b/repos/base-sel4/lib/mk/base-sel4.mk
index e9faa7f35..3ebad650f 100644
--- a/repos/base-sel4/lib/mk/base-sel4.mk
+++ b/repos/base-sel4/lib/mk/base-sel4.mk
@@ -4,4 +4,4 @@ SRC_CC += capability_space.cc
SRC_CC += thread_start.cc thread_init.cc
SRC_CC += cache.cc
-LIBS += syscall-sel4 base-sel4-common
+LIBS += syscall-sel4 base-sel4-common timeout
diff --git a/repos/base/lib/symbols/ld b/repos/base/lib/symbols/ld
index 6994b5eab..dcc787218 100644
--- a/repos/base/lib/symbols/ld
+++ b/repos/base/lib/symbols/ld
@@ -46,8 +46,18 @@ _Z13genode_atexitPFvvE T
_Z16main_thread_utcbv T
_Z21genode___cxa_finalizePv T
_Z22__ldso_raise_exceptionv T
+_ZN5Timer10Connection16schedule_timeoutEN6Genode12MicrosecondsERNS1_11Time_source15Timeout_handlerE T
+_ZN5Timer10Connection18_schedule_one_shotERN6Genode7TimeoutENS1_12MicrosecondsE T
+_ZN5Timer10Connection18_schedule_periodicERN6Genode7TimeoutENS1_12MicrosecondsE T
+_ZN5Timer10Connection8_discardERN6Genode7TimeoutE T
+_ZN5Timer10Connection9curr_timeEv T
+_ZN5Timer10ConnectionC1ERN6Genode3EnvEPKc T
+_ZN5Timer10ConnectionC1Ev T
+_ZN5Timer10ConnectionC2ERN6Genode3EnvEPKc T
+_ZN5Timer10ConnectionC2Ev T
_ZN6Genode10Entrypoint16_dispatch_signalERNS_6SignalE T
_ZN6Genode10Entrypoint16schedule_suspendEPFvvES2_ T
+_ZN6Genode10Entrypoint22Signal_proxy_component6signalEv T
_ZN6Genode10Entrypoint25_process_incoming_signalsEv T
_ZN6Genode10Entrypoint31wait_and_dispatch_one_io_signalEv T
_ZN6Genode10Entrypoint6manageERNS_22Signal_dispatcher_baseE T
@@ -56,7 +66,6 @@ _ZN6Genode10EntrypointC1ERNS_3EnvE T
_ZN6Genode10EntrypointC1ERNS_3EnvEmPKc T
_ZN6Genode10EntrypointC2ERNS_3EnvE T
_ZN6Genode10EntrypointC2ERNS_3EnvEmPKc T
-_ZN6Genode10Entrypoint22Signal_proxy_component6signalEv T
_ZN6Genode10Ipc_serverC1Ev T
_ZN6Genode10Ipc_serverC2Ev T
_ZN6Genode10Ipc_serverD1Ev T
@@ -116,6 +125,7 @@ _ZN6Genode14Signal_contextD2Ev T
_ZN6Genode14Timeout_thread11alarm_timerEv T
_ZN6Genode14Timeout_thread5entryEv T
_ZN6Genode14cache_coherentEmm T
+_ZN6Genode14env_deprecatedEv T
_ZN6Genode14ipc_reply_waitERKNS_17Native_capabilityENS_18Rpc_exception_codeERNS_11Msgbuf_baseES5_ T
_ZN6Genode15Alarm_scheduler12_setup_alarmERNS_5AlarmEmm T
_ZN6Genode15Alarm_scheduler13next_deadlineEPm T
@@ -186,6 +196,12 @@ _ZN6Genode18Signal_transmitterC1ENS_10CapabilityINS_14Signal_contextEEE T
_ZN6Genode18Signal_transmitterC2ENS_10CapabilityINS_14Signal_contextEEE T
_ZN6Genode18server_socket_pairEv T
_ZN6Genode20env_session_id_spaceEv T
+_ZN6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
+_ZN6Genode23Alarm_timeout_scheduler18_schedule_one_shotERNS_7TimeoutENS_12MicrosecondsE T
+_ZN6Genode23Alarm_timeout_scheduler18_schedule_periodicERNS_7TimeoutENS_12MicrosecondsE T
+_ZN6Genode23Alarm_timeout_scheduler7_enableEv T
+_ZN6Genode23Alarm_timeout_schedulerC1ERNS_11Time_sourceE T
+_ZN6Genode23Alarm_timeout_schedulerC2ERNS_11Time_sourceE T
_ZN6Genode25env_stack_area_region_mapE B 4
_ZN6Genode26env_stack_area_ram_sessionE B 4
_ZN6Genode29upgrade_pd_quota_non_blockingENS_9Ram_quotaENS_9Cap_quotaE T
@@ -195,7 +211,6 @@ _ZN6Genode3Log8_releaseEv T
_ZN6Genode3Raw7_outputEv T
_ZN6Genode3Raw8_acquireEv T
_ZN6Genode3Raw8_releaseEv T
-_ZN6Genode14env_deprecatedEv T
_ZN6Genode4Heap11quota_limitEm T
_ZN6Genode4Heap4freeEPvm T
_ZN6Genode4Heap5allocEmPPv T
@@ -307,10 +322,18 @@ _ZN6Genode7Console7vprintfEPKcP13__va_list_tag T
_ZN6Genode7Console7vprintfEPKcPc T
_ZN6Genode7Console7vprintfEPKcPv T
_ZN6Genode7Console7vprintfEPKcSt9__va_list T
+_ZN6Genode7Timeout17schedule_one_shotENS_12MicrosecondsERNS0_7HandlerE T
+_ZN6Genode7Timeout17schedule_periodicENS_12MicrosecondsERNS0_7HandlerE T
+_ZN6Genode7Timeout5AlarmD0Ev W
+_ZN6Genode7Timeout5AlarmD1Ev W
+_ZN6Genode7Timeout5AlarmD2Ev W
+_ZN6Genode7Timeout7discardEv T
_ZN6Genode7cap_mapEv T
_ZN6Genode7vprintfEPKcP13__va_list_tag T
_ZN6Genode7vprintfEPKcPc T
_ZN6Genode7vprintfEPKcSt9__va_list T
+_ZN6Genode8DurationpLENS_12MicrosecondsE T
+_ZN6Genode8DurationpLENS_12MillisecondsE T
_ZN6Genode8ipc_callENS_17Native_capabilityERNS_11Msgbuf_baseES2_m T
_ZN6Genode9ipc_replyENS_17Native_capabilityENS_18Rpc_exception_codeERNS_11Msgbuf_baseE T
_ZNK6Genode11Sliced_heap8overheadEm T
@@ -335,6 +358,7 @@ _ZNK6Genode5Child21notify_resource_availEv T
_ZNK6Genode6Thread10stack_baseEv T
_ZNK6Genode6Thread4nameEv T
_ZNK6Genode6Thread9stack_topEv T
+_ZNK6Genode8Duration17trunc_to_plain_usEv T
_ZNKSt13bad_exception4whatEv T
_ZNKSt9exception4whatEv T
_ZNSt13bad_exceptionD0Ev T
@@ -361,6 +385,7 @@ _ZTIN10__cxxabiv120__function_type_infoE D 12
_ZTIN10__cxxabiv120__si_class_type_infoE D 12
_ZTIN10__cxxabiv121__vmi_class_type_infoE D 12
_ZTIN10__cxxabiv123__fundamental_type_infoE D 12
+_ZTIN5Timer10ConnectionE D 48
_ZTIN6Genode11Sliced_heapE D 12
_ZTIN6Genode14Rpc_entrypointE D 2
_ZTIN6Genode14Rpc_entrypointE D 32
@@ -370,6 +395,7 @@ _ZTIN6Genode14Timeout_threadE D 32
_ZTIN6Genode17Region_map_clientE D 12
_ZTIN6Genode17Rm_session_clientE D 12
_ZTIN6Genode18Allocator_avl_baseE D 12
+_ZTIN6Genode23Alarm_timeout_schedulerE D 80
_ZTIN6Genode4HeapE D 12
_ZTIN6Genode4SlabE D 12
_ZTIN6Genode5AlarmE D 8
@@ -379,6 +405,7 @@ _ZTIN6Genode5ChildE D 40
_ZTIN6Genode6OutputE D 8
_ZTIN6Genode6ThreadE D 8
_ZTIN6Genode7ConsoleE D 8
+_ZTIN6Genode7Timeout5AlarmE D 24
_ZTIPDd D 16
_ZTIPDe D 16
_ZTIPDf D 16
@@ -484,6 +511,7 @@ _ZTSN10__cxxabiv120__function_type_infoE R
_ZTSN10__cxxabiv120__si_class_type_infoE R
_ZTSN10__cxxabiv121__vmi_class_type_infoE R
_ZTSN10__cxxabiv123__fundamental_type_infoE R
+_ZTSN5Timer10ConnectionE R
_ZTSN6Genode11Sliced_heapE R
_ZTSN6Genode14Rpc_entrypointE R
_ZTSN6Genode14Signal_contextE R
@@ -491,6 +519,7 @@ _ZTSN6Genode14Timeout_threadE R
_ZTSN6Genode17Region_map_clientE R
_ZTSN6Genode17Rm_session_clientE R
_ZTSN6Genode18Allocator_avl_baseE R
+_ZTSN6Genode23Alarm_timeout_schedulerE R
_ZTSN6Genode4HeapE R
_ZTSN6Genode4SlabE R
_ZTSN6Genode5AlarmE R
@@ -499,6 +528,7 @@ _ZTSN6Genode5ChildE R
_ZTSN6Genode6OutputE R
_ZTSN6Genode6ThreadE R
_ZTSN6Genode7ConsoleE R
+_ZTSN6Genode7Timeout5AlarmE R
_ZTSSt10bad_typeid R
_ZTSSt13bad_exception R
_ZTSSt16bad_array_length R
@@ -527,6 +557,7 @@ _ZTVN10__cxxabiv121__vmi_class_type_infoE D 2
_ZTVN10__cxxabiv121__vmi_class_type_infoE D 44
_ZTVN10__cxxabiv123__fundamental_type_infoE D 2
_ZTVN10__cxxabiv123__fundamental_type_infoE D 32
+_ZTVN5Timer10ConnectionE D 116
_ZTVN6Genode11Sliced_heapE D 2
_ZTVN6Genode11Sliced_heapE D 36
_ZTVN6Genode14Rpc_entrypointE D 1
@@ -541,6 +572,7 @@ _ZTVN6Genode17Rm_session_clientE D 1
_ZTVN6Genode17Rm_session_clientE D 24
_ZTVN6Genode18Allocator_avl_baseE D 4
_ZTVN6Genode18Allocator_avl_baseE D 64
+_ZTVN6Genode23Alarm_timeout_schedulerE D 80
_ZTVN6Genode4HeapE D 2
_ZTVN6Genode4HeapE D 36
_ZTVN6Genode4SlabE D 2
@@ -557,6 +589,7 @@ _ZTVN6Genode6ThreadE D 1
_ZTVN6Genode6ThreadE D 24
_ZTVN6Genode7ConsoleE D 1
_ZTVN6Genode7ConsoleE D 24
+_ZTVN6Genode7Timeout5AlarmE D 40
_ZTVSt10bad_typeid D 1
_ZTVSt10bad_typeid D 20
_ZTVSt13bad_exception D 1
@@ -573,6 +606,20 @@ _ZTVSt9exception D 1
_ZTVSt9exception D 20
_ZTVSt9type_info D 2
_ZTVSt9type_info D 32
+_ZThn232_N5Timer10Connection16schedule_timeoutEN6Genode12MicrosecondsERNS1_11Time_source15Timeout_handlerE T
+_ZThn232_N5Timer10Connection9curr_timeEv T
+_ZThn236_N5Timer10Connection18_schedule_one_shotERN6Genode7TimeoutENS1_12MicrosecondsE T
+_ZThn236_N5Timer10Connection18_schedule_periodicERN6Genode7TimeoutENS1_12MicrosecondsE T
+_ZThn236_N5Timer10Connection8_discardERN6Genode7TimeoutE T
+_ZThn236_N5Timer10Connection9curr_timeEv T
+_ZThn280_N5Timer10Connection16schedule_timeoutEN6Genode12MicrosecondsERNS1_11Time_source15Timeout_handlerE T
+_ZThn280_N5Timer10Connection9curr_timeEv T
+_ZThn288_N5Timer10Connection18_schedule_one_shotERN6Genode7TimeoutENS1_12MicrosecondsE T
+_ZThn288_N5Timer10Connection18_schedule_periodicERN6Genode7TimeoutENS1_12MicrosecondsE T
+_ZThn288_N5Timer10Connection8_discardERN6Genode7TimeoutE T
+_ZThn288_N5Timer10Connection9curr_timeEv T
+_ZThn4_N6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
+_ZThn8_N6Genode23Alarm_timeout_scheduler14handle_timeoutENS_8DurationE T
_ZZN6Genode18Allocator_avl_base5BlockC4EmmbE10num_blocks V
_ZdlPv W
_ZdlPvPN6Genode11DeallocatorE T
diff --git a/repos/dde_linux/src/lib/lxip/lxcc_emul.cc b/repos/dde_linux/src/lib/lxip/lxcc_emul.cc
index 87f26e656..416f98bd4 100644
--- a/repos/dde_linux/src/lib/lxip/lxcc_emul.cc
+++ b/repos/dde_linux/src/lib/lxip/lxcc_emul.cc
@@ -344,7 +344,7 @@ static Genode::Signal_context_capability tick_sig_cap;
void Lx::event_init(Genode::Env &env, Genode::Entrypoint &ep, void (*ticker)())
{
- static Timeout handler(env, ep, ticker);
+ static ::Timeout handler(env, ep, ticker);
_timeout = &handler;
}
diff --git a/repos/gems/src/server/terminal/main.cc b/repos/gems/src/server/terminal/main.cc
index c0dd9de57..f81b9f494 100644
--- a/repos/gems/src/server/terminal/main.cc
+++ b/repos/gems/src/server/terminal/main.cc
@@ -24,7 +24,6 @@
#include
#include
#include
-#include
/* terminal includes */
#include
@@ -531,8 +530,7 @@ struct Terminal::Main
Framebuffer::Connection _framebuffer { _env, Framebuffer::Mode() };
Input::Connection _input { _env };
- Timer::Connection _timer_conection { _env };
- Genode::Timer _timer { _timer_conection, _env.ep() };
+ Timer::Connection _timer { _env };
Sliced_heap _sliced_heap { _env.ram(), _env.rm() };
@@ -556,12 +554,12 @@ struct Terminal::Main
Signal_handler _input_handler {
_env.ep(), *this, &Main::_handle_input };
- void _handle_key_repeat(Time_source::Microseconds);
+ void _handle_key_repeat(Duration);
- One_shot_timeout _key_repeat_timeout {
+ Timer::One_shot_timeout _key_repeat_timeout {
_timer, *this, &Main::_handle_key_repeat };
- void _handle_flush(Time_source::Microseconds);
+ void _handle_flush(Duration);
/*
* Time in milliseconds between a change of the terminal content and the
@@ -575,7 +573,7 @@ struct Terminal::Main
void _trigger_flush()
{
if (!_flush_scheduled) {
- _flush_timeout.start(Time_source::Microseconds{1000*_flush_delay});
+ _flush_timeout.schedule(Microseconds{1000*_flush_delay});
_flush_scheduled = true;
}
}
@@ -590,7 +588,7 @@ struct Terminal::Main
Trigger_flush(Main &main) : _main(main) { }
} _trigger_flush_callback { *this };
- One_shot_timeout _flush_timeout {
+ Timer::One_shot_timeout _flush_timeout {
_timer, *this, &Main::_handle_flush };
Main(Genode::Env &env,
@@ -657,11 +655,11 @@ void Terminal::Main::_handle_input()
});
if (_repeat_next)
- _key_repeat_timeout.start(Time_source::Microseconds{1000*_repeat_next});
+ _key_repeat_timeout.schedule(Microseconds{1000*_repeat_next});
}
-void Terminal::Main::_handle_key_repeat(Time_source::Microseconds)
+void Terminal::Main::_handle_key_repeat(Duration)
{
if (_repeat_next) {
@@ -675,7 +673,7 @@ void Terminal::Main::_handle_key_repeat(Time_source::Microseconds)
}
-void Terminal::Main::_handle_flush(Time_source::Microseconds)
+void Terminal::Main::_handle_flush(Duration)
{
_flush_scheduled = false;
_flush_callback_registry.flush();
diff --git a/repos/gems/src/server/terminal/target.mk b/repos/gems/src/server/terminal/target.mk
index dba8b32b5..46b6e93be 100644
--- a/repos/gems/src/server/terminal/target.mk
+++ b/repos/gems/src/server/terminal/target.mk
@@ -1,4 +1,4 @@
TARGET = terminal
SRC_CC = main.cc
-LIBS = base timeout
+LIBS = base
SRC_BIN = $(notdir $(wildcard $(PRG_DIR)/*.tff))
diff --git a/repos/libports/lib/mk/libc.mk b/repos/libports/lib/mk/libc.mk
index 7eb2cc223..b06f95b15 100644
--- a/repos/libports/lib/mk/libc.mk
+++ b/repos/libports/lib/mk/libc.mk
@@ -4,7 +4,7 @@
LIBS = libc-string libc-locale libc-stdlib libc-stdio libc-gen libc-gdtoa \
libc-inet libc-stdtime libc-regex libc-compat libc-setjmp libc-mem
-LIBS += base vfs timeout
+LIBS += base vfs
#
# Back end
diff --git a/repos/libports/src/lib/libc/nanosleep.cc b/repos/libports/src/lib/libc/nanosleep.cc
index df6de9e90..9c0738a73 100644
--- a/repos/libports/src/lib/libc/nanosleep.cc
+++ b/repos/libports/src/lib/libc/nanosleep.cc
@@ -16,8 +16,6 @@
#include "task.h"
-using namespace Genode;
-
extern "C" __attribute__((weak))
int _nanosleep(const struct timespec *req, struct timespec *rem)
{
diff --git a/repos/libports/src/lib/libc/task.cc b/repos/libports/src/lib/libc/task.cc
index 4494fa294..77f366b45 100644
--- a/repos/libports/src/lib/libc/task.cc
+++ b/repos/libports/src/lib/libc/task.cc
@@ -23,7 +23,6 @@
#include
#include
#include
-#include
/* libc includes */
#include
@@ -49,7 +48,7 @@ namespace Libc {
class Timeout_handler;
class Io_response_handler;
- using Microseconds = Genode::Time_source::Microseconds;
+ using Genode::Microseconds;
}
@@ -167,18 +166,13 @@ class Libc::Env_implementation : public Libc::Env
struct Libc::Timer
{
- ::Timer::Connection _timer_connection;
- Genode::Timer _timer;
+ ::Timer::Connection _timer;
- Timer(Genode::Env &env)
- :
- _timer_connection(env),
- _timer(_timer_connection, env.ep())
- { }
+ Timer(Genode::Env &env) : _timer(env) { }
- unsigned long curr_time() const
+ unsigned long curr_time()
{
- return _timer.curr_time().value/1000;
+ return _timer.curr_time().trunc_to_plain_us().value/1000;
}
static Microseconds microseconds(unsigned long timeout_ms)
@@ -188,7 +182,7 @@ struct Libc::Timer
static unsigned long max_timeout()
{
- return Genode::Timer::Microseconds::max().value/1000;
+ return ~0UL/1000;
}
};
@@ -217,14 +211,14 @@ struct Libc::Timeout_handler
*/
struct Libc::Timeout
{
- Libc::Timer_accessor &_timer_accessor;
- Timeout_handler &_handler;
- Genode::One_shot_timeout _timeout;
+ Libc::Timer_accessor &_timer_accessor;
+ Timeout_handler &_handler;
+ ::Timer::One_shot_timeout _timeout;
bool _expired = true;
unsigned long _absolute_timeout_ms = 0;
- void _handle(Microseconds now)
+ void _handle(Duration now)
{
_expired = true;
_absolute_timeout_ms = 0;
@@ -245,7 +239,7 @@ struct Libc::Timeout
_expired = false;
_absolute_timeout_ms = now + timeout_ms;
- _timeout.start(_timer_accessor.timer().microseconds(timeout_ms));
+ _timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms));
}
unsigned long duration_left() const
diff --git a/repos/libports/src/lib/libc/task.h b/repos/libports/src/lib/libc/task.h
index d6f1395ab..00397e283 100644
--- a/repos/libports/src/lib/libc/task.h
+++ b/repos/libports/src/lib/libc/task.h
@@ -21,10 +21,6 @@
#ifndef _LIBC__TASK_H_
#define _LIBC__TASK_H_
-/* Genode includes */
-#include
-
-
namespace Libc {
/**
diff --git a/repos/os/include/os/duration.h b/repos/os/include/os/duration.h
new file mode 100644
index 000000000..16d94b3d6
--- /dev/null
+++ b/repos/os/include/os/duration.h
@@ -0,0 +1,84 @@
+/*
+ * \brief A duration type for both highly precise and long durations
+ * \author Martin Stein
+ * \date 2017-03-21
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _OS__DURATION_H_
+#define _OS__DURATION_H_
+
+/* Genode includes */
+#include
+#include
+
+namespace Genode {
+
+ class Microseconds;
+ class Milliseconds;
+ class Duration;
+}
+
+
+/**
+ * Makes it clear that a given integer value stands for microseconds
+ */
+struct Genode::Microseconds
+{
+ unsigned long value;
+
+ explicit Microseconds(unsigned long value) : value(value) { }
+};
+
+
+/**
+ * Makes it clear that a given integer value stands for milliseconds
+ */
+struct Genode::Milliseconds
+{
+ unsigned long value;
+
+ explicit Milliseconds(unsigned long value) : value(value) { }
+};
+
+
+/**
+ * A duration type that combines high precision and large intervals
+ */
+struct Genode::Duration
+{
+ public:
+
+ struct Overflow : Exception { };
+
+ private:
+
+ enum { US_PER_MS = 1000UL };
+ enum { MS_PER_HOUR = 1000UL * 60 * 60 };
+ enum { US_PER_HOUR = 1000UL * 1000 * 60 * 60 };
+
+ unsigned long _microseconds { 0 };
+ unsigned long _hours { 0 };
+
+ void _raise_hours(unsigned long hours);
+
+ public:
+
+ void operator += (Microseconds us);
+ void operator += (Milliseconds ms);
+
+ bool operator < (Duration &other) const;
+
+ explicit Duration(Milliseconds ms) { *this += ms; }
+ explicit Duration(Microseconds us) { *this += us; }
+
+ Microseconds trunc_to_plain_us() const;
+};
+
+#endif /* _OS__DURATION_H_ */
diff --git a/repos/os/include/os/time_source.h b/repos/os/include/os/time_source.h
deleted file mode 100644
index 78d77cf18..000000000
--- a/repos/os/include/os/time_source.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * \brief Interface of a time source that can handle one timeout at a time
- * \author Martin Stein
- * \date 2016-11-04
- */
-
-/*
- * Copyright (C) 2016-2017 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _OS__TIME_SOURCE_H_
-#define _OS__TIME_SOURCE_H_
-
-namespace Genode { class Time_source; }
-
-/**
- * Interface of a time source that can handle one timeout at a time
- */
-struct Genode::Time_source
-{
- /**
- * Makes it clear which time unit an interfaces takes
- */
- struct Microseconds
- {
- unsigned long value;
-
- explicit Microseconds(unsigned long const value) : value(value) { }
-
- static Microseconds max() { return Microseconds(~0UL); }
- };
-
- /**
- * Interface of a timeout callback
- */
- struct Timeout_handler
- {
- virtual void handle_timeout(Microseconds curr_time) = 0;
- };
-
- /**
- * Return the current time of the source
- */
- virtual Microseconds curr_time() const = 0;
-
- /**
- * Return the maximum timeout duration that the source can handle
- */
- virtual Microseconds max_timeout() const = 0;
-
- /**
- * Install a timeout, overrides the last timeout if any
- *
- * \param duration timeout duration
- * \param handler timeout callback
- */
- virtual void schedule_timeout(Microseconds duration,
- Timeout_handler &handler) = 0;
-};
-
-#endif /* _OS__TIME_SOURCE_H_ */
diff --git a/repos/os/include/os/timer.h b/repos/os/include/os/timer.h
deleted file mode 100644
index 4f6481f2f..000000000
--- a/repos/os/include/os/timer.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * \brief Multiplexes a timer session amongst different timeouts
- * \author Martin Stein
- * \date 2016-11-04
- */
-
-/*
- * Copyright (C) 2016-2017 Genode Labs GmbH
- *
- * This file is part of the Genode OS framework, which is distributed
- * under the terms of the GNU Affero General Public License version 3.
- */
-
-#ifndef _TIMER_H_
-#define _TIMER_H_
-
-/* Genode includes */
-#include
-#include
-#include
-
-namespace Genode {
- class Timer;
- class Timer_time_source;
-}
-
-
-/**
- * Implementation helper for 'Timer'
- *
- * \noapi
- */
-class Genode::Timer_time_source : public Genode::Time_source
-{
- private:
-
- enum { MIN_TIMEOUT_US = 5000 };
-
- using Signal_handler = Genode::Io_signal_handler;
-
- ::Timer::Session &_session;
- Signal_handler _signal_handler;
- Timeout_handler *_handler = nullptr;
-
- void _handle_timeout()
- {
- if (_handler)
- _handler->handle_timeout(curr_time());
- }
-
- public:
-
- Timer_time_source(::Timer::Session &session, Entrypoint &ep)
- :
- _session(session),
- _signal_handler(ep, *this, &Timer_time_source::_handle_timeout)
- {
- _session.sigh(_signal_handler);
- }
-
- Microseconds curr_time() const {
- return Microseconds(1000UL * _session.elapsed_ms()); }
-
- void schedule_timeout(Microseconds duration,
- Timeout_handler &handler)
- {
- if (duration.value < MIN_TIMEOUT_US)
- duration.value = MIN_TIMEOUT_US;
-
- if (duration.value > max_timeout().value)
- duration.value = max_timeout().value;
-
- _handler = &handler;
- _session.trigger_once(duration.value);
- }
-
- Microseconds max_timeout() const { return Microseconds::max(); }
-};
-
-
-/**
- * Timer-session based timeout scheduler
- *
- * Multiplexes a timer session amongst different timeouts.
- */
-struct Genode::Timer : private Genode::Timer_time_source,
- public Genode::Alarm_timeout_scheduler
-{
- using Time_source::Microseconds;
- using Alarm_timeout_scheduler::curr_time;
-
- Timer(::Timer::Session &session, Entrypoint &ep)
- :
- Timer_time_source(session, ep),
- Alarm_timeout_scheduler(*(Time_source*)this)
- { }
-};
-
-#endif /* _TIMER_H_ */
diff --git a/repos/os/include/os/timeout.h b/repos/os/include/timer/timeout.h
similarity index 58%
rename from repos/os/include/os/timeout.h
rename to repos/os/include/timer/timeout.h
index 4fed98d11..ac75445cd 100644
--- a/repos/os/include/os/timeout.h
+++ b/repos/os/include/timer/timeout.h
@@ -2,6 +2,11 @@
* \brief Multiplexing one time source amongst different timeouts
* \author Martin Stein
* \date 2016-11-04
+ *
+ * These classes are not meant to be used directly. They merely exist to share
+ * the generic parts of timeout-scheduling between the Timer::Connection and the
+ * Timer driver. For user-level timeout-scheduling you should use the interface
+ * in timer_session/connection.h instead.
*/
/*
@@ -11,23 +16,72 @@
* under the terms of the GNU Affero General Public License version 3.
*/
-#ifndef _OS__TIMEOUT_H_
-#define _OS__TIMEOUT_H_
+#ifndef _TIMER__TIMEOUT_H_
+#define _TIMER__TIMEOUT_H_
/* Genode includes */
#include
-#include
#include
+#include
+#include
namespace Genode {
+ class Time_source;
class Timeout_scheduler;
class Timeout;
class Alarm_timeout_scheduler;
- template class Periodic_timeout;
- template class One_shot_timeout;
}
+namespace Timer
+{
+ class Connection;
+ class Root_component;
+}
+
+
+/**
+ * Interface of a time source that can handle one timeout at a time
+ */
+struct Genode::Time_source
+{
+ /**
+ * Interface of a timeout callback
+ */
+ struct Timeout_handler
+ {
+ virtual void handle_timeout(Duration curr_time) = 0;
+ };
+
+ /**
+ * Return the current time of the source
+ */
+ virtual Duration curr_time() = 0;
+
+ /**
+ * Return the maximum timeout duration that the source can handle
+ */
+ virtual Microseconds max_timeout() const = 0;
+
+ /**
+ * Install a timeout, overrides the last timeout if any
+ *
+ * \param duration timeout duration
+ * \param handler timeout callback
+ */
+ virtual void schedule_timeout(Microseconds duration,
+ Timeout_handler &handler) = 0;
+
+ /**
+ * Tell the time source which scheduler to use for its own timeouts
+ *
+ * This method enables a time source for example to synchronize with an
+ * accurate but expensive timer only on a periodic basis while using a
+ * cheaper interpolation in general.
+ */
+ virtual void scheduler(Timeout_scheduler &scheduler) { };
+};
+
/**
* Interface of a time-source multiplexer
@@ -38,10 +92,6 @@ namespace Genode {
*/
class Genode::Timeout_scheduler
{
- public:
-
- using Microseconds = Time_source::Microseconds;
-
private:
friend Timeout;
@@ -74,7 +124,7 @@ class Genode::Timeout_scheduler
/**
* Read out the now time of the scheduler
*/
- virtual Microseconds curr_time() const = 0;
+ virtual Duration curr_time() = 0;
};
@@ -97,16 +147,11 @@ class Genode::Timeout : private Noncopyable
*/
struct Handler
{
- using Microseconds = Time_source::Microseconds;
-
- virtual void handle_timeout(Microseconds curr_time) = 0;
+ virtual void handle_timeout(Duration curr_time) = 0;
};
private:
- using Microseconds = Time_source::Microseconds;
-
-
struct Alarm : Genode::Alarm
{
Timeout_scheduler &timeout_scheduler;
@@ -137,98 +182,8 @@ class Genode::Timeout : private Noncopyable
void schedule_one_shot(Microseconds duration, Handler &handler);
void discard();
-};
-
-/**
- * Periodic timeout that is linked to a custom handler, starts when constructed
- */
-template
-struct Genode::Periodic_timeout : private Noncopyable
-{
- public:
-
- using Microseconds = Timeout_scheduler::Microseconds;
-
- private:
-
- typedef void (HANDLER::*Handler_method)(Microseconds);
-
- Timeout _timeout;
-
- struct Handler : Timeout::Handler
- {
- HANDLER &object;
- Handler_method const method;
-
- Handler(HANDLER &object, Handler_method method)
- : object(object), method(method) { }
-
-
- /**********************
- ** Timeout::Handler **
- **********************/
-
- void handle_timeout(Microseconds curr_time) override {
- (object.*method)(curr_time); }
-
- } _handler;
-
- public:
-
- Periodic_timeout(Timeout_scheduler &timeout_scheduler,
- HANDLER &object,
- Handler_method method,
- Microseconds duration)
- :
- _timeout(timeout_scheduler), _handler(object, method)
- {
- _timeout.schedule_periodic(duration, _handler);
- }
-};
-
-
-/**
- * One-shot timeout that is linked to a custom handler, started manually
- */
-template
-class Genode::One_shot_timeout : private Noncopyable
-{
- private:
-
- using Microseconds = Timeout_scheduler::Microseconds;
-
- typedef void (HANDLER::*Handler_method)(Microseconds);
-
- Timeout _timeout;
-
- struct Handler : Timeout::Handler
- {
- HANDLER &object;
- Handler_method const method;
-
- Handler(HANDLER &object, Handler_method method)
- : object(object), method(method) { }
-
-
- /**********************
- ** Timeout::Handler **
- **********************/
-
- void handle_timeout(Microseconds curr_time) override {
- (object.*method)(curr_time); }
-
- } _handler;
-
- public:
-
- One_shot_timeout(Timeout_scheduler &timeout_scheduler,
- HANDLER &object,
- Handler_method method)
- : _timeout(timeout_scheduler), _handler(object, method) { }
-
- void start(Microseconds duration) {
- _timeout.schedule_one_shot(duration, _handler); }
+ bool scheduled() { return _alarm.handler != nullptr; }
};
@@ -239,17 +194,22 @@ class Genode::Alarm_timeout_scheduler : private Noncopyable,
public Timeout_scheduler,
public Time_source::Timeout_handler
{
+ friend class Timer::Connection;
+ friend class Timer::Root_component;
+
private:
Time_source &_time_source;
Alarm_scheduler _alarm_scheduler;
+ void _enable();
+
/**********************************
** Time_source::Timeout_handler **
**********************************/
- void handle_timeout(Microseconds curr_time) override;
+ void handle_timeout(Duration curr_time) override;
/***********************
@@ -271,8 +231,7 @@ class Genode::Alarm_timeout_scheduler : private Noncopyable,
** Timeout_scheduler **
***********************/
- Microseconds curr_time() const override {
- return _time_source.curr_time(); }
+ Duration curr_time() override { return _time_source.curr_time(); }
};
-#endif /* _OS__TIMEOUT_H_ */
+#endif /* _TIMER__TIMEOUT_H_ */
diff --git a/repos/os/include/timer_session/connection.h b/repos/os/include/timer_session/connection.h
index b0839f4e3..c2e4cd6a9 100644
--- a/repos/os/include/timer_session/connection.h
+++ b/repos/os/include/timer_session/connection.h
@@ -1,5 +1,5 @@
/*
- * \brief Connection to timer service
+ * \brief Connection to timer service and timeout scheduler
* \author Norman Feske
* \date 2008-08-22
*/
@@ -14,16 +14,158 @@
#ifndef _INCLUDE__TIMER_SESSION__CONNECTION_H_
#define _INCLUDE__TIMER_SESSION__CONNECTION_H_
+/* Genode includes */
#include
#include
+#include
+#include
+#include
+#include
-namespace Timer { class Connection; }
+namespace Timer
+{
+ class Connection;
+ template class Periodic_timeout;
+ template class One_shot_timeout;
+}
-class Timer::Connection : public Genode::Connection, public Session_client
+/**
+ * Periodic timeout that is linked to a custom handler, scheduled when constructed
+ */
+template
+struct Timer::Periodic_timeout : private Genode::Noncopyable
{
private:
+ using Duration = Genode::Duration;
+ using Timeout = Genode::Timeout;
+ using Timeout_scheduler = Genode::Timeout_scheduler;
+ using Microseconds = Genode::Microseconds;
+
+ typedef void (HANDLER::*Handler_method)(Duration);
+
+ Timeout _timeout;
+
+ struct Handler : Timeout::Handler
+ {
+ HANDLER &object;
+ Handler_method const method;
+
+ Handler(HANDLER &object, Handler_method method)
+ : object(object), method(method) { }
+
+
+ /**********************
+ ** Timeout::Handler **
+ **********************/
+
+ void handle_timeout(Duration curr_time) override {
+ (object.*method)(curr_time); }
+
+ } _handler;
+
+ public:
+
+ Periodic_timeout(Timeout_scheduler &timeout_scheduler,
+ HANDLER &object,
+ Handler_method method,
+ Microseconds duration)
+ :
+ _timeout(timeout_scheduler), _handler(object, method)
+ {
+ _timeout.schedule_periodic(duration, _handler);
+ }
+};
+
+
+/**
+ * One-shot timeout that is linked to a custom handler, scheduled manually
+ */
+template
+class Timer::One_shot_timeout : private Genode::Noncopyable
+{
+ private:
+
+ using Duration = Genode::Duration;
+ using Timeout = Genode::Timeout;
+ using Timeout_scheduler = Genode::Timeout_scheduler;
+ using Microseconds = Genode::Microseconds;
+
+ typedef void (HANDLER::*Handler_method)(Duration);
+
+ Timeout _timeout;
+
+ struct Handler : Timeout::Handler
+ {
+ HANDLER &object;
+ Handler_method const method;
+
+ Handler(HANDLER &object, Handler_method method)
+ : object(object), method(method) { }
+
+
+ /**********************
+ ** Timeout::Handler **
+ **********************/
+
+ void handle_timeout(Duration curr_time) override {
+ (object.*method)(curr_time); }
+
+ } _handler;
+
+ public:
+
+ One_shot_timeout(Timeout_scheduler &timeout_scheduler,
+ HANDLER &object,
+ Handler_method method)
+ : _timeout(timeout_scheduler), _handler(object, method) { }
+
+ void schedule(Microseconds duration) {
+ _timeout.schedule_one_shot(duration, _handler); }
+
+ void discard() { _timeout.discard(); }
+
+ bool scheduled() { return _timeout.scheduled(); }
+};
+
+
+/**
+ * Connection to timer service and timeout scheduler
+ *
+ * Multiplexes a timer session amongst different timeouts.
+ */
+class Timer::Connection : public Genode::Connection,
+ public Session_client,
+ private Genode::Time_source,
+ public Genode::Timeout_scheduler
+{
+ private:
+
+ using Timeout = Genode::Timeout;
+ using Timeout_handler = Genode::Time_source::Timeout_handler;
+ using Timestamp = Genode::Trace::Timestamp;
+ using Duration = Genode::Duration;
+ using Lock = Genode::Lock;
+ using Microseconds = Genode::Microseconds;
+ using Milliseconds = Genode::Milliseconds;
+ using Entrypoint = Genode::Entrypoint;
+
+ /*
+ * The mode determines which interface of the timer connection is
+ * enabled. Initially, a timer connection is in LEGACY mode. When in
+ * MODERN mode, a call to the LEGACY interface causes an exception.
+ * When in LEGACY mode, a call to the MODERN interface causes a switch
+ * to the MODERN mode. The LEGACY interface is deprecated. Please
+ * prefer using the MODERN interface.
+ *
+ * LEGACY = Timer Session interface, blocking calls usleep and msleep
+ * MODERN = more precise curr_time, non-blocking and multiplexed
+ * handling with Periodic_timeout resp. One_shot_timeout
+ */
+ enum Mode { LEGACY, MODERN };
+
+ Mode _mode { LEGACY };
Genode::Lock _lock;
Genode::Signal_receiver _sig_rec;
Genode::Signal_context _default_sigh_ctx;
@@ -33,21 +175,88 @@ class Timer::Connection : public Genode::Connection, public Session_cli
Genode::Signal_context_capability _custom_sigh_cap;
+ void _enable_modern_mode();
+
+ void _sigh(Signal_context_capability sigh)
+ {
+ Session_client::sigh(sigh);
+ }
+
+
+ /*************************
+ ** Time_source helpers **
+ *************************/
+
+ /*
+ * The higher the factor shift, the more precise is the time
+ * interpolation but the more likely it becomes that an overflow
+ * would occur during calculations. In this case, the timer
+ * down-scales the values live which is avoidable overhead.
+ */
+ enum { TS_TO_US_RATIO_SHIFT = 4 };
+ enum { MIN_TIMEOUT_US = 5000 };
+ enum { REAL_TIME_UPDATE_PERIOD_US = 500000 };
+ enum { MAX_TS = ~(Timestamp)0ULL >> TS_TO_US_RATIO_SHIFT };
+ enum { MAX_INTERPOLATION_QUALITY = 3 };
+ enum { MAX_REMOTE_TIME_LATENCY_US = 500 };
+ enum { MAX_REMOTE_TIME_TRIALS = 5 };
+
+ Genode::Io_signal_handler _signal_handler;
+
+ Timeout_handler *_handler { nullptr };
+ Lock _real_time_lock { Lock::UNLOCKED };
+ unsigned long _ms { elapsed_ms() };
+ Timestamp _ts { _timestamp() };
+ Duration _real_time { Milliseconds(_ms) };
+ Duration _interpolated_time { _real_time };
+ unsigned _interpolation_quality { 0 };
+ unsigned long _us_to_ts_factor { 1UL << TS_TO_US_RATIO_SHIFT };
+
+ Timestamp _timestamp();
+
+ void _update_interpolation_quality(unsigned long min_factor,
+ unsigned long max_factor);
+
+ unsigned long _ts_to_us_ratio(Timestamp ts, unsigned long us);
+
+ void _update_real_time();
+
+ Duration _update_interpolated_time(Duration &interpolated_time);
+
+ void _handle_timeout();
+
+
+ /*****************
+ ** Time_source **
+ *****************/
+
+ void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
+ Microseconds max_timeout() const override { return Microseconds(REAL_TIME_UPDATE_PERIOD_US); }
+
+
+ /*******************************
+ ** Timeout_scheduler helpers **
+ *******************************/
+
+ Genode::Alarm_timeout_scheduler _scheduler { *this };
+
+
+ /***********************
+ ** Timeout_scheduler **
+ ***********************/
+
+ void _schedule_one_shot(Timeout &timeout, Microseconds duration) override;
+ void _schedule_periodic(Timeout &timeout, Microseconds duration) override;
+ void _discard(Timeout &timeout) override;
+
public:
+ struct Cannot_use_both_legacy_and_modern_interface : Genode::Exception { };
+
/**
* Constructor
*/
- Connection(Genode::Env &env, char const *label = "")
- :
- Genode::Connection(env, session(env.parent(),
- "ram_quota=10K, cap_quota=%u, label=\"%s\"",
- CAP_QUOTA, label)),
- Session_client(cap())
- {
- /* register default signal handler */
- Session_client::sigh(_default_sigh_cap);
- }
+ Connection(Genode::Env &env, char const *label = "");
/**
* Constructor
@@ -56,28 +265,36 @@ class Timer::Connection : public Genode::Connection, public Session_cli
* \deprecated Use the constructor with 'Env &' as first
* argument instead
*/
- Connection() __attribute__((deprecated))
- :
- Genode::Connection(session("ram_quota=10K")),
- Session_client(cap())
- {
- /* register default signal handler */
- Session_client::sigh(_default_sigh_cap);
- }
+ Connection() __attribute__((deprecated));
~Connection() { _sig_rec.dissolve(&_default_sigh_ctx); }
/*
* Intercept 'sigh' to keep track of customized signal handlers
+ *
+ * \noapi
+ * \deprecated Use One_shot_timeout (or Periodic_timeout) instead
*/
- void sigh(Signal_context_capability sigh)
+ void sigh(Signal_context_capability sigh) override
{
+ if (_mode == MODERN) {
+ throw Cannot_use_both_legacy_and_modern_interface();
+ }
_custom_sigh_cap = sigh;
Session_client::sigh(_custom_sigh_cap);
}
+ /*
+ * Block for a time span of 'us' microseconds
+ *
+ * \noapi
+ * \deprecated Use One_shot_timeout (or Periodic_timeout) instead
+ */
void usleep(unsigned us)
{
+ if (_mode == MODERN) {
+ throw Cannot_use_both_legacy_and_modern_interface();
+ }
/*
* Omit the interaction with the timer driver for the corner case
* of not sleeping at all. This corner case may be triggered when
@@ -105,10 +322,26 @@ class Timer::Connection : public Genode::Connection, public Session_cli
Session_client::sigh(_custom_sigh_cap);
}
+ /*
+ * Block for a time span of 'ms' milliseconds
+ *
+ * \noapi
+ * \deprecated Use One_shot_timeout (or Periodic_timeout) instead
+ */
void msleep(unsigned ms)
{
+ if (_mode == MODERN) {
+ throw Cannot_use_both_legacy_and_modern_interface();
+ }
usleep(1000*ms);
}
+
+
+ /***********************************
+ ** Timeout_scheduler/Time_source **
+ ***********************************/
+
+ Duration curr_time() override;
};
#endif /* _INCLUDE__TIMER_SESSION__CONNECTION_H_ */
diff --git a/repos/os/lib/mk/timeout.mk b/repos/os/lib/mk/timeout.mk
index 2c489a767..eaddf2777 100644
--- a/repos/os/lib/mk/timeout.mk
+++ b/repos/os/lib/mk/timeout.mk
@@ -1,5 +1,10 @@
SRC_CC += timeout.cc
+SRC_CC += timer_connection.cc
+SRC_CC += timer_connection_timestamp.cc
+SRC_CC += duration.cc
LIBS += alarm
+INC_DIR += $(BASE_DIR)/src/include
+
vpath % $(REP_DIR)/src/lib/timeout
diff --git a/repos/os/run/timeout.run b/repos/os/run/timeout.run
index 671bcec62..8cf04ca95 100644
--- a/repos/os/run/timeout.run
+++ b/repos/os/run/timeout.run
@@ -2,7 +2,28 @@
# Build
#
-build "core init drivers/timer test/timeout"
+#
+# Do not run on QEMU as its time emulation is not precise enough
+#
+if {[get_cmd_switch --autopilot] && [have_include "power_on/qemu"]} {
+ puts "\nRunning timeout test in autopilot on Qemu is not recommended.\n"
+ exit 0
+}
+
+#
+# Do not run on ARM with kernels other than HW
+#
+# The ARM performance counter has no reliable frequency as the ARM idle command
+# (often called on idle) halts the counter. Only on the HW kernel we have a syscall
+# that enables us to avoid the use of the performance counter by reading the kernel
+# time instead.
+#
+if {[expr [have_spec arm] && ![have_spec hw]]} {
+ puts "\n Run script is not supported on this platform.\n";
+ exit 0
+}
+
+build "core init drivers/platform drivers/timer test/timeout test/cpufreq"
#
# Boot image
@@ -33,7 +54,7 @@ install_config {
-
+
}
@@ -44,30 +65,8 @@ build_boot_image "core ld.lib.so init timer test-timeout"
# Execution
#
-append qemu_args "-nographic -m 64"
+append qemu_args "-nographic -m 350"
-#
-# We check for each timeout that has a distance of at least 200ms to each
-# other timeout:
-#
-# 0 ms
-# 0 ms
-# 700 ms -> check for 700 ms
-# 1000 ms -> check for 1000 ms
-# 1400 ms -> check for 700 ms
-# 2000 ms
-# 2100 ms
-# 2800 ms -> check for 700 ms
-# 3000 ms -> check for 1000 ms
-# 3250 ms -> check for 3250 ms
-# 3500 ms -> check for 700 ms
-# 4000 ms -> check for 1000 ms
-# 4200 ms -> check for 700 ms
-# 4900 ms
-# 5000 ms
-# 5200 ms -> check for 5200 ms
-# 5600 ms -> check for 700 ms
-# 6000 ms -> check for 1000 ms
-#
-
-run_genode_until ".*700ms timeout.*\n.*1000ms timeout.*\n.*700ms timeout.*\n.*700ms timeout.*\n.*1000ms timeout.*\n.*3250ms timeout.*\n.*700ms timeout.*\n.*1000ms timeout.*\n.*700ms timeout.*\n.*5200ms timeout.*\n.*700ms timeout.*\n.*1000ms timeout.*\n" 20
+run_genode_until "child \"test\" exited with exit value.*\n" 900
+grep_output {\[init\] child "test" exited with exit value}
+compare_output_to {[init] child "test" exited with exit value 0}
diff --git a/repos/os/src/drivers/timer/fiasco/time_source.cc b/repos/os/src/drivers/timer/fiasco/time_source.cc
index 35bb2fc64..91d706675 100644
--- a/repos/os/src/drivers/timer/fiasco/time_source.cc
+++ b/repos/os/src/drivers/timer/fiasco/time_source.cc
@@ -39,7 +39,8 @@ namespace Fiasco {
#include
using namespace Fiasco;
-using Microseconds = Genode::Time_source::Microseconds;
+using Microseconds = Genode::Microseconds;
+using Duration = Genode::Duration;
static l4_timeout_s mus_to_timeout(unsigned long mus)
@@ -71,14 +72,14 @@ Microseconds Timer::Time_source::max_timeout() const
}
-Microseconds Timer::Time_source::curr_time() const
+Duration Timer::Time_source::curr_time()
{
Genode::Lock::Guard lock_guard(_lock);
static Genode::Attached_rom_dataspace kip_ds(_env, "l4v2_kip");
static Fiasco::l4_kernel_info_t * const kip =
kip_ds.local_addr();
- return Microseconds(kip->clock);
+ return Duration(Microseconds(kip->clock));
}
diff --git a/repos/os/src/drivers/timer/hw/time_source.cc b/repos/os/src/drivers/timer/hw/time_source.cc
index 96c979149..722a2f9dc 100644
--- a/repos/os/src/drivers/timer/hw/time_source.cc
+++ b/repos/os/src/drivers/timer/hw/time_source.cc
@@ -23,7 +23,6 @@
#include
using namespace Genode;
-using Microseconds = Genode::Time_source::Microseconds;
enum { MIN_TIMEOUT_US = 1000 };
@@ -56,14 +55,14 @@ void Timer::Time_source::schedule_timeout(Microseconds duration,
}
-Microseconds Timer::Time_source::curr_time() const
+Duration Timer::Time_source::curr_time()
{
unsigned long const timeout_age_us = Kernel::timeout_age_us();
if (timeout_age_us > _last_timeout_age_us) {
/* increment time by the difference since the last update */
- _curr_time_us += timeout_age_us - _last_timeout_age_us;
+ _curr_time += Microseconds(timeout_age_us - _last_timeout_age_us);
_last_timeout_age_us = timeout_age_us;
}
- return Microseconds(_curr_time_us);
+ return _curr_time;
}
diff --git a/repos/os/src/drivers/timer/hw/time_source.h b/repos/os/src/drivers/timer/hw/time_source.h
index 0eb29f165..73e507746 100644
--- a/repos/os/src/drivers/timer/hw/time_source.h
+++ b/repos/os/src/drivers/timer/hw/time_source.h
@@ -14,17 +14,26 @@
#ifndef _TIME_SOURCE_H_
#define _TIME_SOURCE_H_
+/* Genode includes */
+#include
+
/* local includes */
#include
-namespace Timer { class Time_source; }
+namespace Timer {
+
+ using Microseconds = Genode::Microseconds;
+ using Duration = Genode::Duration;
+ class Time_source;
+}
class Timer::Time_source : public Genode::Signalled_time_source
{
private:
- unsigned long mutable _curr_time_us = 0;
+
+ Duration mutable _curr_time { Microseconds(0) };
unsigned long mutable _last_timeout_age_us = 0;
unsigned long const _max_timeout_us;
@@ -37,7 +46,7 @@ class Timer::Time_source : public Genode::Signalled_time_source
** Genode::Time_source **
*************************/
- Microseconds curr_time() const override;
+ Duration curr_time() override;
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
Microseconds max_timeout() const override {
return Microseconds(_max_timeout_us); };
diff --git a/repos/os/src/drivers/timer/include/root_component.h b/repos/os/src/drivers/timer/include/root_component.h
index b123898ed..41045b0b7 100644
--- a/repos/os/src/drivers/timer/include/root_component.h
+++ b/repos/os/src/drivers/timer/include/root_component.h
@@ -56,7 +56,9 @@ class Timer::Root_component : public Genode::Root_component
:
Genode::Root_component(&env.ep().rpc_ep(), &md_alloc),
_time_source(env), _timeout_scheduler(_time_source)
- { }
+ {
+ _timeout_scheduler._enable();
+ }
};
#endif /* _ROOT_COMPONENT_H_ */
diff --git a/repos/os/src/drivers/timer/include/session_component.h b/repos/os/src/drivers/timer/include/session_component.h
index 61ec05f44..09f1e8e2d 100644
--- a/repos/os/src/drivers/timer/include/session_component.h
+++ b/repos/os/src/drivers/timer/include/session_component.h
@@ -21,9 +21,14 @@
#include
#include
#include
-#include
+#include
-namespace Timer { class Session_component; }
+namespace Timer {
+
+ using Microseconds = Genode::Microseconds;
+ using Duration = Genode::Duration;
+ class Session_component;
+}
class Timer::Session_component : public Genode::Rpc_object,
@@ -36,9 +41,10 @@ class Timer::Session_component : public Genode::Rpc_object,
Genode::Timeout_scheduler &_timeout_scheduler;
Genode::Signal_context_capability _sigh;
- unsigned long const _init_time_us = _timeout_scheduler.curr_time().value;
+ unsigned long const _init_time_us =
+ _timeout_scheduler.curr_time().trunc_to_plain_us().value;
- void handle_timeout(Microseconds) {
+ void handle_timeout(Duration) {
Genode::Signal_transmitter(_sigh).submit(); }
public:
@@ -65,7 +71,8 @@ class Timer::Session_component : public Genode::Rpc_object,
}
unsigned long elapsed_ms() const override {
- return (_timeout_scheduler.curr_time().value - _init_time_us) / 1000; }
+ return (_timeout_scheduler.curr_time().trunc_to_plain_us().value -
+ _init_time_us) / 1000; }
void msleep(unsigned) override { /* never called at the server side */ }
void usleep(unsigned) override { /* never called at the server side */ }
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 9a9b18888..2e7c30d05 100644
--- a/repos/os/src/drivers/timer/include/signalled_time_source.h
+++ b/repos/os/src/drivers/timer/include/signalled_time_source.h
@@ -16,7 +16,7 @@
/* Genode includes */
#include
-#include
+#include
#include
namespace Genode { class Signalled_time_source; }
diff --git a/repos/os/src/drivers/timer/include/threaded_time_source.h b/repos/os/src/drivers/timer/include/threaded_time_source.h
index 1f21d5f3f..fa13aaeaf 100644
--- a/repos/os/src/drivers/timer/include/threaded_time_source.h
+++ b/repos/os/src/drivers/timer/include/threaded_time_source.h
@@ -18,10 +18,12 @@
/* Genode inludes */
#include
#include
-#include
+#include
namespace Timer {
+ using Genode::Microseconds;
+ using Genode::Duration;
class Threaded_time_source;
}
@@ -33,7 +35,7 @@ class Timer::Threaded_time_source : public Genode::Time_source,
struct Irq_dispatcher
{
- GENODE_RPC(Rpc_do_dispatch, void, do_dispatch, Microseconds);
+ GENODE_RPC(Rpc_do_dispatch, void, do_dispatch, Duration);
GENODE_RPC_INTERFACE(Rpc_do_dispatch);
};
@@ -47,10 +49,10 @@ class Timer::Threaded_time_source : public Genode::Time_source,
** Irq_dispatcher **
********************/
- void do_dispatch(Microseconds duration)
+ void do_dispatch(Duration curr_time)
{
if (handler) {
- handler->handle_timeout(Microseconds(duration)); }
+ handler->handle_timeout(Duration(curr_time)); }
}
} _irq_dispatcher_component;
diff --git a/repos/os/src/drivers/timer/linux/time_source.cc b/repos/os/src/drivers/timer/linux/time_source.cc
index 0d6937289..ddaaecfb7 100644
--- a/repos/os/src/drivers/timer/linux/time_source.cc
+++ b/repos/os/src/drivers/timer/linux/time_source.cc
@@ -20,7 +20,6 @@
#include
using namespace Genode;
-using Microseconds = Genode::Time_source::Microseconds;
inline int lx_gettimeofday(struct timeval *tv, struct timeval *tz) {
@@ -34,11 +33,11 @@ Microseconds Timer::Time_source::max_timeout() const
}
-Microseconds Timer::Time_source::curr_time() const
+Duration Timer::Time_source::curr_time()
{
struct timeval tv;
lx_gettimeofday(&tv, 0);
- return Microseconds(tv.tv_sec * 1000 * 1000 + tv.tv_usec);
+ return Duration(Microseconds(tv.tv_sec * 1000 * 1000 + tv.tv_usec));
}
diff --git a/repos/os/src/drivers/timer/nova/time_source.cc b/repos/os/src/drivers/timer/nova/time_source.cc
index a17fa4f76..a92ba0da1 100644
--- a/repos/os/src/drivers/timer/nova/time_source.cc
+++ b/repos/os/src/drivers/timer/nova/time_source.cc
@@ -23,7 +23,6 @@
using namespace Genode;
using namespace Nova;
-using Microseconds = Genode::Time_source::Microseconds;
Timer::Time_source::Time_source(Env &env) : Threaded_time_source(env)
diff --git a/repos/os/src/drivers/timer/nova/time_source.h b/repos/os/src/drivers/timer/nova/time_source.h
index c775708ba..ad7794bb4 100644
--- a/repos/os/src/drivers/timer/nova/time_source.h
+++ b/repos/os/src/drivers/timer/nova/time_source.h
@@ -64,8 +64,8 @@ class Timer::Time_source : public Threaded_time_source
Microseconds max_timeout() const override { return _tsc_to_us(~0UL); }
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
- Microseconds curr_time() const override {
- return _tsc_to_us(Genode::Trace::timestamp()); }
+ Duration curr_time() override {
+ return Duration(_tsc_to_us(Genode::Trace::timestamp())); }
};
#endif /* _TIME_SOURCE_H_ */
diff --git a/repos/os/src/drivers/timer/periodic/time_source.cc b/repos/os/src/drivers/timer/periodic/time_source.cc
index c5e81ae2e..0a67971e2 100644
--- a/repos/os/src/drivers/timer/periodic/time_source.cc
+++ b/repos/os/src/drivers/timer/periodic/time_source.cc
@@ -30,7 +30,7 @@ void Timer::Time_source::schedule_timeout(Microseconds duration,
void Timer::Time_source::_wait_for_irq()
{
enum { SLEEP_GRANULARITY_US = 1000UL };
- unsigned long last_time_us = curr_time().value;
+ unsigned long last_time_us = curr_time().trunc_to_plain_us().value;
_lock.lock();
while (_next_timeout_us > 0) {
_lock.unlock();
@@ -38,7 +38,7 @@ void Timer::Time_source::_wait_for_irq()
try { _usleep(SLEEP_GRANULARITY_US); }
catch (Blocking_canceled) { }
- unsigned long curr_time_us = curr_time().value;
+ unsigned long curr_time_us = curr_time().trunc_to_plain_us().value;
unsigned long sleep_duration_us = curr_time_us - last_time_us;
last_time_us = curr_time_us;
diff --git a/repos/os/src/drivers/timer/periodic/time_source.h b/repos/os/src/drivers/timer/periodic/time_source.h
index 98519bd3c..d43a47b8f 100644
--- a/repos/os/src/drivers/timer/periodic/time_source.h
+++ b/repos/os/src/drivers/timer/periodic/time_source.h
@@ -50,7 +50,7 @@ class Timer::Time_source : public Threaded_time_source
** Genode::Time_source **
*************************/
- Microseconds curr_time() const override;
+ Duration curr_time() override;
Microseconds max_timeout() const override;
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
};
diff --git a/repos/os/src/drivers/timer/pit/time_source.cc b/repos/os/src/drivers/timer/pit/time_source.cc
index 8c1752f01..737126d10 100644
--- a/repos/os/src/drivers/timer/pit/time_source.cc
+++ b/repos/os/src/drivers/timer/pit/time_source.cc
@@ -16,7 +16,6 @@
#include
using namespace Genode;
-using Microseconds = Genode::Time_source::Microseconds;
void Timer::Time_source::_set_counter(uint16_t value)
@@ -67,7 +66,7 @@ void Timer::Time_source::schedule_timeout(Microseconds duration,
}
-Microseconds Timer::Time_source::curr_time() const
+Duration Timer::Time_source::curr_time()
{
uint32_t passed_ticks;
@@ -100,7 +99,7 @@ Microseconds Timer::Time_source::curr_time() const
/* use current counter as the reference for the next update */
_counter_init_value = curr_counter;
- return Microseconds(_curr_time_us);
+ return Duration(Microseconds(_curr_time_us));
}
diff --git a/repos/os/src/drivers/timer/pit/time_source.h b/repos/os/src/drivers/timer/pit/time_source.h
index 62e26bdce..0d192162c 100644
--- a/repos/os/src/drivers/timer/pit/time_source.h
+++ b/repos/os/src/drivers/timer/pit/time_source.h
@@ -18,11 +18,17 @@
/* Genode includes */
#include
#include
+#include
/* local includes */
#include
-namespace Timer { class Time_source; }
+namespace Timer {
+
+ using Microseconds = Genode::Microseconds;
+ using Duration = Genode::Duration;
+ class Time_source;
+}
class Timer::Time_source : public Genode::Signalled_time_source
@@ -81,7 +87,7 @@ class Timer::Time_source : public Genode::Signalled_time_source
** Genode::Time_source **
*************************/
- Microseconds curr_time() const override;
+ Duration curr_time() override;
void schedule_timeout(Microseconds duration, Timeout_handler &handler) override;
Microseconds max_timeout() const override {
return Microseconds(PIT_MAX_USEC); }
diff --git a/repos/os/src/drivers/timer/target.inc b/repos/os/src/drivers/timer/target.inc
index 72b8f8e65..b110dc04b 100644
--- a/repos/os/src/drivers/timer/target.inc
+++ b/repos/os/src/drivers/timer/target.inc
@@ -1,5 +1,5 @@
SRC_CC += main.cc
-LIBS += base timeout
+LIBS += base
INC_DIR += $(REP_DIR)/src/drivers/timer/include
vpath %.cc $(REP_DIR)/src/drivers/timer
diff --git a/repos/os/src/lib/timeout/duration.cc b/repos/os/src/lib/timeout/duration.cc
new file mode 100644
index 000000000..41321ebf6
--- /dev/null
+++ b/repos/os/src/lib/timeout/duration.cc
@@ -0,0 +1,67 @@
+/*
+ * \brief A duration type for both highly precise and long durations
+ * \author Martin Stein
+ * \date 2017-03-21
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+
+using namespace Genode;
+
+
+void Duration::_raise_hours(unsigned long hours)
+{
+ unsigned long const old_hours = _hours;
+ _hours += hours;
+ if (_hours < old_hours) {
+ throw Overflow(); }
+}
+
+
+void Duration::operator += (Microseconds us)
+{
+ _microseconds += us.value;
+ if (_microseconds > US_PER_HOUR) {
+ _microseconds -= US_PER_HOUR;
+ _raise_hours(1);
+ }
+}
+
+
+void Duration::operator += (Milliseconds ms)
+{
+ /* filter out hours if any */
+ if (ms.value >= MS_PER_HOUR) {
+ unsigned long const hours = ms.value / MS_PER_HOUR;
+ _raise_hours(hours);
+ ms.value -= hours * MS_PER_HOUR;
+ }
+ /* add the rest as microseconds value */
+ *this += Microseconds(ms.value * US_PER_MS);
+}
+
+
+bool Duration::operator < (Duration &other) const
+{
+ if (_hours != other._hours) {
+ return _hours < other._hours; }
+
+ if (_microseconds != other._microseconds) {
+ return _microseconds < other._microseconds; }
+
+ return false;
+}
+
+
+Microseconds Duration::trunc_to_plain_us() const
+{
+ return Microseconds(_microseconds + (_hours ? _hours * US_PER_HOUR : 0));
+}
diff --git a/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc b/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc
new file mode 100644
index 000000000..dc2f04b04
--- /dev/null
+++ b/repos/os/src/lib/timeout/hw/timer_connection_timestamp.cc
@@ -0,0 +1,24 @@
+/*
+ * \brief Timestamp implementation for the Genode Timer
+ * \author Martin Stein
+ * \date 2016-11-04
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+
+using namespace Genode;
+
+
+Trace::Timestamp Timer::Connection::_timestamp()
+{
+ return Kernel::time();
+}
diff --git a/repos/os/src/lib/timeout/timeout.cc b/repos/os/src/lib/timeout/timeout.cc
index b5bfd532d..4846f7a0c 100644
--- a/repos/os/src/lib/timeout/timeout.cc
+++ b/repos/os/src/lib/timeout/timeout.cc
@@ -12,7 +12,7 @@
*/
/* Genode includes */
-#include
+#include
using namespace Genode;
@@ -28,6 +28,7 @@ void Timeout::schedule_periodic(Microseconds duration, Handler &handler)
_alarm.timeout_scheduler._schedule_periodic(*this, duration);
}
+
void Timeout::schedule_one_shot(Microseconds duration, Handler &handler)
{
_alarm.handler = &handler;
@@ -35,6 +36,7 @@ void Timeout::schedule_one_shot(Microseconds duration, Handler &handler)
_alarm.timeout_scheduler._schedule_one_shot(*this, duration);
}
+
void Timeout::discard()
{
_alarm.timeout_scheduler._discard(*this);
@@ -49,24 +51,29 @@ void Timeout::discard()
bool Timeout::Alarm::on_alarm(unsigned)
{
if (handler) {
- handler->handle_timeout(timeout_scheduler.curr_time()); }
+ Handler *current = handler;
+ if (!periodic) {
+ handler = nullptr;
+ }
+ current->handle_timeout(timeout_scheduler.curr_time());
+ }
return periodic;
}
-
/*****************************
** Alarm_timeout_scheduler **
*****************************/
-void Alarm_timeout_scheduler::handle_timeout(Microseconds curr_time)
+void Alarm_timeout_scheduler::handle_timeout(Duration curr_time)
{
- _alarm_scheduler.handle(curr_time.value);
+ unsigned long const curr_time_us = curr_time.trunc_to_plain_us().value;
+ _alarm_scheduler.handle(curr_time_us);
unsigned long sleep_time_us;
Alarm::Time deadline_us;
if (_alarm_scheduler.next_deadline(&deadline_us)) {
- sleep_time_us = deadline_us - curr_time.value;
+ sleep_time_us = deadline_us - curr_time_us;
} else {
sleep_time_us = _time_source.max_timeout().value; }
@@ -83,17 +90,21 @@ void Alarm_timeout_scheduler::handle_timeout(Microseconds curr_time)
Alarm_timeout_scheduler::Alarm_timeout_scheduler(Time_source &time_source)
:
_time_source(time_source)
+{ }
+
+
+void Alarm_timeout_scheduler::_enable()
{
- time_source.schedule_timeout(Microseconds(0), *this);
+ _time_source.schedule_timeout(Microseconds(0), *this);
}
void Alarm_timeout_scheduler::_schedule_one_shot(Timeout &timeout,
Microseconds duration)
{
- _alarm_scheduler.schedule_absolute(&timeout._alarm,
- _time_source.curr_time().value +
- duration.value);
+ _alarm_scheduler.schedule_absolute(
+ &timeout._alarm,
+ _time_source.curr_time().trunc_to_plain_us().value + duration.value);
if (_alarm_scheduler.head_timeout(&timeout._alarm)) {
_time_source.schedule_timeout(Microseconds(0), *this); }
@@ -103,7 +114,7 @@ void Alarm_timeout_scheduler::_schedule_one_shot(Timeout &timeout,
void Alarm_timeout_scheduler::_schedule_periodic(Timeout &timeout,
Microseconds duration)
{
- _alarm_scheduler.handle(_time_source.curr_time().value);
+ _alarm_scheduler.handle(_time_source.curr_time().trunc_to_plain_us().value);
_alarm_scheduler.schedule(&timeout._alarm, duration.value);
if (_alarm_scheduler.head_timeout(&timeout._alarm)) {
_time_source.schedule_timeout(Microseconds(0), *this); }
diff --git a/repos/os/src/lib/timeout/timer_connection.cc b/repos/os/src/lib/timeout/timer_connection.cc
new file mode 100644
index 000000000..3a3f33a96
--- /dev/null
+++ b/repos/os/src/lib/timeout/timer_connection.cc
@@ -0,0 +1,268 @@
+/*
+ * \brief Connection to timer service and timeout scheduler
+ * \author Martin Stein
+ * \date 2016-11-04
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+
+using namespace Genode;
+using namespace Genode::Trace;
+
+
+void Timer::Connection::_update_interpolation_quality(unsigned long min_factor,
+ unsigned long max_factor)
+{
+ /*
+ * If the factor gets adapted less than 12.5%, we raise the
+ * interpolation-quality value. Otherwise, we reset it to zero.
+ * We can safely do the shift on the factor as it should be
+ * at least of value 1 << TS_TO_US_RATIO_SHIFT.
+ */
+ if ((max_factor - min_factor) < (max_factor >> 3)) {
+ if (_interpolation_quality < MAX_INTERPOLATION_QUALITY) {
+ _interpolation_quality++; }
+ } else if (_interpolation_quality) {
+ _interpolation_quality = 0;
+ }
+}
+
+
+unsigned long Timer::Connection::_ts_to_us_ratio(Timestamp ts,
+ unsigned long us)
+{
+ /*
+ * If the timestamp difference is to big to do the following
+ * factor calculation without an overflow, scale both timestamp
+ * and time difference down equally. This should neither happen
+ * often nor have much effect on the resulting factor.
+ */
+ while (ts > MAX_TS) {
+ warning("timestamp value too big");
+ ts >>= 1;
+ us >>= 1;
+ }
+ if (!us) { us = 1; }
+ if (!ts) { ts = 1; }
+
+ /*
+ * To make the result more precise, we scale up the numerator of
+ * the calculation. This upscaling must be considered when using
+ * the result.
+ */
+ Timestamp const result = (ts << TS_TO_US_RATIO_SHIFT) / us;
+ unsigned long const result_ul = (unsigned long)result;
+ if (result == result_ul) {
+ return result_ul; }
+
+ warning("Timestamp-to-time ratio too big");
+ return ~0UL;
+}
+
+
+void Timer::Connection::_update_real_time()
+{
+ Lock_guard lock_guard(_real_time_lock);
+
+ Timestamp ts = 0UL;
+ unsigned long ms = 0UL;
+ unsigned long us_diff = ~0UL;
+
+ for (unsigned remote_time_trials = 0;
+ remote_time_trials < MAX_REMOTE_TIME_TRIALS;
+ remote_time_trials++)
+ {
+ /* determine time and timestamp difference since the last call */
+ Timestamp volatile new_ts = _timestamp();
+ unsigned long volatile new_ms = elapsed_ms();
+
+ if (_interpolation_quality < MAX_INTERPOLATION_QUALITY) {
+ ms = new_ms;
+ ts = new_ts;
+ break;
+ }
+
+ Timestamp const ts_diff = _timestamp() - new_ts;
+ unsigned long const new_us_diff = _ts_to_us_ratio(ts_diff,
+ _us_to_ts_factor);
+
+ /* remember results only if the latency was better than last time */
+ if (new_us_diff < us_diff) {
+ ms = new_ms;
+ ts = new_ts;
+
+ if (us_diff < MAX_REMOTE_TIME_LATENCY_US) {
+ break;
+ }
+ }
+ }
+
+ unsigned long const ms_diff = ms - _ms;
+ Timestamp const ts_diff = ts - _ts;
+
+ /* update real time and values for next difference calculation */
+ _ms = ms;
+ _ts = ts;
+ _real_time += Milliseconds(ms_diff);
+
+ unsigned long const new_factor = _ts_to_us_ratio(ts_diff, ms_diff * 1000UL);
+ unsigned long const old_factor = _us_to_ts_factor;
+
+ /* update interpolation-quality value */
+ if (old_factor > new_factor) { _update_interpolation_quality(new_factor, old_factor); }
+ else { _update_interpolation_quality(old_factor, new_factor); }
+
+ _us_to_ts_factor = new_factor;
+}
+
+
+Duration Timer::Connection::_update_interpolated_time(Duration &interpolated_time)
+{
+ /*
+ * The new interpolated time value may be smaller than a
+ * previously interpolated time value (based on an older real time
+ * value and factor). In this case, we don't want the user time to
+ * jump back but to freeze at the higher value until the new
+ * interpolation has caught up.
+ */
+ if (_interpolated_time < interpolated_time) {
+ _interpolated_time = interpolated_time; }
+
+ return _interpolated_time;
+}
+
+
+void Timer::Connection::_handle_timeout()
+{
+ unsigned long const ms = elapsed_ms();
+ if (ms - _ms > REAL_TIME_UPDATE_PERIOD_US / 1000UL) {
+ _update_real_time();
+ }
+ if (_handler) {
+ _handler->handle_timeout(Duration(Milliseconds(ms)));
+ }
+}
+
+
+void Timer::Connection::schedule_timeout(Microseconds duration,
+ Timeout_handler &handler)
+{
+ if (duration.value < MIN_TIMEOUT_US)
+ duration.value = MIN_TIMEOUT_US;
+
+ if (duration.value > REAL_TIME_UPDATE_PERIOD_US)
+ duration.value = REAL_TIME_UPDATE_PERIOD_US;
+
+ _handler = &handler;
+ trigger_once(duration.value);
+}
+
+
+Duration Timer::Connection::curr_time()
+{
+ _enable_modern_mode();
+
+ Reconstructible > lock_guard(_real_time_lock);
+ Duration interpolated_time(_real_time);
+
+ /*
+ * Interpolate with timestamps only if the factor value
+ * remained stable for some time. If we would interpolate with
+ * a yet unstable factor, there's an increased risk that the
+ * interpolated time falsely reaches an enourmous level. Then
+ * the value would stand still for quite some time because we
+ * can't let it jump back to a more realistic level. This
+ * would also eliminate updates of the real time as the
+ * timeout scheduler that manages our update timeout also
+ * uses this function.
+ */
+ if (_interpolation_quality == MAX_INTERPOLATION_QUALITY) {
+
+ /* locally buffer real-time related members */
+ unsigned long const ts = _ts;
+ unsigned long const us_to_ts_factor = _us_to_ts_factor;
+
+ lock_guard.destruct();
+
+ /* get time difference since the last real time update */
+ Timestamp const ts_diff = _timestamp() - ts;
+ unsigned long const us_diff = _ts_to_us_ratio(ts_diff, us_to_ts_factor);
+
+ interpolated_time += Microseconds(us_diff);
+
+ } else {
+
+ /*
+ * Use remote timer instead of timestamps
+ */
+ interpolated_time += Milliseconds(elapsed_ms() - _ms);
+
+ lock_guard.destruct();
+ }
+ return _update_interpolated_time(interpolated_time);
+}
+
+
+void Timer::Connection::_enable_modern_mode()
+{
+ if (_mode == MODERN) {
+ return;
+ }
+ _mode = MODERN;
+ _sigh(_signal_handler);
+ _scheduler._enable();
+}
+
+
+Timer::Connection::Connection(Genode::Env &env, char const *label)
+:
+ Genode::Connection(env, session(env.parent(),
+ "ram_quota=10K, cap_quota=%u, label=\"%s\"",
+ CAP_QUOTA, label)),
+ Session_client(cap()),
+ _signal_handler(env.ep(), *this, &Connection::_handle_timeout)
+{
+ /* register default signal handler */
+ Session_client::sigh(_default_sigh_cap);
+}
+
+
+Timer::Connection::Connection()
+:
+ Genode::Connection(session("ram_quota=10K")),
+ Session_client(cap()),
+ _signal_handler(internal_env().ep(), *this, &Connection::_handle_timeout)
+{
+ /* register default signal handler */
+ Session_client::sigh(_default_sigh_cap);
+}
+
+
+void Timer::Connection::_schedule_one_shot(Timeout &timeout, Microseconds duration)
+{
+ _enable_modern_mode();
+ _scheduler._schedule_one_shot(timeout, duration);
+};
+
+
+void Timer::Connection::_schedule_periodic(Timeout &timeout, Microseconds duration)
+{
+ _enable_modern_mode();
+ _scheduler._schedule_periodic(timeout, duration);
+};
+
+
+void Timer::Connection::_discard(Timeout &timeout)
+{
+ _enable_modern_mode();
+ _scheduler._discard(timeout);
+}
diff --git a/repos/os/src/lib/timeout/timer_connection_timestamp.cc b/repos/os/src/lib/timeout/timer_connection_timestamp.cc
new file mode 100644
index 000000000..8e7928235
--- /dev/null
+++ b/repos/os/src/lib/timeout/timer_connection_timestamp.cc
@@ -0,0 +1,24 @@
+/*
+ * \brief Timestamp implementation for the Genode Timer
+ * \author Martin Stein
+ * \date 2016-11-04
+ */
+
+/*
+ * Copyright (C) 2016-2017 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+
+using namespace Genode;
+
+
+Trace::Timestamp Timer::Connection::_timestamp()
+{
+ return Trace::timestamp();
+}
diff --git a/repos/os/src/server/input_filter/chargen_source.h b/repos/os/src/server/input_filter/chargen_source.h
index 670132583..a256e141c 100644
--- a/repos/os/src/server/input_filter/chargen_source.h
+++ b/repos/os/src/server/input_filter/chargen_source.h
@@ -333,28 +333,28 @@ class Input_filter::Chargen_source : public Source, Source::Sink
*/
struct Char_repeater
{
- Source::Sink &_destination;
- Genode::Timer &_timer;
+ Source::Sink &_destination;
+ Timer::Connection &_timer;
- Time_source::Microseconds const _delay;
- Time_source::Microseconds const _rate;
+ Microseconds const _delay;
+ Microseconds const _rate;
Input::Event::Utf8 _curr_character { 0 };
enum State { IDLE, REPEAT } _state;
- void _handle_timeout(Time_source::Microseconds)
+ void _handle_timeout(Duration)
{
if (_state == REPEAT) {
_destination.submit_event(Input::Event(_curr_character));
- _timeout.start(_rate);
+ _timeout.schedule(_rate);
}
}
- One_shot_timeout _timeout {
+ Timer::One_shot_timeout _timeout {
_timer, *this, &Char_repeater::_handle_timeout };
- Char_repeater(Source::Sink &destination, Genode::Timer &timer,
+ Char_repeater(Source::Sink &destination, Timer::Connection &timer,
Xml_node node)
:
_destination(destination), _timer(timer),
@@ -367,7 +367,7 @@ class Input_filter::Chargen_source : public Source, Source::Sink
_curr_character = character;
_state = REPEAT;
- _timeout.start(_delay);
+ _timeout.schedule(_delay);
}
void cancel()
diff --git a/repos/os/src/server/input_filter/main.cc b/repos/os/src/server/input_filter/main.cc
index f42dc4105..0209f53c8 100644
--- a/repos/os/src/server/input_filter/main.cc
+++ b/repos/os/src/server/input_filter/main.cc
@@ -52,10 +52,9 @@ struct Input_filter::Main : Input_connection::Avail_handler,
{
struct Lazy
{
- Timer::Connection connection;
- Genode::Timer timer;
+ Timer::Connection timer;
- Lazy(Env &env) : connection(env), timer(connection, env.ep()) { }
+ Lazy(Env &env) : timer(env) { }
};
Env &_env;
@@ -67,7 +66,7 @@ struct Input_filter::Main : Input_connection::Avail_handler,
/**
* Timer_accessor interface
*/
- Genode::Timer &timer() override
+ Timer::Connection &timer() override
{
if (!lazy.constructed())
lazy.construct(_env);
diff --git a/repos/os/src/server/input_filter/target.mk b/repos/os/src/server/input_filter/target.mk
index af45ee015..dc5b5350d 100644
--- a/repos/os/src/server/input_filter/target.mk
+++ b/repos/os/src/server/input_filter/target.mk
@@ -1,4 +1,4 @@
TARGET = input_filter
SRC_CC = main.cc
-LIBS = base timeout
+LIBS = base
INC_DIR += $(PRG_DIR)
diff --git a/repos/os/src/server/input_filter/timer_accessor.h b/repos/os/src/server/input_filter/timer_accessor.h
index dfecc45a3..7bfe0bef3 100644
--- a/repos/os/src/server/input_filter/timer_accessor.h
+++ b/repos/os/src/server/input_filter/timer_accessor.h
@@ -15,10 +15,10 @@
#define _INPUT_FILTER__TIMER_ACCESSOR_H_
/* Genode includes */
-#include
+#include
namespace Input_filter { struct Timer_accessor; }
-struct Input_filter::Timer_accessor { virtual Genode::Timer &timer() = 0; };
+struct Input_filter::Timer_accessor { virtual Timer::Connection &timer() = 0; };
#endif /* _INPUT_FILTER__TIMER_ACCESSOR_H_ */
diff --git a/repos/os/src/server/nic_dump/component.cc b/repos/os/src/server/nic_dump/component.cc
index 4a6af43e2..fc67efce5 100644
--- a/repos/os/src/server/nic_dump/component.cc
+++ b/repos/os/src/server/nic_dump/component.cc
@@ -54,17 +54,17 @@ Session_component_base(Allocator &guarded_alloc_backing,
** Session_component **
***********************/
-Net::Session_component::Session_component(Allocator &alloc,
- size_t const amount,
- Ram_session &buf_ram,
- size_t const tx_buf_size,
- size_t const rx_buf_size,
- Region_map ®ion_map,
- Uplink &uplink,
- Xml_node config,
- Genode::Timer &timer,
- unsigned &curr_time,
- Entrypoint &ep)
+Net::Session_component::Session_component(Allocator &alloc,
+ size_t const amount,
+ Ram_session &buf_ram,
+ size_t const tx_buf_size,
+ size_t const rx_buf_size,
+ Region_map ®ion_map,
+ Uplink &uplink,
+ Xml_node config,
+ Timer::Connection &timer,
+ unsigned &curr_time,
+ Entrypoint &ep)
:
Session_component_base(alloc, amount, buf_ram, tx_buf_size, rx_buf_size),
Session_rpc_object(region_map, _tx_buf, _rx_buf, &_range_alloc, ep.rpc_ep()),
@@ -99,14 +99,14 @@ void Session_component::link_state_sigh(Signal_context_capability sigh)
** Root **
**********/
-Net::Root::Root(Entrypoint &ep,
- Allocator &alloc,
- Uplink &uplink,
- Ram_session &buf_ram,
- Xml_node config,
- Genode::Timer &timer,
- unsigned &curr_time,
- Region_map ®ion_map)
+Net::Root::Root(Entrypoint &ep,
+ Allocator &alloc,
+ Uplink &uplink,
+ Ram_session &buf_ram,
+ Xml_node config,
+ Timer::Connection &timer,
+ unsigned &curr_time,
+ Region_map ®ion_map)
:
Root_component(&ep.rpc_ep(),
&alloc),
diff --git a/repos/os/src/server/nic_dump/component.h b/repos/os/src/server/nic_dump/component.h
index 9e08745c3..1ebbcab1e 100644
--- a/repos/os/src/server/nic_dump/component.h
+++ b/repos/os/src/server/nic_dump/component.h
@@ -93,7 +93,7 @@ class Net::Session_component : public Session_component_base,
Genode::Region_map ®ion_map,
Uplink &uplink,
Genode::Xml_node config,
- Genode::Timer &timer,
+ Timer::Connection &timer,
unsigned &curr_time,
Genode::Entrypoint &ep);
@@ -118,7 +118,7 @@ class Net::Root : public Genode::Root_component
#include
-#include
+#include
namespace Net {
@@ -49,7 +49,7 @@ class Net::Interface
Genode::Allocator &_alloc;
Pointer _remote;
Interface_label _label;
- Genode::Timer &_timer;
+ Timer::Connection &_timer;
unsigned &_curr_time;
bool _log_time;
@@ -77,7 +77,7 @@ class Net::Interface
Interface(Genode::Entrypoint &ep,
Interface_label label,
- Genode::Timer &timer,
+ Timer::Connection &timer,
unsigned &curr_time,
bool log_time,
Genode::Allocator &alloc);
diff --git a/repos/os/src/server/nic_dump/main.cc b/repos/os/src/server/nic_dump/main.cc
index 193e25706..f225aa07b 100644
--- a/repos/os/src/server/nic_dump/main.cc
+++ b/repos/os/src/server/nic_dump/main.cc
@@ -30,8 +30,7 @@ class Main
private:
Genode::Attached_rom_dataspace _config;
- Timer::Connection _timer_connection;
- Genode::Timer _timer;
+ Timer::Connection _timer;
unsigned _curr_time { 0 };
Genode::Heap _heap;
Uplink _uplink;
@@ -45,8 +44,7 @@ class Main
Main::Main(Env &env)
:
- _config(env, "config"), _timer_connection(env),
- _timer(_timer_connection, env.ep()), _heap(&env.ram(), &env.rm()),
+ _config(env, "config"), _timer(env), _heap(&env.ram(), &env.rm()),
_uplink(env, _config.xml(), _timer, _curr_time, _heap),
_root(env.ep(), _heap, _uplink, env.ram(), _config.xml(), _timer,
_curr_time, env.rm())
diff --git a/repos/os/src/server/nic_dump/target.mk b/repos/os/src/server/nic_dump/target.mk
index a8e7ae9f8..7737008c7 100644
--- a/repos/os/src/server/nic_dump/target.mk
+++ b/repos/os/src/server/nic_dump/target.mk
@@ -1,6 +1,6 @@
TARGET = nic_dump
-LIBS += base net config timeout
+LIBS += base net config
SRC_CC += component.cc main.cc uplink.cc interface.cc
diff --git a/repos/os/src/server/nic_dump/uplink.cc b/repos/os/src/server/nic_dump/uplink.cc
index 2d92f669b..82f124c88 100644
--- a/repos/os/src/server/nic_dump/uplink.cc
+++ b/repos/os/src/server/nic_dump/uplink.cc
@@ -22,11 +22,11 @@ using namespace Net;
using namespace Genode;
-Net::Uplink::Uplink(Env &env,
- Xml_node config,
- Genode::Timer &timer,
- unsigned &curr_time,
- Allocator &alloc)
+Net::Uplink::Uplink(Env &env,
+ Xml_node config,
+ Timer::Connection &timer,
+ unsigned &curr_time,
+ Allocator &alloc)
:
Nic::Packet_allocator(&alloc),
Nic::Connection(env, this, BUF_SIZE, BUF_SIZE),
diff --git a/repos/os/src/server/nic_dump/uplink.h b/repos/os/src/server/nic_dump/uplink.h
index ec6687057..b81339e8f 100644
--- a/repos/os/src/server/nic_dump/uplink.h
+++ b/repos/os/src/server/nic_dump/uplink.h
@@ -46,7 +46,7 @@ class Net::Uplink : public Nic::Packet_allocator,
Uplink(Genode::Env &env,
Genode::Xml_node config,
- Genode::Timer &timer,
+ Timer::Connection &timer,
unsigned &curr_time,
Genode::Allocator &alloc);
};
diff --git a/repos/os/src/server/nic_router/component.cc b/repos/os/src/server/nic_router/component.cc
index a8bd64c87..3ab9ec0ac 100644
--- a/repos/os/src/server/nic_router/component.cc
+++ b/repos/os/src/server/nic_router/component.cc
@@ -55,7 +55,7 @@ Session_component_base(Allocator &guarded_alloc_backing,
***********************/
Net::Session_component::Session_component(Allocator &alloc,
- Genode::Timer &timer,
+ Timer::Connection &timer,
size_t const amount,
Ram_session &buf_ram,
size_t const tx_buf_size,
@@ -95,7 +95,7 @@ void Session_component::link_state_sigh(Signal_context_capability sigh)
**********/
Net::Root::Root(Entrypoint &ep,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Allocator &alloc,
Mac_address const &router_mac,
Configuration &config,
diff --git a/repos/os/src/server/nic_router/component.h b/repos/os/src/server/nic_router/component.h
index ba2c03117..f47dbfda3 100644
--- a/repos/os/src/server/nic_router/component.h
+++ b/repos/os/src/server/nic_router/component.h
@@ -84,7 +84,7 @@ class Net::Session_component : public Session_component_base,
public:
Session_component(Genode::Allocator &alloc,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Genode::size_t const amount,
Genode::Ram_session &buf_ram,
Genode::size_t const tx_buf_size,
@@ -110,7 +110,7 @@ class Net::Root : public Genode::Root_component
{
private:
- Genode::Timer &_timer;
+ Timer::Connection &_timer;
Mac_allocator _mac_alloc;
Genode::Entrypoint &_ep;
Mac_address const _router_mac;
@@ -128,7 +128,7 @@ class Net::Root : public Genode::Root_component
public:
Root(Genode::Entrypoint &ep,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Genode::Allocator &alloc,
Mac_address const &router_mac,
Configuration &config,
diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc
index 16fb4446c..e45a81264 100644
--- a/repos/os/src/server/nic_router/interface.cc
+++ b/repos/os/src/server/nic_router/interface.cc
@@ -570,7 +570,7 @@ void Interface::_send(Ethernet_frame ð, Genode::size_t const size)
Interface::Interface(Entrypoint &ep,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Mac_address const router_mac,
Genode::Allocator &alloc,
Mac_address const mac,
diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h
index 3898e9a2d..683416304 100644
--- a/repos/os/src/server/nic_router/interface.h
+++ b/repos/os/src/server/nic_router/interface.h
@@ -52,7 +52,7 @@ class Net::Interface
private:
- Genode::Timer &_timer;
+ Timer::Connection &_timer;
Genode::Allocator &_alloc;
Domain &_domain;
Arp_cache _arp_cache;
@@ -150,7 +150,7 @@ class Net::Interface
struct Packet_postponed : Genode::Exception { };
Interface(Genode::Entrypoint &ep,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Mac_address const router_mac,
Genode::Allocator &alloc,
Mac_address const mac,
diff --git a/repos/os/src/server/nic_router/link.cc b/repos/os/src/server/nic_router/link.cc
index f4cb023d4..a1ec89425 100644
--- a/repos/os/src/server/nic_router/link.cc
+++ b/repos/os/src/server/nic_router/link.cc
@@ -115,7 +115,7 @@ Link::Link(Interface &cln_interface,
Pointer const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Configuration &config,
uint8_t const protocol)
:
@@ -127,11 +127,11 @@ Link::Link(Interface &cln_interface,
_close_timeout_us(_config.rtt_sec() * 2 * 1000 * 1000),
_protocol(protocol)
{
- _close_timeout.start(_close_timeout_us);
+ _close_timeout.schedule(_close_timeout_us);
}
-void Link::_handle_close_timeout(Genode::Timer::Microseconds)
+void Link::_handle_close_timeout(Duration)
{
dissolve();
_client._interface.link_closed(*this, _protocol);
@@ -167,7 +167,7 @@ Tcp_link::Tcp_link(Interface &cln_interface,
Pointer const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Configuration &config,
uint8_t const protocol)
:
@@ -179,7 +179,7 @@ Tcp_link::Tcp_link(Interface &cln_interface,
void Tcp_link::_fin_acked()
{
if (_server_fin_acked && _client_fin_acked) {
- _close_timeout.start(_close_timeout_us);
+ _close_timeout.schedule(_close_timeout_us);
_closed = true;
}
}
@@ -228,7 +228,7 @@ Udp_link::Udp_link(Interface &cln_interface,
Pointer const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Configuration &config,
uint8_t const protocol)
:
diff --git a/repos/os/src/server/nic_router/link.h b/repos/os/src/server/nic_router/link.h
index 44492722f..56f5c5e2d 100644
--- a/repos/os/src/server/nic_router/link.h
+++ b/repos/os/src/server/nic_router/link.h
@@ -15,7 +15,7 @@
#define _LINK_H_
/* Genode includes */
-#include
+#include
#include
#include
#include
@@ -129,13 +129,13 @@ class Net::Link : public Link_list::Element
Link_side _client;
Pointer const _server_port_alloc;
Link_side _server;
- Genode::One_shot_timeout _close_timeout;
- Genode::Timer::Microseconds const _close_timeout_us;
+ Timer::One_shot_timeout _close_timeout;
+ Genode::Microseconds const _close_timeout_us;
Genode::uint8_t const _protocol;
- void _handle_close_timeout(Genode::Timer::Microseconds);
+ void _handle_close_timeout(Genode::Duration);
- void _packet() { _close_timeout.start(_close_timeout_us); }
+ void _packet() { _close_timeout.schedule(_close_timeout_us); }
public:
@@ -146,7 +146,7 @@ class Net::Link : public Link_list::Element
Pointer const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Configuration &config,
Genode::uint8_t const protocol);
@@ -188,7 +188,7 @@ class Net::Tcp_link : public Link
Pointer const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Configuration &config,
Genode::uint8_t const protocol);
@@ -205,7 +205,7 @@ struct Net::Udp_link : Link
Pointer const srv_port_alloc,
Interface &srv_interface,
Link_side_id const &srv_id,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Configuration &config,
Genode::uint8_t const protocol);
diff --git a/repos/os/src/server/nic_router/main.cc b/repos/os/src/server/nic_router/main.cc
index 3c2720434..76de05c23 100644
--- a/repos/os/src/server/nic_router/main.cc
+++ b/repos/os/src/server/nic_router/main.cc
@@ -15,7 +15,6 @@
#include
#include
#include
-#include
#include
#include
@@ -32,8 +31,7 @@ class Main
{
private:
- Timer::Connection _timer_connection;
- Genode::Timer _timer;
+ Timer::Connection _timer;
Genode::Heap _heap;
Genode::Attached_rom_dataspace _config_rom;
Configuration _config;
@@ -48,12 +46,10 @@ class Main
Main::Main(Env &env)
:
- _timer_connection(env), _timer(_timer_connection, env.ep()),
- _heap(&env.ram(), &env.rm()), _config_rom(env, "config"),
- _config(_config_rom.xml(), _heap),
- _uplink(env, _timer, _heap, _config),
- _root(env.ep(), _timer, _heap, _uplink.router_mac(), _config, env.ram(),
- env.rm())
+ _timer(env), _heap(&env.ram(), &env.rm()), _config_rom(env, "config"),
+ _config(_config_rom.xml(), _heap), _uplink(env, _timer, _heap, _config),
+ _root(env.ep(), _timer, _heap, _uplink.router_mac(), _config,
+ env.ram(), env.rm())
{
env.parent().announce(env.ep().manage(_root));
}
diff --git a/repos/os/src/server/nic_router/target.mk b/repos/os/src/server/nic_router/target.mk
index aa1e192c8..3404d8d9a 100644
--- a/repos/os/src/server/nic_router/target.mk
+++ b/repos/os/src/server/nic_router/target.mk
@@ -1,6 +1,6 @@
TARGET = nic_router
-LIBS += base net config timeout
+LIBS += base net config
SRC_CC += arp_waiter.cc ip_rule.cc
SRC_CC += component.cc port_allocator.cc forward_rule.cc
diff --git a/repos/os/src/server/nic_router/uplink.cc b/repos/os/src/server/nic_router/uplink.cc
index d2d5bdf99..61de2afc4 100644
--- a/repos/os/src/server/nic_router/uplink.cc
+++ b/repos/os/src/server/nic_router/uplink.cc
@@ -24,7 +24,7 @@ using namespace Genode;
Net::Uplink::Uplink(Env &env,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Genode::Allocator &alloc,
Configuration &config)
:
diff --git a/repos/os/src/server/nic_router/uplink.h b/repos/os/src/server/nic_router/uplink.h
index d6358c4a1..0d6165fdc 100644
--- a/repos/os/src/server/nic_router/uplink.h
+++ b/repos/os/src/server/nic_router/uplink.h
@@ -47,7 +47,7 @@ class Net::Uplink : public Nic::Packet_allocator,
public:
Uplink(Genode::Env &env,
- Genode::Timer &timer,
+ Timer::Connection &timer,
Genode::Allocator &alloc,
Configuration &config);
diff --git a/repos/os/src/test/timeout/main.cc b/repos/os/src/test/timeout/main.cc
index 107f8d316..d9c79be82 100644
--- a/repos/os/src/test/timeout/main.cc
+++ b/repos/os/src/test/timeout/main.cc
@@ -13,42 +13,553 @@
/* Genode includes */
#include
+#include
#include
-#include
-
+#include
+#include
using namespace Genode;
-class Main
+struct Test
{
- private:
+ Env &env;
+ unsigned &error_cnt;
+ Signal_transmitter done;
+ unsigned id;
+ Timer::Connection timer_connection { env };
+ Timer::Connection timer { env };
- using Microseconds = Genode::Timer::Microseconds;
+ Test(Env &env,
+ unsigned &error_cnt,
+ Signal_context_capability done,
+ unsigned id,
+ char const *brief)
+ :
+ env(env), error_cnt(error_cnt), done(done), id(id)
+ {
+ /*
+ * FIXME Activate interpolation early to give it some time to
+ * calibrate. Otherwise, we may get non-representative
+ * results in at least the fast-polling test, which starts
+ * directly with the heaviest load. This is only necessary
+ * because Timer::Connection by now must be backwards compatible
+ * and therefore starts interpolation only on demand.
+ */
+ timer.curr_time();
- void _handle(Microseconds now, Cstring name) {
- log(now.value / 1000, " ms: ", name, " timeout triggered"); }
+ log("\nTEST ", id, ": ", brief, "\n");
+ }
- void _handle_pt1(Microseconds now) { _handle(now, "Periodic 700ms"); }
- void _handle_pt2(Microseconds now) { _handle(now, "Periodic 1000ms"); }
- void _handle_ot1(Microseconds now) { _handle(now, "One-shot 3250ms"); }
- void _handle_ot2(Microseconds now) { _handle(now, "One-shot 5200ms"); }
+ float percentage(unsigned long value, unsigned long base)
+ {
+ /*
+ * FIXME When base = 0 and value != 0, we normally want to return
+ * FLT_MAX but this causes a compile error. Thus, we use a
+ * pretty high value instead.
+ */
+ return base ? ((float)value / base * 100) : value ? 1000000 : 0;
+ }
- Timer::Connection _timer_connection;
- Genode::Timer _timer;
- Periodic_timeout _pt1 { _timer, *this, &Main::_handle_pt1, Microseconds(700000) };
- Periodic_timeout _pt2 { _timer, *this, &Main::_handle_pt2, Microseconds(1000000) };
- One_shot_timeout _ot1 { _timer, *this, &Main::_handle_ot1 };
- One_shot_timeout _ot2 { _timer, *this, &Main::_handle_ot2 };
+ ~Test() { log("\nTEST ", id, " finished\n"); }
+};
- public:
- Main(Env &env) : _timer_connection(env),
- _timer(_timer_connection, env.ep())
- {
- _ot1.start(Microseconds(3250000));
- _ot2.start(Microseconds(5300000));
+struct Mixed_timeouts : Test
+{
+ static constexpr char const *brief = "schedule multiple timeouts simultaneously";
+
+ enum { NR_OF_EVENTS = 20 };
+ enum { NR_OF_TIMEOUTS = 4 };
+ enum { MAX_ERROR_PC = 10 };
+
+ struct Timeout
+ {
+ char const *const name;
+ Microseconds const us;
+ };
+
+ struct Event
+ {
+ Timeout const *const timeout;
+ Duration const time;
+ };
+
+ Timeout const timeouts[NR_OF_TIMEOUTS] {
+ { "Periodic 700 ms", Microseconds( 700000) },
+ { "Periodic 1000 ms", Microseconds(1000000) },
+ { "One-shot 3250 ms", Microseconds(3250000) },
+ { "One-shot 5200 ms", Microseconds(5200000) }
+ };
+
+ /*
+ * We want to check only timeouts that have a distance of at least
+ * 200ms to each other timeout. Thus, the items in this array that
+ * have an empty name are treated as wildcards and match any timeout.
+ */
+ Event const events[NR_OF_EVENTS] {
+ { nullptr, Duration(Milliseconds(0)) },
+ { nullptr, Duration(Milliseconds(0)) },
+ { &timeouts[0], Duration(Milliseconds(700)) },
+ { &timeouts[1], Duration(Milliseconds(1000)) },
+ { &timeouts[0], Duration(Milliseconds(1400)) },
+ { nullptr, Duration(Milliseconds(2000)) },
+ { nullptr, Duration(Milliseconds(2100)) },
+ { &timeouts[0], Duration(Milliseconds(2800)) },
+ { &timeouts[1], Duration(Milliseconds(3000)) },
+ { &timeouts[2], Duration(Milliseconds(3250)) },
+ { &timeouts[0], Duration(Milliseconds(3500)) },
+ { &timeouts[1], Duration(Milliseconds(4000)) },
+ { &timeouts[0], Duration(Milliseconds(4200)) },
+ { nullptr, Duration(Milliseconds(4900)) },
+ { nullptr, Duration(Milliseconds(5000)) },
+ { &timeouts[3], Duration(Milliseconds(5200)) },
+ { &timeouts[0], Duration(Milliseconds(5600)) },
+ { &timeouts[1], Duration(Milliseconds(6000)) },
+ { &timeouts[0], Duration(Milliseconds(6300)) },
+ { &timeouts[2], Duration(Milliseconds(6500)) }
+ };
+
+ Duration init_time { Microseconds(0) };
+ unsigned event_id { 0 };
+
+ Timer::Periodic_timeout pt1 { timer, *this, &Mixed_timeouts::handle_pt1, timeouts[0].us };
+ Timer::Periodic_timeout pt2 { timer, *this, &Mixed_timeouts::handle_pt2, timeouts[1].us };
+ Timer::One_shot_timeout ot1 { timer, *this, &Mixed_timeouts::handle_ot1 };
+ Timer::One_shot_timeout ot2 { timer, *this, &Mixed_timeouts::handle_ot2 };
+
+ void handle_pt1(Duration time) { handle(time, timeouts[0]); }
+ void handle_pt2(Duration time) { handle(time, timeouts[1]); }
+ void handle_ot1(Duration time) { handle(time, timeouts[2]); ot1.schedule(timeouts[2].us); }
+ void handle_ot2(Duration time) { handle(time, timeouts[3]); }
+
+ void handle(Duration time, Timeout const &timeout)
+ {
+ if (event_id == NR_OF_EVENTS) {
+ return; }
+
+ if (!event_id) {
+ init_time = time; }
+
+ Event const &event = events[event_id++];
+ unsigned long time_us = time.trunc_to_plain_us().value -
+ init_time.trunc_to_plain_us().value;
+
+ unsigned long event_time_us = event.time.trunc_to_plain_us().value;
+ unsigned long error_us = max(time_us, event_time_us) -
+ min(time_us, event_time_us);
+
+ float const error_pc = percentage(error_us, timeout.us.value);
+
+ log(time_us / 1000UL, " ms: ", timeout.name, " timeout triggered,"
+ " error ", error_us, " us (", error_pc, " %)");
+
+ if (error_pc > MAX_ERROR_PC) {
+
+ error("absolute timeout error greater than ", (unsigned)MAX_ERROR_PC, " %");
+ error_cnt++;
}
+ if (event.timeout && event.timeout != &timeout) {
+
+ error("expected timeout ", timeout.name);
+ error_cnt++;
+ }
+ if (event_id == NR_OF_EVENTS) {
+ done.submit(); }
+ }
+
+ Mixed_timeouts(Env &env,
+ unsigned &error_cnt,
+ Signal_context_capability done,
+ unsigned id)
+ :
+ Test(env, error_cnt, done, id, brief)
+ {
+ ot1.schedule(timeouts[2].us);
+ ot2.schedule(timeouts[3].us);
+ }
+};
+
+
+struct Fast_polling : Test
+{
+ static constexpr char const *brief = "poll time pretty fast";
+
+ enum { NR_OF_ROUNDS = 4 };
+ enum { MIN_ROUND_DURATION_MS = 2000 };
+ enum { MAX_NR_OF_POLLS = 10000000 };
+ enum { MIN_NR_OF_POLLS = 1000 };
+ enum { STACK_SIZE = 4 * 1024 * sizeof(addr_t) };
+ enum { MIN_TIME_COMPARISONS = 100 };
+ enum { MAX_TIME_ERR_US = 10000 };
+ enum { MAX_AVG_TIME_ERR_US = 1000 };
+ enum { MAX_DELAY_ERR_US = 2000 };
+ enum { MAX_AVG_DELAY_ERR_US = 20 };
+ enum { MAX_POLL_LATENCY_US = 1000 };
+ enum { BUF_SIZE = MAX_NR_OF_POLLS * sizeof(unsigned long) };
+
+ Entrypoint main_ep;
+ Signal_handler main_handler;
+
+ Attached_ram_dataspace local_us_buf_1 { env.ram(), env.rm(), BUF_SIZE };
+ Attached_ram_dataspace local_us_buf_2 { env.ram(), env.rm(), BUF_SIZE };
+ Attached_ram_dataspace remote_ms_buf { env.ram(), env.rm(), BUF_SIZE };
+ unsigned long volatile *local_us_1 { local_us_buf_1.local_addr() };
+ unsigned long volatile *local_us_2 { local_us_buf_2.local_addr() };
+ unsigned long volatile *remote_ms { remote_ms_buf.local_addr() };
+
+ unsigned const delay_loops_per_poll[NR_OF_ROUNDS] { 1,
+ 1000,
+ 10000,
+ 100000 };
+
+ /*
+ * Accumulates great amounts of integer values to one average value
+ *
+ * Aims for best possible precision with a fixed amount of integer buffers
+ */
+ struct Average_accumulator
+ {
+ private:
+
+ unsigned long _avg { 0 };
+ unsigned long _avg_cnt { 0 };
+ unsigned long _acc { 0 };
+ unsigned long _acc_cnt { 0 };
+
+ public:
+
+ void flush()
+ {
+ unsigned long acc_avg = _acc / _acc_cnt;
+ if (!_avg_cnt) { _avg = _avg + acc_avg; }
+ else {
+ float acc_fac = (float)_acc_cnt / _avg_cnt;
+ _avg = (_avg + ((float)acc_fac * acc_avg)) / (1 + acc_fac);
+ }
+ _avg_cnt += _acc_cnt;
+ _acc = 0;
+ _acc_cnt = 0;
+ }
+
+ void add(unsigned long add)
+ {
+ if (add > (~0UL - _acc)) {
+ flush(); }
+ _acc += add;
+ _acc_cnt++;
+ }
+
+ unsigned long avg()
+ {
+ if (_acc_cnt) {
+ flush(); }
+ return _avg;
+ }
+
+ unsigned long avg_cnt()
+ {
+ if (_acc_cnt) {
+ flush(); }
+ return _avg_cnt;
+ }
+ };
+
+ unsigned long delay_us(unsigned poll)
+ {
+ return local_us_1[poll - 1] > local_us_1[poll] ?
+ local_us_1[poll - 1] - local_us_1[poll] :
+ local_us_1[poll] - local_us_1[poll - 1];
+ }
+
+ unsigned long estimate_delay_loops_per_ms()
+ {
+ log("estimate CPU speed ...");
+ for (unsigned long max_cnt = 1000UL * 1000UL; ; max_cnt *= 2) {
+
+ /* measure consumed time of a limited busy loop */
+ unsigned long volatile start_ms = timer_connection.elapsed_ms();
+ for (unsigned long volatile cnt = 0; cnt < max_cnt; cnt++) { }
+ unsigned long volatile end_ms = timer_connection.elapsed_ms();
+
+ /*
+ * We only return the result if the loop was time intensive enough
+ * and therefore representative. Otherwise we raise the loop-
+ * counter limit and do a new estimation.
+ */
+ unsigned long diff_ms = end_ms - start_ms;
+ if (diff_ms > 1000UL) {
+ return max_cnt / diff_ms; }
+ }
+ }
+
+ void main()
+ {
+ /*
+ * Estimate CPU speed
+ *
+ * The test delays must be done through busy spinning. If we would
+ * use a timer session instead, we could not produce delays of only a
+ * few microseconds. Thus, to get similar delays on each platform we
+ * have to do this estimation.
+ */
+ unsigned long volatile delay_loops_per_remote_poll =
+ estimate_delay_loops_per_ms() / 100;
+
+ /* do several rounds of the test with different parameters each */
+ for (unsigned round = 0; round < NR_OF_ROUNDS; round++) {
+
+ /* print round parameters */
+ log("");
+ log("--- Round ", round + 1,
+ ": polling delay ", delay_loops_per_poll[round], " loop(s) ---");
+ log("");
+
+ unsigned long volatile delay_loops = 0;
+
+ unsigned long nr_of_polls = MAX_NR_OF_POLLS;
+ unsigned long delay_loops_per_poll_ = delay_loops_per_poll[round];
+ unsigned long end_remote_ms = timer_connection.elapsed_ms() +
+ MIN_ROUND_DURATION_MS;
+
+ /* limit polling to our buffer capacity */
+ for (unsigned poll = 0; poll < nr_of_polls; poll++) {
+
+ /* create delay between two polls */
+ for (unsigned long volatile i = 0; i < delay_loops_per_poll_; i++) { }
+
+ /* count delay loops to limit frequency of remote time reading */
+ delay_loops += delay_loops_per_poll_;
+
+ /*
+ * We buffer the results in local variables first so the RAM
+ * access wont raise the delay between the reading of the
+ * different time values.
+ */
+ unsigned long volatile local_us_1_;
+ unsigned long volatile local_us_2_;
+ unsigned long volatile remote_ms_;
+
+ /* read local time before the remote time reading */
+ local_us_1_ = timer.curr_time().trunc_to_plain_us().value;
+
+ /*
+ * Limit frequency of remote-time reading
+ *
+ * If we would stress the timer connection to much, the
+ * back-end functionality of the timeout framework would
+ * remarkably slow down which causes a phase of adaption with
+ * bigger errors. But the goal of the framework is to spare
+ * calls to timer connections anyway. So, its fine to limit
+ * the polling frequency here.
+ */
+ if (delay_loops > delay_loops_per_remote_poll) {
+
+ /* read remote time and second local time */
+ remote_ms_ = timer_connection.elapsed_ms();
+ local_us_2_ = timer.curr_time().trunc_to_plain_us().value;
+
+ /* reset delay counter for remote-time reading */
+ delay_loops = 0;
+
+ } else {
+
+ /* mark remote-time and second local-time value invalid */
+ remote_ms_ = 0;
+ local_us_2_ = 0;
+ }
+ /* store results to the buffers */
+ remote_ms[poll] = remote_ms_;
+ local_us_1[poll] = local_us_1_;
+ local_us_2[poll] = local_us_2_;
+
+ /* if the minimum round duration is reached, end polling */
+ if (remote_ms_ > end_remote_ms) {
+ nr_of_polls = poll + 1;
+ break;
+ }
+ }
+
+ /*
+ * Mark results with a bad latency dismissed
+ *
+ * It might be, that we got scheduled away between reading out
+ * local and remote time. This would cause the test result to
+ * be much worse than the actual precision of the timeout
+ * framework. Thus, we ignore such results.
+ */
+ unsigned nr_of_good_polls = 0;
+ unsigned nr_of_bad_polls = 0;
+ for (unsigned poll = 0; poll < nr_of_polls; poll++) {
+
+ if (remote_ms[poll] &&
+ local_us_2[poll] - local_us_1[poll] > MAX_POLL_LATENCY_US)
+ {
+ local_us_1[poll] = 0;
+ nr_of_bad_polls++;
+
+ } else {
+
+ nr_of_good_polls++; }
+ }
+
+ /*
+ * Calculate the average delay between consecutive polls
+ * (using the local time).
+ */
+ Average_accumulator avg_delay_us;
+ for (unsigned poll = 1; poll < nr_of_polls; poll++) {
+
+ /* skip if this result was dismissed */
+ if (!local_us_1[poll]) {
+ poll++;
+ continue;
+ }
+ /* check if local time is monotone */
+ if (local_us_1[poll - 1] > local_us_1[poll]) {
+
+ error("time is not monotone at poll #", poll);
+ error_cnt++;
+ }
+ /* check out delay between this poll and the last one */
+ avg_delay_us.add(delay_us(poll));
+ }
+
+ /*
+ * Calculate the average and maximum error of the local time
+ * compared to the remote time as well as the duration of the
+ * whole test round.
+ */
+ Average_accumulator avg_time_err_us;
+ unsigned long max_time_err_us = 0UL;
+
+ for (unsigned poll = 0; poll < nr_of_polls; poll++) {
+
+ /* skip if this result was dismissed */
+ if (!local_us_1[poll]) {
+ continue; }
+
+ /* skip if this poll contains no remote time */
+ if (!remote_ms[poll]) {
+ continue; }
+
+ /* scale-up remote time to microseconds and calculate error */
+ if (remote_ms[poll] > ~0UL / 1000UL) {
+ error("can not translate remote time to microseconds");
+ error_cnt++;
+ }
+ unsigned long const remote_us = remote_ms[poll] * 1000UL;
+ unsigned long const time_err_us = remote_us > local_us_1[poll] ?
+ remote_us - local_us_1[poll] :
+ local_us_1[poll] - remote_us;
+
+ /* update max time error */
+ if (time_err_us > max_time_err_us) {
+ max_time_err_us = time_err_us; }
+
+ /* update average time error */
+ avg_time_err_us.add(time_err_us);
+ }
+ Average_accumulator avg_delay_err_us;
+ unsigned long avg_delay_us_ = avg_delay_us.avg();
+
+ /*
+ * Calculate the average error of the delays compared to the
+ * average delay (in microseconds and percent of the average
+ * delay).
+ */
+ unsigned long max_delay_err_us = 0;
+ for (unsigned poll = 1; poll < nr_of_polls; poll++) {
+
+ /* skip if this result was dismissed */
+ if (!local_us_1[poll]) {
+ poll++;
+ continue;
+ }
+
+ unsigned long delay_us_ = delay_us(poll);
+ unsigned long delay_err_us = delay_us_ > avg_delay_us_ ?
+ delay_us_ - avg_delay_us_ :
+ avg_delay_us_ - delay_us_;
+
+ if (delay_err_us > max_delay_err_us) {
+ max_delay_err_us = delay_err_us; }
+
+ avg_delay_err_us.add(delay_err_us);
+ }
+
+ unsigned long const max_avg_delay_err_us = (unsigned long)MAX_AVG_DELAY_ERR_US +
+ avg_delay_us_ / 20;
+
+ bool const error_nr_of_good_polls = (nr_of_good_polls < MIN_NR_OF_POLLS);
+ bool const error_nr_of_time_cmprs = (avg_time_err_us.avg_cnt() < MIN_TIME_COMPARISONS);
+ bool const error_avg_time_err = (avg_time_err_us.avg() > MAX_AVG_TIME_ERR_US);
+ bool const error_max_time_err = (max_time_err_us > MAX_TIME_ERR_US);
+ bool const error_avg_delay_err = (avg_delay_err_us.avg() > max_avg_delay_err_us);
+
+ error_cnt += error_nr_of_good_polls;
+ error_cnt += error_nr_of_time_cmprs;
+ error_cnt += error_avg_time_err;
+ error_cnt += error_max_time_err;
+ error_cnt += error_avg_delay_err;
+
+ log(error_nr_of_good_polls ? "\033[31mbad: " : "good: ", "nr of good polls ", nr_of_good_polls, " (min ", (unsigned)MIN_NR_OF_POLLS, ")\033[0m");
+ log( " ", "nr of bad polls ", nr_of_bad_polls );
+ log(error_nr_of_time_cmprs ? "\033[31mbad: " : "good: ", "nr of time comparisons ", avg_time_err_us.avg_cnt(), " (min ", (unsigned)MIN_TIME_COMPARISONS, ")\033[0m");
+ log(error_avg_time_err ? "\033[31mbad: " : "good: ", "average time error ", avg_time_err_us.avg(), " us (max ", (unsigned long)MAX_AVG_TIME_ERR_US, " us)\033[0m");
+ log(error_max_time_err ? "\033[31mbad: " : "good: ", "maximum time error ", max_time_err_us, " us (max ", (unsigned long)MAX_TIME_ERR_US, " us)\033[0m");
+ log( " ", "average delay ", avg_delay_us.avg(), " us" );
+ log(error_avg_delay_err ? "\033[31mbad: " : "good: ", "average delay error ", avg_delay_err_us.avg(), " us (max ", max_avg_delay_err_us, " us)\033[0m");
+ log( " ", "maximum delay error ", max_delay_err_us, " us" );
+
+ }
+ done.submit();
+ }
+
+ Fast_polling(Env &env,
+ unsigned &error_cnt,
+ Signal_context_capability done,
+ unsigned id)
+ :
+ Test(env, error_cnt, done, id, brief),
+ main_ep(env, STACK_SIZE, "fast_polling_ep"),
+ main_handler(main_ep, *this, &Fast_polling::main)
+ {
+ Signal_transmitter(main_handler).submit();
+ }
+};
+
+
+struct Main
+{
+ Env &env;
+ unsigned error_cnt { 0 };
+ Constructible test_1;
+ Constructible test_2;
+ Signal_handler test_1_done { env.ep(), *this, &Main::handle_test_1_done };
+ Signal_handler test_2_done { env.ep(), *this, &Main::handle_test_2_done };
+
+ Main(Env &env) : env(env)
+ {
+ test_1.construct(env, error_cnt, test_1_done, 1);
+ }
+
+ void handle_test_1_done()
+ {
+ test_1.destruct();
+ test_2.construct(env, error_cnt, test_2_done, 2);
+ }
+
+ void handle_test_2_done()
+ {
+ test_2.destruct();
+ if (error_cnt) {
+ error("test failed because of ", error_cnt, " error(s)");
+ env.parent().exit(-1);
+ } else {
+ env.parent().exit(0);
+ }
+ }
};
diff --git a/repos/os/src/test/timeout/target.mk b/repos/os/src/test/timeout/target.mk
index 146f03935..d5e522101 100644
--- a/repos/os/src/test/timeout/target.mk
+++ b/repos/os/src/test/timeout/target.mk
@@ -1,4 +1,4 @@
TARGET = test-timeout
SRC_CC += main.cc
-LIBS += base timeout
+LIBS += base
INC_DIR += $(PRG_DIR)