From 15b3d7726845fb24a1f67fc4b6de5e03bf3b9d3f Mon Sep 17 00:00:00 2001 From: Thomas Cort Date: Sun, 31 Mar 2013 01:24:24 +0000 Subject: [PATCH] libc: add adjtime() system call. Implement the adjtime() system call and add a test for it to test69. Additionally, install the adjtime.2 and clock_*.2 man pages. --- distrib/sets/lists/minix/mi | 4 +++ kernel/clock.c | 26 ++++++++++++++- kernel/proto.h | 1 + kernel/system/do_settime.c | 14 +++++--- lib/libc/sys-minix/MISSING_SYSCALLS | 1 - lib/libc/sys-minix/Makefile.inc | 2 +- lib/libc/sys-minix/adjtime.c | 36 +++++++++++++++++++++ lib/libc/sys-minix/clock_settime.c | 1 + lib/libc/sys/Makefile.inc | 9 ++++-- servers/pm/param.h | 1 + servers/pm/time.c | 3 +- sys/sys/time.h | 2 +- test/test69.c | 50 +++++++++++++++++++++++++++-- 13 files changed, 136 insertions(+), 14 deletions(-) create mode 100644 lib/libc/sys-minix/adjtime.c diff --git a/distrib/sets/lists/minix/mi b/distrib/sets/lists/minix/mi index 33c4e431f..6414f674c 100644 --- a/distrib/sets/lists/minix/mi +++ b/distrib/sets/lists/minix/mi @@ -1455,6 +1455,7 @@ ./usr/man/man1/znew.1 minix-sys ./usr/man/man2/accept.2 minix-sys ./usr/man/man2/access.2 minix-sys +./usr/man/man2/adjtime.2 minix-sys ./usr/man/man2/alarm.2 minix-sys ./usr/man/man2/bind.2 minix-sys ./usr/man/man2/brk.2 minix-sys @@ -1463,6 +1464,9 @@ ./usr/man/man2/chown.2 minix-sys ./usr/man/man2/chroot.2 minix-sys ./usr/man/man2/close.2 minix-sys +./usr/man/man2/clock_getres.2 minix-sys +./usr/man/man2/clock_gettime.2 minix-sys +./usr/man/man2/clock_settime.2 minix-sys ./usr/man/man2/connect.2 minix-sys ./usr/man/man2/creat.2 minix-sys ./usr/man/man2/dup.2 minix-sys diff --git a/kernel/clock.c b/kernel/clock.c index 688ab6695..be6cfa572 100644 --- a/kernel/clock.c +++ b/kernel/clock.c @@ -20,6 +20,7 @@ * clock_stop: called just before MINIX shutdown * get_realtime: get wall time since boot in clock ticks * set_realtime: set wall time since boot in clock ticks + * set_adjtime_delta: set the number of ticks to adjust realtime * get_monotonic: get monotonic time since boot in clock ticks * set_timer: set a watchdog timer (+) * reset_timer: reset a watchdog timer (+) @@ -63,6 +64,11 @@ static clock_t monotonic = 0; */ static clock_t realtime = 0; +/* Number of ticks to adjust realtime by. A negative value implies slowing + * down realtime, a positive value implies speeding it up. + */ +static clock_t adjtime_delta = 0; + /* * The boot processor's timer interrupt handler. In addition to non-boot cpus * it keeps real time and notifies the clock task if need be. @@ -90,7 +96,17 @@ int timer_int_handler(void) if (cpu_is_bsp(cpuid)) { monotonic++; - realtime++; + + /* if adjtime_delta has ticks remaining, apply one to realtime. + * limit changes to every other interrupt. + */ + if (adjtime_delta != 0 && monotonic & 0x1) { + /* go forward or stay behind */ + realtime += (adjtime_delta > 0) ? 2 : 0; + adjtime_delta += (adjtime_delta > 0) ? -1 : +1; + } else { + realtime++; + } } /* Update user and system accounting times. Charge the current process @@ -176,6 +192,14 @@ void set_realtime(clock_t newrealtime) realtime = newrealtime; } +/*===========================================================================* + * set_adjtime_delta * + *===========================================================================*/ +void set_adjtime_delta(clock_t ticks) +{ + adjtime_delta = ticks; +} + /*===========================================================================* * get_monotonic * *===========================================================================*/ diff --git a/kernel/proto.h b/kernel/proto.h index 120c62051..7952922dd 100644 --- a/kernel/proto.h +++ b/kernel/proto.h @@ -17,6 +17,7 @@ struct timer; /* clock.c */ clock_t get_realtime(void); void set_realtime(clock_t); +void set_adjtime_delta(clock_t); clock_t get_monotonic(void); void set_timer(struct timer *tp, clock_t t, tmr_func_t f); void reset_timer(struct timer *tp); diff --git a/kernel/system/do_settime.c b/kernel/system/do_settime.c index 7c106dd50..bf408ce69 100644 --- a/kernel/system/do_settime.c +++ b/kernel/system/do_settime.c @@ -17,12 +17,20 @@ *===========================================================================*/ int do_settime(struct proc * caller, message * m_ptr) { - clock_t newclock; + clock_t newclock, ticks; time_t timediff; if (m_ptr->T_CLOCK_ID != CLOCK_REALTIME) /* only realtime can change */ return EINVAL; + if (m_ptr->T_SETTIME_NOW == 0) { /* user just wants to adjtime() */ + /* convert delta value from seconds and nseconds to ticks */ + ticks = (m_ptr->T_TIME_SEC * system_hz) + + (m_ptr->T_TIME_NSEC/(1000000000/system_hz)); + set_adjtime_delta(ticks); + return(OK); + } /* else user wants to set the time */ + /* prevent a negative value for realtime */ if (m_ptr->T_TIME_SEC <= boottime) { /* boottime was likely wrong, try to correct it. */ @@ -35,9 +43,7 @@ int do_settime(struct proc * caller, message * m_ptr) timediff = m_ptr->T_TIME_SEC - boottime; newclock = (timediff*system_hz) + (m_ptr->T_TIME_NSEC/(1000000000/system_hz)); - if (m_ptr->T_SETTIME_NOW) { - set_realtime(newclock); - } /* else used adjtime() method (to be implemented) */ + set_realtime(newclock); return(OK); } diff --git a/lib/libc/sys-minix/MISSING_SYSCALLS b/lib/libc/sys-minix/MISSING_SYSCALLS index 440ab35b5..dc75c0669 100644 --- a/lib/libc/sys-minix/MISSING_SYSCALLS +++ b/lib/libc/sys-minix/MISSING_SYSCALLS @@ -1,6 +1,5 @@ _lwp_* acct -adjtime lchmod lchown clone diff --git a/lib/libc/sys-minix/Makefile.inc b/lib/libc/sys-minix/Makefile.inc index 211545599..542197c7d 100644 --- a/lib/libc/sys-minix/Makefile.inc +++ b/lib/libc/sys-minix/Makefile.inc @@ -1,6 +1,6 @@ .PATH: ${.CURDIR}/sys-minix -SRCS+= accept.c access.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \ +SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \ chdir.c chmod.c fchmod.c chown.c fchown.c chroot.c close.c \ clock_getres.c clock_gettime.c clock_settime.c \ connect.c dup.c dup2.c execve.c fcntl.c flock.c fpathconf.c fork.c \ diff --git a/lib/libc/sys-minix/adjtime.c b/lib/libc/sys-minix/adjtime.c new file mode 100644 index 000000000..b38d8846d --- /dev/null +++ b/lib/libc/sys-minix/adjtime.c @@ -0,0 +1,36 @@ +#include +#include +#include "namespace.h" + +#include +#include + +#ifdef __weak_alias +__weak_alias(adjtime, __adjtime50); +#endif + +int adjtime(const struct timeval *delta, struct timeval *olddelta) +{ + message m; + + m.m2_i2 = 0; /* use adjtime() method to slowly adjust the clock. */ + m.m2_i1 = (clockid_t) CLOCK_REALTIME; + m.m2_l1 = (time_t) delta->tv_sec; + m.m2_l2 = (long) delta->tv_usec * 1000; /* convert usec to nsec */ + + if (_syscall(PM_PROC_NR, CLOCK_SETTIME, &m) < 0) + return -1; + + if (olddelta != NULL) { + /* the kernel returns immediately and the adjustment happens in the + * background. Also, any currently running adjustment is stopped by + * another call to adjtime(2), so the only values possible on Minix + * for olddelta are those of delta. + */ + olddelta->tv_sec = delta->tv_sec; + olddelta->tv_usec = delta->tv_usec; + } + + return 0; +} + diff --git a/lib/libc/sys-minix/clock_settime.c b/lib/libc/sys-minix/clock_settime.c index 28d518778..d608ef66f 100644 --- a/lib/libc/sys-minix/clock_settime.c +++ b/lib/libc/sys-minix/clock_settime.c @@ -12,6 +12,7 @@ int clock_settime(clockid_t clock_id, const struct timespec *ts) { message m; + m.m2_i2 = 1; /* set time immediately. don't use adjtime() method. */ m.m2_i1 = (clockid_t) clock_id; m.m2_l1 = (time_t) ts->tv_sec; m.m2_l2 = (long) ts->tv_nsec; diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 3d6d088ee..b20b7ea66 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -221,8 +221,8 @@ LintSysPseudoNoerr.c: ${LIBCDIR}/sys/makelintstub \ .endif # !defined(__MINIX) .if !defined(__MINIX) -MAN+= accept.2 access.2 acct.2 adjtime.2 bind.2 brk.2 chdir.2 \ - chflags.2 chmod.2 chown.2 chroot.2 clock_settime.2 clone.2 close.2 \ +MAN+= accept.2 access.2 acct.2 bind.2 brk.2 chdir.2 \ + chflags.2 chmod.2 chown.2 chroot.2 clone.2 close.2 \ connect.2 dup.2 execve.2 _exit.2 extattr_get_file.2 \ fcntl.2 fdatasync.2 fhopen.2 \ flock.2 fork.2 fsync.2 getcontext.2 getdents.2 \ @@ -244,7 +244,7 @@ MAN+= accept.2 access.2 acct.2 adjtime.2 bind.2 brk.2 chdir.2 \ mprotect.2 mremap.2 msgctl.2 msgget.2 msgrcv.2 msgsnd.2 msync.2 \ munmap.2 nanosleep.2 nfssvc.2 ntp_adjtime.2 open.2 pathconf.2 pipe.2 .else -MAN+= pipe.2 +MAN+= adjtime.2 clock_settime.2 pipe.2 .endif # !defined(__MINIX) .if !defined(__MINIX) MAN+= pmc_control.2 poll.2 posix_fadvise.2 profil.2 ptrace.2 __quotactl.2 \ @@ -271,8 +271,11 @@ MLINKS+=chflags.2 fchflags.2 chflags.2 lchflags.2 MLINKS+=chmod.2 fchmod.2 chmod.2 lchmod.2 MLINKS+=chown.2 fchown.2 chown.2 lchown.2 MLINKS+=chroot.2 fchroot.2 +.else MLINKS+=clock_settime.2 clock_gettime.2 MLINKS+=clock_settime.2 clock_getres.2 +.endif # !defined(__MINIX) +.if !defined(__MINIX) MLINKS+=extattr_get_file.2 extattr_set_file.2 \ extattr_get_file.2 extattr_delete_file.2 \ extattr_get_file.2 extattr_list_file.2 \ diff --git a/servers/pm/param.h b/servers/pm/param.h index 260910fbd..3bdb266aa 100644 --- a/servers/pm/param.h +++ b/servers/pm/param.h @@ -31,6 +31,7 @@ #define svrctl_argp m2_p1 #define stime m2_l1 #define clk_id m2_i1 +#define settime_now m2_i2 #define time_sec m2_l1 #define time_nsec m2_l2 #define memsize m4_l1 diff --git a/servers/pm/time.c b/servers/pm/time.c index aea2e421b..40a73e00d 100644 --- a/servers/pm/time.c +++ b/servers/pm/time.c @@ -76,7 +76,8 @@ int do_settime() switch (m_in.clk_id) { case CLOCK_REALTIME: - s= sys_settime(1, m_in.clk_id, m_in.time_sec, m_in.time_nsec); + s= sys_settime(m_in.settime_now, m_in.clk_id, m_in.time_sec, + m_in.time_nsec); return(s); case CLOCK_MONOTONIC: /* monotonic cannot be changed */ default: diff --git a/sys/sys/time.h b/sys/sys/time.h index 6cda042ff..b4f809e40 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -285,8 +285,8 @@ int setitimer(int, const struct itimerval * __restrict, #endif /* _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE || _NETBSD_SOURCE */ #if defined(_NETBSD_SOURCE) || defined(HAVE_NBTOOL_CONFIG_H) -#ifndef __minix int adjtime(const struct timeval *, struct timeval *) __RENAME(__adjtime50); +#ifndef __minix int futimes(int, const struct timeval [2]) __RENAME(__futimes50); int lutimes(const char *, const struct timeval [2]) __RENAME(__lutimes50); #endif /* !__minix */ diff --git a/test/test69.c b/test/test69.c index 0282f60bb..7c1a6e631 100644 --- a/test/test69.c +++ b/test/test69.c @@ -1,4 +1,8 @@ -/* Test 69. clock_getres(), clock_gettime(). */ +/* Test 69. clock_getres(), clock_gettime(), clock_settime(), adjtime(). + * + * Note, any type of ntpd or software that calls adjtime() or settimeofday() + * should be disabled while running this test. This test takes ~40s to run. + */ #include #include @@ -10,7 +14,9 @@ #define TRIALS 100 #define MAX_ERROR 4 +#ifndef DEBUG #define DEBUG 0 +#endif int subtest = 1; @@ -21,6 +27,7 @@ void quit(void); static void test_clock_getres(); static void test_clock_gettime(); static void test_clock_settime(); +static void test_adjtime(); static void show_timespec(char *msg, struct timespec *ts); static void test_clock_getres() @@ -60,7 +67,6 @@ static void test_clock_gettime() if (ts2.tv_sec < 0 || ts2.tv_nsec < 0) e(29); if (ts2.tv_sec <= ts.tv_sec) e(30); - if (clock_gettime(-1, &ts) == 0) e(31); } @@ -95,6 +101,45 @@ static void test_clock_settime(void) if (clock_settime(-1, &ts) == 0) e(60); } +static void test_adjtime(void) +{ + struct timeval delta, olddelta; + struct timespec rt, mt; + + /* set the realtime clock to the same value as the monotonic clock */ + if (clock_gettime(CLOCK_MONOTONIC, &mt) == -1) e(65); + if (clock_settime(CLOCK_REALTIME, &mt) == -1) e(66); + + delta.tv_sec = 7; + delta.tv_usec = 0; + + if (adjtime(&delta, &olddelta) != 0) e(70); /* adjust +7 seconds */ + sleep(15); /* should take 14 seconds to adjust the clock */ + + /* check that the 7 second adjustment puts us between 5 and 10 seconds + * ahead of the monotonic clock. + */ + if (clock_gettime(CLOCK_MONOTONIC, &mt) == -1) e(71); + if (clock_gettime(CLOCK_REALTIME, &rt) == -1) e(72); + show_timespec("Monotonic", &mt); + show_timespec("Realtime (+7)", &rt); + if (rt.tv_sec - 5 < mt.tv_sec || rt.tv_sec - 10 > mt.tv_sec) e(73); + + delta.tv_sec = -7; + if (adjtime(&delta, &olddelta) != 0) e(73); /* adjust -7 seconds */ + sleep(15); /* should take 14 seconds to adjust the clock */ + + /* check that the 7 second adjustment puts us close to even with + * the monotonic clock. + */ + if (clock_gettime(CLOCK_MONOTONIC, &mt) == -1) e(74); + if (clock_gettime(CLOCK_REALTIME, &rt) == -1) e(75); + show_timespec("Monotonic", &mt); + show_timespec("Realtime (-7)", &rt); + if (abs(rt.tv_sec - mt.tv_sec) > 5) e(76); + +} + static void show_timespec(char *msg, struct timespec *ts) { #if DEBUG == 1 @@ -113,6 +158,7 @@ int main() test_clock_getres(); test_clock_gettime(); test_clock_settime(); + test_adjtime(); /* get test end time */ if (clock_gettime(CLOCK_MONOTONIC, &endtime) == -1) e(2);