Noux: more useful gettimeofday() implementation

There are certain programs that need gettimeofday(), e.g.
network-related tools like ping(1) etc. but also filesystem-related
programs like find(1) etc. and of course time-related programs like
date(1).

As there is currently no interface in Genode for actually using clock
devices like RTC on x86 (though there is a driver for it) we "abuse"
the timeout_scheduler thread to at least provide flow-of-time.

Noux: add clock_gettime() implementation

For now, only CLOCK_SECOND is supported.

Noux: add utimes() dummy

Fixes #401
This commit is contained in:
Josef Söntgen 2012-09-12 16:12:55 +02:00 committed by Norman Feske
parent 81e0bfefb6
commit 837f913094
5 changed files with 137 additions and 11 deletions

View File

@ -72,6 +72,9 @@ namespace Noux {
SYSCALL_SHUTDOWN,
SYSCALL_CONNECT,
SYSCALL_USERINFO,
SYSCALL_GETTIMEOFDAY,
SYSCALL_CLOCK_GETTIME,
SYSCALL_UTIMES,
SYSCALL_INVALID = -1
};
@ -116,6 +119,9 @@ namespace Noux {
NOUX_DECL_SYSCALL_NAME(SHUTDOWN)
NOUX_DECL_SYSCALL_NAME(CONNECT)
NOUX_DECL_SYSCALL_NAME(USERINFO)
NOUX_DECL_SYSCALL_NAME(GETTIMEOFDAY)
NOUX_DECL_SYSCALL_NAME(CLOCK_GETTIME)
NOUX_DECL_SYSCALL_NAME(UTIMES)
case SYSCALL_INVALID: return 0;
}
return 0;

View File

