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) { }
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)
@ -281,22 +281,22 @@ struct Libc::Timeout
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;
_absolute_timeout_ms = now + timeout_ms;
_absolute_timeout_ms = now.value + timeout_ms;
_timeout.schedule(_timer_accessor.timer().microseconds(timeout_ms));
}
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 _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();
}
@ -889,7 +889,7 @@ void Libc::dispatch_pending_io_signals()
}
unsigned long Libc::current_time()
Genode::Duration Libc::current_time()
{
return kernel->current_time();
}

View File

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

View File

@ -24,32 +24,54 @@ namespace Libc { time_t read_rtc(); }
extern "C" __attribute__((weak))
int clock_gettime(clockid_t clk_id, struct timespec *ts)
{
if (!ts) return 0;
static bool initial_rtc_requested = false;
static time_t initial_rtc = 0;
static unsigned long t0 = 0;
if (!ts) return Libc::Errno(EFAULT);
/* initialize timespec just in case users do not check for errors */
ts->tv_sec = 0;
ts->tv_nsec = 0;
/* try to read rtc once */
if (!initial_rtc_requested) {
initial_rtc_requested = true;
switch (clk_id) {
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)
t0 = Libc::current_time();
/* try to read rtc once */
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);
unsigned long time = Libc::current_time() - t0;
ts->tv_sec = initial_rtc + time/1000;
ts->tv_nsec = (time % 1000) * (1000*1000);
}
return 0;
}
@ -62,7 +84,7 @@ int gettimeofday(struct timeval *tv, struct timezone *)
struct timespec ts;
if (int ret = clock_gettime(0, &ts))
if (int ret = clock_gettime(CLOCK_REALTIME, &ts))
return ret;
tv->tv_sec = ts.tv_sec;