]> Zhao Yanbai Git Server - minix.git/commitdiff
libc: add clock_settime() system call. 69/469/1
authorThomas Cort <tcort@minix3.org>
Sat, 30 Mar 2013 16:59:21 +0000 (16:59 +0000)
committerBen Gras <ben@minix3.org>
Thu, 4 Apr 2013 13:04:54 +0000 (15:04 +0200)
This also adds the sys_settime() kernel call which allows for the adjusting
of the clock named realtime in the kernel. The existing sys_stime()
function is still needed for a separate job (setting the boottime). The
boottime is set in the readclock driver. The sys_settime() interface is
meant to be flexible and will support both clock_settime() and adjtime()
when adjtime() is implemented later.

settimeofday() was adjusted to use the clock_settime() interface.

One side note discovered during testing: uptime(1) (part of the last(1)),
uses wtmp to determine boottime (not Minix's times(2)). This leads `uptime`
to report odd results when you set the time to a time prior to boottime.
This isn't a new bug introduced by my changes. It's been there for a while.

24 files changed:
include/minix/callnr.h
include/minix/com.h
include/minix/syslib.h
include/time.h
kernel/clock.c
kernel/proto.h
kernel/system.c
kernel/system.h
kernel/system/Makefile.inc
kernel/system/do_settime.c [new file with mode: 0644]
lib/libc/sys-minix/MISSING_SYSCALLS
lib/libc/sys-minix/Makefile.inc
lib/libc/sys-minix/clock_getres.c
lib/libc/sys-minix/clock_gettime.c
lib/libc/sys-minix/clock_settime.c [new file with mode: 0644]
lib/libc/sys-minix/settimeofday.c
lib/libsys/Makefile
lib/libsys/sys_settime.c [new file with mode: 0644]
servers/pm/param.h
servers/pm/proto.h
servers/pm/table.c
servers/pm/time.c
servers/vfs/table.c
test/test69.c

index d3c9e35298c278200b28c8b5eedb5bbb2f7ec06c..f4417ddf5bc6b8c78d6bd91aa98774cf59fca19d 100644 (file)
@@ -1,4 +1,4 @@
-#define NCALLS          116    /* number of system calls allowed */
+#define NCALLS          117    /* number of system calls allowed */
 
 /* In case it isn't obvious enough: this list is sorted numerically. */
 #define EXIT              1 
 #define PM_GETSID      113     /* PM getsid() */
 #define CLOCK_GETRES   114     /* clock_getres() */
 #define CLOCK_GETTIME  115     /* clock_gettime() */
+#define CLOCK_SETTIME  116     /* clock_settime() */
 
 #define TASK_REPLY     121     /* to VFS: reply code from drivers, not 
                                 * really a standalone call.
index 327c3dcba568a80cafd429ccfb244c044c9d772c..4ffa407d56f564d718c8e7212feb3bbd9039db53 100644 (file)
 #  define SYS_PROFBUF    (KERNEL_CALL + 38)     /* sys_profbuf() */
 
 #  define SYS_STIME      (KERNEL_CALL + 39)    /* sys_stime() */
+#  define SYS_SETTIME    (KERNEL_CALL + 40)    /* sys_settime() */
 
 #  define SYS_VMCTL      (KERNEL_CALL + 43)    /* sys_vmctl() */
 #  define SYS_SYSCTL     (KERNEL_CALL + 44)    /* sys_sysctl() */
 #define T_REAL_TICKS   m4_l4   /* number of wall clock ticks since boottime */
 #define T_BOOT_TICKS   m4_l5   /* number of hard clock ticks since boottime */
 
+/* Field names for SYS_SETTIME. */
+#define T_SETTIME_NOW  m4_l2   /* non-zero for immediate, 0 for adjtime */
+#define T_CLOCK_ID     m4_l3   /* clock to adjust */
+#define T_TIME_SEC     m4_l4   /* time in seconds since 1970 */
+#define T_TIME_NSEC    m4_l5   /* number of nano seconds */
+
 /* Field names for SYS_TRACE, SYS_PRIVCTL, SYS_STATECTL. */
 #define CTL_ENDPT      m2_i1   /* process number of the caller */
 #define CTL_REQUEST    m2_i2   /* server control request */
index f1bc43186cf76afeeec6764f432628bb18cc403b..4d373843da5a6c2b092c6df63d68f1da07bc26d4 100644 (file)
@@ -65,6 +65,7 @@ int sys_vmctl_get_memreq(endpoint_t *who, vir_bytes *mem, vir_bytes
 int sys_vmctl_enable_paging(void * data);
 
 int sys_readbios(phys_bytes address, void *buf, size_t size);
+int sys_settime(int now, clockid_t clk_id, time_t sec, long nsec);
 int sys_stime(time_t boottime);
 int sys_sysctl(int ctl, char *arg1, int arg2);
 int sys_sysctl_stacktrace(endpoint_t who);
index 1a9d425437caecec6238be783e3867fe7c787d90..711297140caa25b547ac235520917d57986b7415 100644 (file)
@@ -162,10 +162,8 @@ int clock_getres(clockid_t, struct timespec *)
     __RENAME(__clock_getres50);
 int clock_gettime(clockid_t, struct timespec *)
     __RENAME(__clock_gettime50);
-#ifndef __minix
 int clock_settime(clockid_t, const struct timespec *)
     __RENAME(__clock_settime50);
-#endif /* !__minix */
 int nanosleep(const struct timespec *, struct timespec *)
     __RENAME(__nanosleep50);
 #ifndef __minix
index a0b796bcc625bc71e584f7093b21b14bfab85cdd..688ab6695901279e8ffee740e53a2af6fdceb5bb 100644 (file)
@@ -19,6 +19,7 @@
  * loop, there are several other minor entry points:
  *   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
  *   get_monotonic:    get monotonic time since boot in clock ticks
  *   set_timer:                set a watchdog timer (+)
  *   reset_timer:      reset a watchdog timer (+)
@@ -167,6 +168,13 @@ clock_t get_realtime(void)
   return(realtime);
 }
 
+/*===========================================================================*
+ *                             set_realtime                                 *
+ *===========================================================================*/
+void set_realtime(clock_t newrealtime)
+{
+  realtime = newrealtime;
+}
 
 /*===========================================================================*
  *                             get_monotonic                                *
index 77e53d8b66fe2edd05914f98ecee75be20d5d1c6..120c620519ae3f5f9648d571ae20ff6045f3cd73 100644 (file)
@@ -16,6 +16,7 @@ struct timer;
 
 /* clock.c */
 clock_t get_realtime(void);
+void set_realtime(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);
index e8fe0387aa802fc7cae371cfbc087039edb523bd..caafd994350a9a958f761402fa887011a92d98a5 100644 (file)
@@ -235,6 +235,7 @@ void system_init(void)
   map(SYS_TIMES, do_times);            /* get uptime and process times */
   map(SYS_SETALARM, do_setalarm);      /* schedule a synchronous alarm */
   map(SYS_STIME, do_stime);            /* set the boottime */
+  map(SYS_SETTIME, do_settime);                /* set the system time (realtime) */
   map(SYS_VTIMER, do_vtimer);          /* set or retrieve a virtual timer */
 
   /* System control. */
index fa58823b666303b712bfb0db9d0e634cb9c85579..9f493ab6ff1a968043a39887c3ebbad251f8fb0d 100644 (file)
@@ -164,6 +164,7 @@ int do_setalarm(struct proc * caller, message *m_ptr);
 #endif
 
 int do_stime(struct proc * caller, message *m_ptr);
+int do_settime(struct proc * caller, message *m_ptr);
 
 int do_vtimer(struct proc * caller, message *m_ptr);
 #if ! USE_VTIMER
index 69efe4e871edbc200e4ada135dfb9ae4b9c93aa2..e90b476402b13f8a067f77adc1b62c169f7faab9 100644 (file)
@@ -13,6 +13,7 @@ SRCS+=        \
        do_times.c \
        do_setalarm.c \
        do_stime.c \
+       do_settime.c \
        do_vtimer.c \
        do_irqctl.c \
        do_copy.c \
diff --git a/kernel/system/do_settime.c b/kernel/system/do_settime.c
new file mode 100644 (file)
index 0000000..7c106dd
--- /dev/null
@@ -0,0 +1,43 @@
+/* The kernel call implemented in this file:
+ *   m_type:   SYS_SETTIME
+ *
+ * The parameters for this kernel call are:
+ *    m4_l2:   T_SETTIME_NOW
+ *    m4_l3:   T_CLOCK_ID
+ *    m4_l4:   T_TIME_SEC
+ *    m4_l5:   T_TIME_NSEC
+ */
+
+#include "kernel/system.h"
+#include <minix/endpoint.h>
+#include <time.h>
+
+/*===========================================================================*
+ *                             do_settime                                   *
+ *===========================================================================*/
+int do_settime(struct proc * caller, message * m_ptr)
+{
+  clock_t newclock;
+  time_t timediff;
+
+  if (m_ptr->T_CLOCK_ID != CLOCK_REALTIME) /* only realtime can change */
+       return EINVAL;
+
+  /* prevent a negative value for realtime */
+  if (m_ptr->T_TIME_SEC <= boottime) {
+       /* boottime was likely wrong, try to correct it. */
+       boottime = m_ptr->T_TIME_SEC;
+       set_realtime(1);
+       return(OK);
+  }
+
+  /* calculate the new value of realtime in ticks */
+  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) */
+
+  return(OK);
+}
index 54b519863a01de77a860cebb95a706f67e995288..440ab35b5c0907d4c681ff18e86d341840fe4a9c 100644 (file)
@@ -4,7 +4,6 @@ adjtime
 lchmod
 lchown
 clone