@ -284,6 +284,11 @@ namespace Noux {
typedef char Home[MAX_HOME_LEN];
typedef unsigned int Uid;
/**
* time/clock definitions
*/
enum Clock_Id { CLOCK_ID_SECOND };
enum General_error { ERR_FD_INVALID, NUM_GENERAL_ERRORS };
enum Stat_error { STAT_ERR_NO_ENTRY = NUM_GENERAL_ERRORS };
enum Fcntl_error { FCNTL_ERR_CMD_INVALID = NUM_GENERAL_ERRORS };
@ -337,6 +342,13 @@ namespace Noux {
enum Socket_error { SOCKET_ERR_ACCESS, SOCKET_ERR_NO_AF_SUPPORT,
SOCKET_ERR_INVALID, SOCKET_ERR_NO_MEMORY };
enum Clock_error { CLOCK_ERR_INVALID, CLOCK_ERR_FAULT, CLOCK_ERR_NO_PERM };
enum Utimes_error { UTIMES_ERR_ACCESS, UTIMES_ERR_FAUL, UTIMES_ERR_EIO,
UTIMES_ERR_NAME_TOO_LONG, UTIMES_ERR_NO_ENTRY,
UTIMES_ERR_NOT_DIRECTORY, UTIMES_ERR_NO_PERM,
UTIMES_ERR_READ_ONLY };
union {
General_error general;
Stat_error stat;
@ -359,6 +371,8 @@ namespace Noux {
Send_error send;
Shutdown_error shutdown;
Socket_error socket;
Clock_error clock;
Utimes_error utimes;
} error;
union {
@ -462,6 +476,14 @@ namespace Noux {
SYSIO_DECL(userinfo, { int request; Uid uid; },
{ User name; Uid uid; Uid gid; Shell shell;
Home home; });
SYSIO_DECL(gettimeofday, { }, { unsigned long sec; unsigned int usec; });
SYSIO_DECL(clock_gettime, { Clock_Id clock_id; },
{ unsigned long sec; unsigned long nsec; });
SYSIO_DECL(utimes, { Path path; unsigned long sec; unsigned long usec; },
{ });
};
};
};

View File

@ -456,21 +456,52 @@ extern "C" pid_t _wait4(pid_t pid, int *status, int options,
extern "C" int clock_gettime(clockid_t clk_id, struct timespec *tp)
{
if (verbose)
PDBG("clock_gettime called - not implemented");
errno = EINVAL;
return -1;
/* we currently only support CLOCK_SECOND */
switch (clk_id) {
case CLOCK_SECOND:
sysio()->clock_gettime_in.clock_id = Noux::Sysio::CLOCK_ID_SECOND;
break;
default:
/* let's save the trip to noux and return directly */
errno = EINVAL;
return -1;
}
if (!noux()->syscall(Noux::Session::SYSCALL_CLOCK_GETTIME)) {
switch (sysio()->error.clock) {
case Noux::Sysio::CLOCK_ERR_INVALID: errno = EINVAL; break;
default: errno = 0; break;
}
return -1;
}
tp->tv_sec = sysio()->clock_gettime_out.sec;
tp->tv_nsec = sysio()->clock_gettime_out.nsec;
return 0;
}
extern "C" int gettimeofday(struct timeval *tv, struct timezone *tz)
{
if (verbose)
PDBG("gettimeofday() called - not implemented");
if (!noux()->syscall(Noux::Session::SYSCALL_GETTIMEOFDAY)) {
errno = EINVAL;
return -1;
}
if (tv) {
tv->tv_sec = 0;
tv->tv_usec = 0;
tv->tv_sec = sysio()->gettimeofday_out.sec;
tv->tv_usec = sysio()->gettimeofday_out.usec;
return 0;
}
extern "C" int utimes(const char* path, const struct timeval *times)
{
if (!noux()->syscall(Noux::Session::SYSCALL_UTIMES)) {
errno = EINVAL;
return -1;
}
return 0;

View File

@ -70,7 +70,7 @@ namespace Noux {
}
public:
Timeout_scheduler() : _curr_time(0) { start(); }
Timeout_scheduler(unsigned long curr_time) : _curr_time(curr_time) { start(); }
Alarm::Time curr_time() const { return _curr_time; }
};
@ -595,6 +595,70 @@ bool Noux::Child::syscall(Noux::Session::Syscall sc)
return true;
}
case SYSCALL_GETTIMEOFDAY:
{
/**
* Since the timeout_scheduler thread is started after noux it
* basicly returns the eleapsed time since noux was started. We
* abuse this timer to provide a more useful implemenation of
* gettimeofday() to make certain programs (e.g. ping(1)) happy.
* Note: this is just a short-term solution because Genode currently
* lacks a proper time interface (there is a RTC driver however, but
* there is no interface for it).
*/
unsigned long time = Noux::timeout_scheduler()->curr_time();
_sysio->gettimeofday_out.sec = (time / 1000);
_sysio->gettimeofday_out.usec = (time % 1000) * 1000;
return true;
}
case SYSCALL_CLOCK_GETTIME:
{
/**
* It's the same procedure as in SYSCALL_GETTIMEOFDAY.
*/
unsigned long time = Noux::timeout_scheduler()->curr_time();
switch (_sysio->clock_gettime_in.clock_id) {
/* CLOCK_SECOND is used by time(3) in the libc. */
case Sysio::CLOCK_ID_SECOND:
{
_sysio->clock_gettime_out.sec = (time / 1000);
_sysio->clock_gettime_out.nsec = 0;
return true;
}
default:
{
_sysio->clock_gettime_out.sec = 0;
_sysio->clock_gettime_out.nsec = 0;
_sysio->error.clock = Sysio::CLOCK_ERR_INVALID;
return false;
}
}
return false;
}
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.
*/
return true;
}
case SYSCALL_SOCKET:
case SYSCALL_GETSOCKOPT:
case SYSCALL_SETSOCKOPT:
@ -713,7 +777,7 @@ Noux::Pid_allocator *Noux::pid_allocator()
Noux::Timeout_scheduler *Noux::timeout_scheduler()
{
static Noux::Timeout_scheduler inst;
static Noux::Timeout_scheduler inst(0);
return &inst;
}

View File

@ -176,6 +176,9 @@ bool Noux::Child::_syscall_net(Noux::Session::Syscall sc)
case SYSCALL_READLINK:
case SYSCALL_SYMLINK:
case SYSCALL_USERINFO:
case SYSCALL_GETTIMEOFDAY:
case SYSCALL_CLOCK_GETTIME:
case SYSCALL_UTIMES:
break;
case SYSCALL_SOCKET:
{