Libc: support monotonic time without RTC

Use the Timer session duration for CLOCK_MONOTONIC and  CLOCK_UPTIME.
Use the Genode::Duration object for passing internal time, it supports
sub-millisecond time and helps disambiguate units of time.

Fix #3018
This commit is contained in:
Emery Hemingway 2018-10-19 15:38:46 +02:00 committed by Christian Helmuth
parent 6178e378c1
commit 3e5ac64ee2
3 changed files with 51 additions and 28 deletions

View File

@ -217,9 +217,9 @@ struct Libc::Timer
Timer(Genode::Env &env) : _timer(env) { } Timer(Genode::Env &env) : _timer(env) { }
unsigned long curr_time() Genode::Duration curr_time()
{ {
return _timer.curr_time().trunc_to_plain_us().value/1000; return _timer.curr_time();
} }
static Microseconds microseconds(unsigned long timeout_ms) static Microseconds microseconds(unsigned long timeout_ms)
@ -281,22 +281,22 @@ struct Libc::Timeout
void start(unsigned long timeout_ms) void start(unsigned long timeout_ms)
{ {
unsigned long const now = _timer_accessor.timer().curr_time(); Milliseconds const now = _timer_accessor.timer().curr_time().trunc_to_plain_ms();
_expired = false; _expired = false;
_absolute_timeout_ms = now + timeout_ms; _absolute_timeout_ms = now.value + timeout_ms;
_timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms)); _timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms));
} }
unsigned long duration_left() const unsigned long duration_left() const
{ {
unsigned long const now = _timer_accessor.timer().curr_time(); Milliseconds const now = _timer_accessor.timer().curr_time().trunc_to_plain_ms();
if (_expired || _absolute_timeout_ms < now) if (_expired || _absolute_timeout_ms < now.value)
return 0; return 0;
return _absolute_timeout_ms - now; return _absolute_timeout_ms - now.value;
} }
}; };
@ -751,7 +751,7 @@ struct Libc::Kernel
} }
} }
unsigned long current_time() Genode::Duration current_time()
{ {
return _timer_accessor.timer().curr_time(); return _timer_accessor.timer().curr_time();
} }
@ -889,7 +889,7 @@ void Libc::dispatch_pending_io_signals()
} }
unsigned long Libc::current_time() Genode::Duration Libc::current_time()
{ {
return kernel->current_time(); return kernel->current_time();
} }

View File

@ -21,6 +21,7 @@
#ifndef _LIBC__TASK_H_ #ifndef _LIBC__TASK_H_
#define _LIBC__TASK_H_ #define _LIBC__TASK_H_
#include <os/duration.h>
#include <util/xml_node.h> #include <util/xml_node.h>
namespace Libc { namespace Libc {
@ -53,7 +54,7 @@ namespace Libc {
/** /**
* Get time since startup in ms * Get time since startup in ms
*/ */
unsigned long current_time(); Genode::Duration current_time();
/** /**
* Suspend main user context and the component entrypoint * Suspend main user context and the component entrypoint

View File

@ -24,32 +24,54 @@ namespace Libc { time_t read_rtc(); }
extern "C" __attribute__((weak)) extern "C" __attribute__((weak))
int clock_gettime(clockid_t clk_id, struct timespec *ts) int clock_gettime(clockid_t clk_id, struct timespec *ts)
{ {
if (!ts) return 0; if (!ts) return Libc::Errno(EFAULT);
static bool initial_rtc_requested = false;
static time_t initial_rtc = 0;
static unsigned long t0 = 0;
/* initialize timespec just in case users do not check for errors */
ts->tv_sec = 0; ts->tv_sec = 0;
ts->tv_nsec = 0; ts->tv_nsec = 0;
/* try to read rtc once */ switch (clk_id) {
if (!initial_rtc_requested) {
initial_rtc_requested = true;
initial_rtc = Libc::read_rtc(); /* IRL wall-time */
case CLOCK_REALTIME:
case CLOCK_SECOND: /* FreeBSD specific */
{
static bool initial_rtc_requested = false;
static time_t initial_rtc = 0;
static unsigned long t0_ms = 0;
if (initial_rtc) /* try to read rtc once */
t0 = Libc::current_time(); if (!initial_rtc_requested) {
initial_rtc_requested = true;
initial_rtc = Libc::read_rtc();
if (initial_rtc) {
t0_ms = Libc::current_time().trunc_to_plain_ms().value;
}
}
if (!initial_rtc) return Libc::Errno(EINVAL);
unsigned long time = Libc::current_time().trunc_to_plain_ms().value - t0_ms;
ts->tv_sec = initial_rtc + time/1000;
ts->tv_nsec = (time % 1000) * (1000*1000);
break;
} }
if (!initial_rtc) /* component uptime */
case CLOCK_MONOTONIC:
case CLOCK_UPTIME:
{
unsigned long us = Libc::current_time().trunc_to_plain_us().value;
ts->tv_sec = us / (1000*1000);
ts->tv_nsec = (us % (1000*1000)) * 1000;
break;
}
default:
return Libc::Errno(EINVAL); return Libc::Errno(EINVAL);
}
unsigned long time = Libc::current_time() - t0;
ts->tv_sec = initial_rtc + time/1000;
ts->tv_nsec = (time % 1000) * (1000*1000);
return 0; return 0;
} }
@ -62,7 +84,7 @@ int gettimeofday(struct timeval *tv, struct timezone *)
struct timespec ts; struct timespec ts;
if (int ret = clock_gettime(0, &ts)) if (int ret = clock_gettime(CLOCK_REALTIME, &ts))
return ret; return ret;
tv->tv_sec = ts.tv_sec; tv->tv_sec = ts.tv_sec;