-clock_settime
 extattr_*
 fhopen
 fhstat
index f47cd87e939832a8e1ba1c84e0a9c094ec8bc4ad..211545599dab4b1cc7ec6a7d0afddf929936f0a7 100644 (file)
@@ -2,7 +2,7 @@
 
 SRCS+=         accept.c access.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_getres.c clock_gettime.c clock_settime.c \
        connect.c dup.c dup2.c execve.c fcntl.c flock.c fpathconf.c fork.c \
        fstatfs.c fstatvfs.c fsync.c ftruncate.c getdents.c getegid.c getgid.c \
        getgroups.c getitimer.c setitimer.c __getlogin.c getpeername.c \
index a40177e773eafabc1d032805444370b26084fdc2..3763305c6df5b54205186d1cf9d0da69e588c9b0 100644 (file)
@@ -12,7 +12,7 @@ int clock_getres(clockid_t clock_id, struct timespec *res)
 {
   message m;
 
-  m.m2_l1 = (clockid_t) clock_id;
+  m.m2_i1 = (clockid_t) clock_id;
 
   if (_syscall(PM_PROC_NR, CLOCK_GETRES, &m) < 0)
        return -1;
index 01ed16cc8486105dcc28c0e8e830454eeee12585..8ea6d34d0d6850f794b65d19d800652f2d4622e6 100644 (file)
@@ -12,7 +12,7 @@ int clock_gettime(clockid_t clock_id, struct timespec *res)
 {
   message m;
 
-  m.m2_l1 = (clockid_t) clock_id;
+  m.m2_i1 = (clockid_t) clock_id;
 
   if (_syscall(PM_PROC_NR, CLOCK_GETTIME, &m) < 0)
        return -1;
diff --git a/lib/libc/sys-minix/clock_settime.c b/lib/libc/sys-minix/clock_settime.c
new file mode 100644 (file)
index 0000000..28d5187
--- /dev/null
@@ -0,0 +1,24 @@
+#include <sys/cdefs.h>
+#include <lib.h>
+#include "namespace.h"
+
+#include <time.h>
+
+#ifdef __weak_alias
+__weak_alias(clock_settime, __clock_settime50);
+#endif
+
+int clock_settime(clockid_t clock_id, const struct timespec *ts)
+{
+  message m;
+
+  m.m2_i1 = (clockid_t) clock_id;
+  m.m2_l1 = (time_t) ts->tv_sec;
+  m.m2_l2 = (long) ts->tv_nsec;
+
+  if (_syscall(PM_PROC_NR, CLOCK_SETTIME, &m) < 0)
+       return -1;
+
+  return 0;
+}
+
index ae0e6b5786cb8c6538354299bc7f83e4e889b0ac..85bef8bc5f89206c0688d11628492d9a6f2cab4f 100644 (file)
@@ -7,11 +7,13 @@
 
 int settimeofday(const struct timeval *tp, const void *tzp)
 {
-       /* Use intermediate variable because stime param is not const */
-       time_t sec = tp->tv_sec;
+       struct timespec ts;
+
+       ts.tv_sec = tp->tv_sec;
+       ts.tv_nsec = tp->tv_usec * 1000;
        
        /* Ignore time zones */
-       return stime(&sec);
+       return clock_settime(CLOCK_REALTIME, &ts);
 }
 
 #if defined(__minix) && defined(__weak_alias)
index 4d36abbaaf105e08b83109df2f83c43dc4930293..f1a4e39b110229f9c03c1cd1ec06f29a790ef140 100644 (file)
@@ -59,6 +59,7 @@ SRCS+=  \
        sys_schedule.c \
        sys_setalarm.c \
        sys_setgrant.c \
+       sys_settime.c \
        sys_sigreturn.c \
        sys_sigsend.c \
        sys_sprof.c \
diff --git a/lib/libsys/sys_settime.c b/lib/libsys/sys_settime.c
new file mode 100644 (file)
index 0000000..6199791
--- /dev/null
@@ -0,0 +1,20 @@
+#include "syslib.h"
+#include <time.h>
+
+int sys_settime(now, clk_id, sec, nsec)
+int now;
+clockid_t clk_id;
+time_t sec;
+long nsec;
+{
+  message m;
+  int r;
+
+  m.T_SETTIME_NOW = now;
+  m.T_CLOCK_ID = clk_id;
+  m.T_TIME_SEC = sec;
+  m.T_TIME_NSEC = nsec;
+
+  r = _kernel_call(SYS_SETTIME, &m);
+  return(r);
+}
index 33a15cb71992694af8f2f655bf0f92231d4d1109..260910fbde3150d00eb1f4361c9b98119803d981 100644 (file)
@@ -30,7 +30,9 @@
 #define svrctl_req     m2_i1
 #define svrctl_argp    m2_p1
 #define stime          m2_l1
-#define clk_id         m2_l1
+#define clk_id         m2_i1
+#define time_sec       m2_l1
+#define time_nsec      m2_l2
 #define memsize        m4_l1
 #define membase        m4_l2
 #define sysuname_req   m1_i1
index 2b86bad6651bf772d89ecd4dc01b1ca252afd612..73e8a4a69dffa0772a2c8e90d180956d0daccf2c 100644 (file)
@@ -88,6 +88,7 @@ int do_time(void);
 int do_times(void);
 int do_getres(void);
 int do_gettime(void);
+int do_settime(void);
 
 /* trace.c */
 int do_trace(void);
index 4c253dabc52f3c3068c7a2c323b5c2aedd9c6584..4a51a8f7c327c2de93d7cef640b0549cdb7a4c9e 100644 (file)
@@ -127,6 +127,7 @@ int (*call_vec[])(void) = {
        do_get,         /* 113 = getsid */
        do_getres,      /* 114 = clock_getres */
        do_gettime,     /* 115 = clock_gettime */
+       do_settime,     /* 116 = clock_settime */
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
index 61fca33ebbdfb1c3104bb8da1822f2b3641a1dd6..aea2e421b48f5a6c364ff0608d66411050c31d14 100644 (file)
@@ -3,6 +3,7 @@
  * The entry points into this file are
  *   do_getres:                perform the CLOCK_GETRES system call
  *   do_gettime:       perform the CLOCK_GETTIME system call
+ *   do_settime:       perform the CLOCK_SETTIME system call
  *   do_time:          perform the TIME system call
  *   do_stime:         perform the STIME system call
  *   do_times:         perform the TIMES system call
@@ -62,6 +63,27 @@ int do_getres()
   }
 }
 
+/*===========================================================================*
+ *                             do_settime                                   *
+ *===========================================================================*/
+int do_settime()
+{
+  int s;
+
+  if (mp->mp_effuid != SUPER_USER) { 
+      return(EPERM);
+  }
+
+  switch (m_in.clk_id) {
+       case CLOCK_REALTIME:
+               s= sys_settime(1, m_in.clk_id, m_in.time_sec, m_in.time_nsec);
+               return(s);
+       case CLOCK_MONOTONIC: /* monotonic cannot be changed */
+       default:
+               return EINVAL; /* invalid/unsupported clock_id */
+  }
+}
+
 /*===========================================================================*
  *                             do_time                                      *
  *===========================================================================*/
index d27b070c4e9a3b27de0b409667673bed5d324ad2..b655426356d6071b7747d4dc14a6fe008afe9ac3 100644 (file)
@@ -131,6 +131,7 @@ int (*call_vec[])(void) = {
        no_sys,         /* 113 = (getsid) */
        no_sys,         /* 114 = (clock_getres) */
        no_sys,         /* 115 = (clock_gettime) */
+       no_sys,         /* 116 = (clock_settime) */
 };
 /* This should not fail with "array size is negative": */
 extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 : -1];
