mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 00:24:51 +00:00
noux: add time modification
... and set initial time by using RTC session. Up to now Noux used a monotic clock whose initial start value always was '0' (which correlates to the start of the UNIX epoch) to provide a notion of time. In addition it is now possible to use the RTC session to set the initial value for use cases where having a proper real-world time matters. To use the RTC session the 'rtc' attribute of the '<config>' node must be set to 'yes'. Thereby the session becomes a mandatory dependency as Noux will not start without it. Issue #1784
This commit is contained in:
parent
d0bf6d2b52
commit
94b63924ed
@ -96,6 +96,7 @@ struct Noux::Sysio
|
||||
unsigned gid;
|
||||
unsigned long inode;
|
||||
unsigned long device;
|
||||
long long mtime;
|
||||
|
||||
Stat & operator= (Vfs::Directory_service::Stat const &stat)
|
||||
{
|
||||
@ -105,6 +106,7 @@ struct Noux::Sysio
|
||||
gid = stat.gid;
|
||||
inode = stat.inode;
|
||||
device = stat.device;
|
||||
mtime = stat.modification_time.value;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -7,3 +7,4 @@ noux_session
|
||||
terminal_session
|
||||
timer_session
|
||||
posix
|
||||
rtc_session
|
||||
|
@ -397,6 +397,9 @@ static void _sysio_to_stat_struct(Noux::Sysio const *sysio, struct stat *buf)
|
||||
buf->st_blocks = (buf->st_size + FS_BLOCK_SIZE - 1) / FS_BLOCK_SIZE;
|
||||
buf->st_ino = sysio->stat_out.st.inode;
|
||||
buf->st_dev = sysio->stat_out.st.device;
|
||||
|
||||
if (sysio->stat_out.st.mtime >= 0)
|
||||
buf->st_mtime = sysio->stat_out.st.mtime;
|
||||
}
|
||||
|
||||
|
||||
@ -934,6 +937,13 @@ extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz)
|
||||
|
||||
extern "C" int utimes(const char* path, const struct timeval *times)
|
||||
{
|
||||
char * const dst = sysio()->utimes_in.path;
|
||||
size_t const max_len = sizeof(sysio()->utimes_in.path);
|
||||
Genode::strncpy(dst, path, max_len);
|
||||
|
||||
sysio()->utimes_in.sec = times ? times->tv_sec : 0;
|
||||
sysio()->utimes_in.usec = times ? times->tv_usec : 0;
|
||||
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_UTIMES)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <verbose.h>
|
||||
#include <user_info.h>
|
||||
#include <armed_timeout.h>
|
||||
#include <time_info.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
@ -124,6 +125,8 @@ class Noux::Child : public Rpc_object<Session>,
|
||||
|
||||
User_info const &_user_info;
|
||||
|
||||
Time_info const &_time_info;
|
||||
|
||||
Parent_exit *_parent_exit;
|
||||
Kill_broadcaster &_kill_broadcaster;
|
||||
Timer::Connection &_timer_connection;
|
||||
@ -319,6 +322,7 @@ class Noux::Child : public Rpc_object<Session>,
|
||||
Child(Child_policy::Name const &name,
|
||||
Verbose const &verbose,
|
||||
User_info const &user_info,
|
||||
Time_info const &time_info,
|
||||
Parent_exit *parent_exit,
|
||||
Kill_broadcaster &kill_broadcaster,
|
||||
Timer::Connection &timer_connection,
|
||||
@ -342,6 +346,7 @@ class Noux::Child : public Rpc_object<Session>,
|
||||
_name(name),
|
||||
_verbose(verbose),
|
||||
_user_info(user_info),
|
||||
_time_info(time_info),
|
||||
_parent_exit(parent_exit),
|
||||
_kill_broadcaster(kill_broadcaster),
|
||||
_timer_connection(timer_connection),
|
||||
@ -521,6 +526,7 @@ class Noux::Child : public Rpc_object<Session>,
|
||||
Child *child = new (_heap) Child(filename,
|
||||
_verbose,
|
||||
_user_info,
|
||||
_time_info,
|
||||
_parent_exit,
|
||||
_kill_broadcaster,
|
||||
_timer_connection,
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <kill_broadcaster.h>
|
||||
#include <vfs/dir_file_system.h>
|
||||
#include <vfs/simple_env.h>
|
||||
#include <time_info.h>
|
||||
|
||||
namespace Noux {
|
||||
|
||||
@ -98,7 +99,9 @@ connect_stdio(Genode::Env &env,
|
||||
Vfs::File_system &root,
|
||||
Noux::Vfs_io_waiter_registry &vfs_io_waiter_registry,
|
||||
Noux::Terminal_io_channel::Type type,
|
||||
Genode::Allocator &alloc)
|
||||
Genode::Allocator &alloc,
|
||||
Noux::Time_info &time_info,
|
||||
Timer::Connection &timer)
|
||||
{
|
||||
using namespace Vfs;
|
||||
using namespace Noux;
|
||||
@ -142,7 +145,8 @@ connect_stdio(Genode::Env &env,
|
||||
|
||||
return *new (alloc)
|
||||
Vfs_io_channel(path.string(), root.leaf_path(path.string()),
|
||||
vfs_handle, vfs_io_waiter_registry, env.ep());
|
||||
vfs_handle, vfs_io_waiter_registry, env.ep(),
|
||||
time_info, timer);
|
||||
}
|
||||
|
||||
|
||||
@ -241,6 +245,8 @@ struct Noux::Main
|
||||
|
||||
User_info _user_info { _config.xml() };
|
||||
|
||||
Time_info _time_info { _env, _config.xml() };
|
||||
|
||||
Signal_handler<Main> _destruct_handler {
|
||||
_env.ep(), *this, &Main::_handle_destruct };
|
||||
|
||||
@ -273,6 +279,7 @@ struct Noux::Main
|
||||
Noux::Child _init_child { _name_of_init_process(),
|
||||
_verbose,
|
||||
_user_info,
|
||||
_time_info,
|
||||
0,
|
||||
_kill_broadcaster,
|
||||
_timer_connection,
|
||||
@ -302,13 +309,13 @@ struct Noux::Main
|
||||
Shared_pointer<Io_channel>
|
||||
_channel_0 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir,
|
||||
_io_response_handler.io_waiter_registry,
|
||||
Tio::STDIN, _heap), _heap },
|
||||
Tio::STDIN, _heap, _time_info, _timer_connection), _heap },
|
||||
_channel_1 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir,
|
||||
_io_response_handler.io_waiter_registry,
|
||||
Tio::STDOUT, _heap), _heap },
|
||||
Tio::STDOUT, _heap, _time_info, _timer_connection), _heap },
|
||||
_channel_2 { &connect_stdio(_env, _terminal, _config.xml(), _root_dir,
|
||||
_io_response_handler.io_waiter_registry,
|
||||
Tio::STDERR, _heap), _heap };
|
||||
Tio::STDERR, _heap, _time_info, _timer_connection), _heap };
|
||||
|
||||
Main(Env &env) : _env(env)
|
||||
{
|
||||
|
@ -238,7 +238,9 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
leaf_path,
|
||||
vfs_handle,
|
||||
_vfs_io_waiter_registry,
|
||||
_env.ep()),
|
||||
_env.ep(),
|
||||
_time_info,
|
||||
_timer_connection),
|
||||
_heap);
|
||||
|
||||
_sysio.open_out.fd = add_io_channel(channel);
|
||||
@ -511,6 +513,7 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
child = new (_heap) Child(_child_policy.name(),
|
||||
_verbose,
|
||||
_user_info,
|
||||
_time_info,
|
||||
this,
|
||||
_kill_broadcaster,
|
||||
_timer_connection,
|
||||
@ -844,7 +847,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
Milliseconds const ms =
|
||||
_timer_connection.curr_time().trunc_to_plain_ms();
|
||||
|
||||
_sysio.gettimeofday_out.sec = (ms.value / 1000);
|
||||
_sysio.gettimeofday_out.sec = _time_info.initial_time();
|
||||
_sysio.gettimeofday_out.sec += (ms.value / 1000);
|
||||
_sysio.gettimeofday_out.usec = (ms.value % 1000) * 1000;
|
||||
|
||||
result = true;
|
||||
@ -864,7 +868,8 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
/* CLOCK_SECOND is used by time(3) in the libc. */
|
||||
case Sysio::CLOCK_ID_SECOND:
|
||||
{
|
||||
_sysio.clock_gettime_out.sec = (ms.value / 1000);
|
||||
_sysio.clock_gettime_out.sec = _time_info.initial_time();
|
||||
_sysio.clock_gettime_out.sec += (ms.value / 1000);
|
||||
_sysio.clock_gettime_out.nsec = 0;
|
||||
|
||||
result = true;
|
||||
@ -889,13 +894,42 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
|
||||
case SYSCALL_UTIMES:
|
||||
{
|
||||
/**
|
||||
* This systemcall is currently not implemented because we lack
|
||||
* the needed mechanisms in most file-systems.
|
||||
*
|
||||
* But we return true anyway to keep certain programs, e.g. make
|
||||
* happy.
|
||||
* Always return true, even if 'update_modification_timestamp'
|
||||
* failed to keep programs, e.g. make, happy.
|
||||
*/
|
||||
result = true;
|
||||
|
||||
char const *path = (char const *)_sysio.utimes_in.path;
|
||||
unsigned long sec = _sysio.utimes_in.sec;
|
||||
unsigned long usec = _sysio.utimes_in.usec;
|
||||
(void)usec;
|
||||
|
||||
Vfs::Vfs_handle *vfs_handle = 0;
|
||||
_root_dir.open(path, 0, &vfs_handle, _heap);
|
||||
if (!vfs_handle) { break; }
|
||||
|
||||
if (!sec) {
|
||||
Milliseconds const ms =
|
||||
_timer_connection.curr_time().trunc_to_plain_ms();
|
||||
sec = _time_info.initial_time();
|
||||
sec += (ms.value / 1000);
|
||||
usec = (ms.value % 1000) * 1000;
|
||||
}
|
||||
|
||||
Registered_no_delete<Vfs_io_waiter>
|
||||
vfs_io_waiter(_vfs_io_waiter_registry);
|
||||
|
||||
Vfs::Timestamp ts { .value = (long long)sec };
|
||||
|
||||
for (;;) {
|
||||
if (vfs_handle->fs().update_modification_timestamp(vfs_handle, ts)) {
|
||||
break;
|
||||
} else {
|
||||
vfs_io_waiter.wait_for_io();
|
||||
}
|
||||
}
|
||||
|
||||
_root_dir.close(vfs_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
|
104
repos/ports/src/noux/time_info.h
Normal file
104
repos/ports/src/noux/time_info.h
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* \brief Time information
|
||||
* \author Josef Soentgen
|
||||
* \date 2019-04-09
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 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 _NOUX__TIME_INFO_H_
|
||||
#define _NOUX__TIME_INFO_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/string.h>
|
||||
#include <util/xml_node.h>
|
||||
#include <rtc_session/connection.h>
|
||||
|
||||
/* Noux includes */
|
||||
#include <noux_session/sysio.h>
|
||||
|
||||
namespace Noux {
|
||||
class Time_info;
|
||||
using namespace Genode;
|
||||
}
|
||||
|
||||
|
||||
class Noux::Time_info : Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
Constructible<Rtc::Connection> _rtc { };
|
||||
|
||||
Genode::int64_t _initial_time { 0 };
|
||||
|
||||
static bool _leap(unsigned year)
|
||||
{
|
||||
return ((year % 4) == 0
|
||||
&& ((year % 100) != 0 || (year % 400) == 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert RTC timestamp to UNIX epoch (UTC)
|
||||
*/
|
||||
static Genode::int64_t _convert(Rtc::Timestamp const &ts)
|
||||
{
|
||||
if (ts.year < 1970) { return 0; }
|
||||
|
||||
/*
|
||||
* Seconds per year lookup table
|
||||
*/
|
||||
static constexpr unsigned _secs_per_year[2] = {
|
||||
365 * 86400, 366 * 86400,
|
||||
};
|
||||
|
||||
/*
|
||||
* Seconds per month lookup table
|
||||
*/
|
||||
static constexpr unsigned _sec_per_month[13] = {
|
||||
0 * 86400,
|
||||
31 * 86400, 28 * 86400, 31 * 86400, 30 * 86400,
|
||||
31 * 86400, 30 * 86400, 31 * 86400, 31 * 86400,
|
||||
30 * 86400, 31 * 86400, 30 * 86400, 31 * 86400
|
||||
};
|
||||
|
||||
Genode::int64_t time = 0;
|
||||
|
||||
for (unsigned i = 1970; i < ts.year; i++) {
|
||||
/* abuse bool conversion for seconds look up */
|
||||
time += _secs_per_year[(int)_leap(i)];
|
||||
}
|
||||
|
||||
for (unsigned i = 1; i < ts.month; i++) {
|
||||
time += _sec_per_month[i];
|
||||
}
|
||||
time += _leap(ts.year) * 86400LL;
|
||||
|
||||
time += 86400LL * (ts.day-1);
|
||||
time += 3600LL * ts.hour;
|
||||
time += 60LL * ts.minute;
|
||||
time += ts.second;
|
||||
|
||||
return time;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Time_info(Env &env, Xml_node config)
|
||||
{
|
||||
/* only try to establish the connection on demand */
|
||||
bool const rtc = config.attribute_value("rtc", false);
|
||||
if (!rtc) { return; }
|
||||
|
||||
_rtc.construct(env);
|
||||
_initial_time = _convert(_rtc->current_time());
|
||||
}
|
||||
|
||||
Genode::int64_t initial_time() const { return _initial_time; }
|
||||
};
|
||||
|
||||
#endif /* _NOUX__TIME_INFO_H_ */
|
@ -14,9 +14,13 @@
|
||||
#ifndef _NOUX__VFS_IO_CHANNEL_H_
|
||||
#define _NOUX__VFS_IO_CHANNEL_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
/* Noux includes */
|
||||
#include <io_channel.h>
|
||||
#include <vfs/dir_file_system.h>
|
||||
#include <time_info.h>
|
||||
|
||||
namespace Noux {
|
||||
class Vfs_io_waiter;
|
||||
@ -69,11 +73,30 @@ struct Noux::Vfs_io_channel : Io_channel
|
||||
|
||||
bool const _dir = _fh.ds().directory(_leaf_path.base());
|
||||
|
||||
Time_info const &_time_info;
|
||||
Timer::Connection &_timer;
|
||||
|
||||
void _sync()
|
||||
{
|
||||
Milliseconds const ms =
|
||||
_timer.curr_time().trunc_to_plain_ms();
|
||||
uint64_t sec = _time_info.initial_time();
|
||||
sec += (ms.value / 1000);
|
||||
|
||||
Vfs::Timestamp ts { .value = (long long)sec };
|
||||
|
||||
Registered_no_delete<Vfs_io_waiter>
|
||||
vfs_io_waiter(_vfs_io_waiter_registry);
|
||||
|
||||
for (;;) {
|
||||
if (_fh.fs().update_modification_timestamp(&_fh, ts)) {
|
||||
break;
|
||||
} else {
|
||||
Genode::error("_sync: update_modification_timestamp failed");
|
||||
vfs_io_waiter.wait_for_io();
|
||||
}
|
||||
}
|
||||
|
||||
while (!_fh.fs().queue_sync(&_fh))
|
||||
vfs_io_waiter.wait_for_io();
|
||||
|
||||
@ -89,11 +112,13 @@ struct Noux::Vfs_io_channel : Io_channel
|
||||
Vfs_io_channel(char const *path, char const *leaf_path,
|
||||
Vfs::Vfs_handle *vfs_handle,
|
||||
Vfs_io_waiter_registry &vfs_io_waiter_registry,
|
||||
Entrypoint &ep)
|
||||
Entrypoint &ep,
|
||||
Time_info const &time_info,
|
||||
Timer::Connection &timer)
|
||||
:
|
||||
_read_avail_handler(ep, *this, &Vfs_io_channel::_handle_read_avail),
|
||||
_fh(*vfs_handle), _vfs_io_waiter_registry(vfs_io_waiter_registry),
|
||||
_path(path), _leaf_path(leaf_path)
|
||||
_path(path), _leaf_path(leaf_path), _time_info(time_info), _timer(timer)
|
||||
{
|
||||
_fh.fs().register_read_ready_sigh(&_fh, _read_avail_handler);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user