index 368cb4abb4bd45a3ded25516b561ce46ab73afae..0282f60bb781b0b2a7556701ff082e5f4fd162d7 100644 (file)
@@ -20,6 +20,7 @@ int main(void);
 void quit(void);
 static void test_clock_getres();
 static void test_clock_gettime();
+static void test_clock_settime();
 static void show_timespec(char *msg, struct timespec *ts);
 
 static void test_clock_getres()
@@ -63,6 +64,37 @@ static void test_clock_gettime()
   if (clock_gettime(-1, &ts) == 0) e(31);
 }
 
+static void test_clock_settime(void)
+{
+  struct timespec ts;
+  struct timespec ts2;
+
+  /* shouldn't be able to set MONOTONIC */
+  if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) e(50);
+  if (clock_settime(CLOCK_MONOTONIC, &ts) == 0) e(51);
+  if (errno != EINVAL) e(52); /* reponse should be EINVAL */
+
+  /* set the time of REALTIME to that of MONOTONIC */
+  if (clock_settime(CLOCK_REALTIME, &ts) == -1) e(53);
+
+  ts.tv_sec += 600; /* time travel 10 minutes into the future */
+  if (clock_gettime(CLOCK_REALTIME, &ts2) == -1) e(54);
+  if (clock_settime(CLOCK_REALTIME, &ts) == -1) e(55);
+  if (clock_gettime(CLOCK_REALTIME, &ts) == -1) e(56);
+
+  /* get the value we set, if it's not about 10 minutes ahead, it failed */
+  if (ts.tv_sec - ts2.tv_sec < 500 ||
+       ts.tv_sec - ts2.tv_sec > 700) e(57);
+
+  /* back to current time - don't leave the system time 10 ahead */
+  if (clock_gettime(CLOCK_REALTIME, &ts) == -1) e(58);
+  ts.tv_sec -= 600;
+  if (clock_settime(CLOCK_REALTIME, &ts) == -1) e(59);
+
+  /* Test with an invalid clock */
+  if (clock_settime(-1, &ts) == 0) e(60);
+}
+
 static void show_timespec(char *msg, struct timespec *ts)
 {
 #if DEBUG == 1
@@ -80,6 +112,7 @@ int main()
 
   test_clock_getres();
   test_clock_gettime();
+  test_clock_settime();
 
   /* get test end time */
   if (clock_gettime(CLOCK_MONOTONIC, &endtime) == -1) e(2);