]> Zhao Yanbai Git Server - minix.git/commitdiff
Support for setitimer(ITIMER_REAL).
authorDavid van Moolenbroek <david@minix3.org>
Sat, 15 Aug 2009 16:09:32 +0000 (16:09 +0000)
committerDavid van Moolenbroek <david@minix3.org>
Sat, 15 Aug 2009 16:09:32 +0000 (16:09 +0000)
20 files changed:
include/minix/callnr.h
include/sys/time.h
lib/posix/Makefile.in
lib/posix/_getitimer.c [new file with mode: 0644]
lib/posix/_setitimer.c [new file with mode: 0644]
lib/syscall/Makefile.in
lib/syscall/getitimer.s [new file with mode: 0644]
lib/syscall/setitimer.s [new file with mode: 0644]
man/man2/getitimer.2 [new file with mode: 0644]
servers/pm/Makefile
servers/pm/alarm.c [new file with mode: 0644]
servers/pm/const.h
servers/pm/forkexit.c
servers/pm/mproc.h
servers/pm/param.h
servers/pm/proto.h
servers/pm/signal.c
servers/pm/table.c
servers/pm/timers.c
servers/vfs/table.c

index 92b5fb3bb23e6e45ec0d99113ad0fe963b18dcb7..1c91cce24831efca5bd313d7429068b1f6f46c6e 100755 (executable)
@@ -53,6 +53,7 @@
 #define CHROOT           61 
 #define SETSID           62
 #define GETPGRP                  63
+#define ITIMER           64
 
 /* Posix signal handling. */
 #define SIGACTION        71
index a2e22609dd867178d677b86a3a4b789d6f2f007b..1303aba4aa87633095a96bcb00c23f0079b1ef5c 100644 (file)
@@ -24,4 +24,19 @@ int gettimeofday(struct timeval *_RESTRICT tp, void *_RESTRICT tzp);
 /* Compatibility with other Unix systems */
 int settimeofday(const struct timeval *tp, const void *tzp);
 
+/* setitimer/getitimer interface */
+struct itimerval
+{
+       struct timeval it_interval;
+       struct timeval it_value;
+};
+
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1       /* Not implemented */
+#define ITIMER_PROF 2          /* Not implemented */
+
+int getitimer(int which, struct itimerval *value);
+int setitimer(int which, const struct itimerval *_RESTRICT value,
+               struct itimerval *_RESTRICT ovalue);
+
 #endif /* _SYS__TIME_H */
index 9303f1a9f59d4494b6db3690fe843722cd1d9b4e..2c5014aea52f4813602eeef3e2179385afa27356 100644 (file)
@@ -40,6 +40,7 @@ libc_FILES=" \
        _geteuid.c \
        _getgid.c \
        _getgroups.c \
+       _getitimer.c \
        _getpgrp.c \
        _getpid.c \
        _getppid.c \
@@ -69,6 +70,7 @@ libc_FILES=" \
        _rmdir.c \
        _select.c \
        _setgid.c \
+       _setitimer.c \
        _setsid.c \
        _setuid.c \
        _sigaction.c \
diff --git a/lib/posix/_getitimer.c b/lib/posix/_getitimer.c
new file mode 100644 (file)
index 0000000..a01c344
--- /dev/null
@@ -0,0 +1,18 @@
+#include <lib.h>
+#define getitimer _getitimer
+#include <sys/time.h>
+
+/*
+ * This is the implementation for the function to
+ * invoke the interval timer retrieval system call.
+ */
+int getitimer(int which, struct itimerval *value)
+{
+  message m;
+
+  m.m1_i1 = which;
+  m.m1_p1 = NULL;              /* only retrieve the timer */
+  m.m1_p2 = (char *) value;
+
+  return _syscall(PM_PROC_NR, ITIMER, &m);
+}
diff --git a/lib/posix/_setitimer.c b/lib/posix/_setitimer.c
new file mode 100644 (file)
index 0000000..8c487ab
--- /dev/null
@@ -0,0 +1,24 @@
+#include <lib.h>
+#define setitimer _setitimer
+#include <sys/time.h>
+
+/*
+ * This is the implementation of the function to
+ * invoke the interval timer setting system call.
+ */
+int setitimer(int which, const struct itimerval *_RESTRICT value,
+               struct itimerval *_RESTRICT ovalue)
+{
+  message m;
+
+  /* A null pointer for 'value' would make setitimer behave like getitimer,
+   * which is not according to the specification, so disallow null pointers.
+   */
+  if (value == NULL) return(EINVAL);
+
+  m.m1_i1 = which;
+  m.m1_p1 = (char *) value;
+  m.m1_p2 = (char *) ovalue;
+
+  return _syscall(PM_PROC_NR, ITIMER, &m);
+}
index 403883f386a783a36740a60f9663c4b90ba0338b..b25f193d825040c0cc21e359c5b1ae6da254950d 100644 (file)
@@ -45,6 +45,7 @@ libc_FILES=" \
        geteuid.s \
        getgid.s \
        getgroups.s \
+       getitimer.s \
        getnpid.s \
        getnprocnr.s \
        getpgrp.s \
@@ -86,6 +87,7 @@ libc_FILES=" \
        select.s \
        seekdir.s \
        setgid.s \
+       setitimer.s \
        setsid.s \
        setuid.s \
        sigaction.s \
diff --git a/lib/syscall/getitimer.s b/lib/syscall/getitimer.s
new file mode 100644 (file)
index 0000000..413dea4
--- /dev/null
@@ -0,0 +1,7 @@
+.sect .text
+.extern __getitimer
+.define _getitimer
+.align 2
+
+_getitimer:
+       jmp     __getitimer
diff --git a/lib/syscall/setitimer.s b/lib/syscall/setitimer.s
new file mode 100644 (file)
index 0000000..6018a1a
--- /dev/null
@@ -0,0 +1,7 @@
+.sect .text
+.extern __setitimer
+.define _setitimer
+.align 2
+
+_setitimer:
+       jmp     __setitimer
diff --git a/man/man2/getitimer.2 b/man/man2/getitimer.2
new file mode 100644 (file)
index 0000000..c30d2cd
--- /dev/null
@@ -0,0 +1,67 @@
+.TH GETITIMER 2  "April 14, 2006"
+.UC 4
+.SH NAME
+getitimer, setitimer \- get and set value of interval timer
+.SH SYNOPSIS
+.nf
+.ft B
+#include <sys/time.h>
+
+int getitimer(int \fIwhich\fP, struct itimerval *\fIvalue\fP)
+.in +5
+.ti -5
+int setitimer(int \fIwhich\fP, const struct itimerval *\fIvalue\fP, struct itimerval *\fIovalue\fP);
+.in -5
+.ft R
+.fi
+.SH DESCRIPTION
+.B Getitimer
+retrieves the current value of the given interval timer, in \fIvalue\fP.
+.PP
+.B Setitimer
+sets a new value for the given interval timer, as given in \fIvalue\fP, and, if \fIovalue\fP is not set to 
+.BR NULL , 
+stores the old value for the interval timer in \fIovalue\fP.
+.PP
+For both functions, the \fIwhich\fP parameter indicates which of the interval timers they work on; \fIwhich\fP can have one of the following values:
+.PP
+.TP 15
+.B ITIMER_REAL
+A timer that is decremented in realtime. When it expires, a
+.BR SIGARLM
+signal is delivered to the process.
+.TP
+.B ITIMER_VIRTUAL
+Not supported on Minix.
+.TP
+.B ITIMER_PROF
+Not supported on Minix.
+.PP
+The specified timer will first expire after the time specified in the 'it_value' field of the itimerval structure. Similarly, upon retrieval the 'it_value' field will contain the time after which the timer will expire.
+.PP
+If 'it_value' is zero, then the timer is disabled, and the 'it_interval' field is ignored and (upon retrieval) set to zero. Otherwise, 'it_interval' contains the repetition interval after which the timer will repeatedly expire, starting from the moment that the timer expires for the first time according to the 'it_value' value. If 'it_interval' is set to zero, no repetition will occur.
+.PP
+The maximum supported timeout value that
+.B setitimer 
+accepts, depends on the clock tick rate of the operating system.
+.PP
+These functions share their real-time timer with
+.BR alarm (2).
+Therefore, use of both types of functions in one program yields undefined results.
+.SH RETURN VALUES
+Upon successful completion, these functions return 0. Otherwise, a value of -1 is returned and \fIerrno\fP is set to indicate the error.
+.SH ERRORS
+The functions will fail if any of the following occur:
+.TP 15
+.B EINVAL
+Either \fIwhich\fP is not one of the ITIMER_* constants above, or one of the timeval structures in \fIvalue\fP contains a bad or too large value.
+.TP
+.B EFAULT
+Bad \fIvalue\fP or \fIovalue\fP address. 
+.TP
+.B ENOSYS
+The value of \fIwhich\fP is not ITIMER_REAL.
+.SH SEE ALSO
+.BR alarm (2)
+.SH AUTHOR
+David van Moolenbroek <dcvmoole@cs.vu.nl>
index 1e1a77fc49da79bbe2285fdd8fe94446b7e2a822..b33e408de6d342af78a2d97a5d389e716e8a8733 100644 (file)
@@ -16,7 +16,7 @@ CPPFLAGS=-I../../kernel/arch/$(ARCH)/include -I$i
 CFLAGS = $(CPROFILE) $(CPPFLAGS)
 LDFLAGS = -i
 
-OBJ =  main.o forkexit.o break.o exec.o time.o timers.o \
+OBJ =  main.o forkexit.o break.o exec.o time.o timers.o alarm.o \
        signal.o utility.o table.o trace.o getset.o misc.o \
        profile.o dma.o
 
diff --git a/servers/pm/alarm.c b/servers/pm/alarm.c
new file mode 100644 (file)
index 0000000..0fcc1d1
--- /dev/null
@@ -0,0 +1,278 @@
+/* This file deals with the alarm clock related system calls, eventually
+ * passing off the work to the functions in timers.c and check_sig() in
+ * signal.c to pass an alarm signal to a process.
+ *
+ * The entry points into this file are:
+ *   do_itimer: perform the ITIMER system call
+ *   do_alarm: perform the ALARM system call
+ *   set_alarm: tell the timer interface to start or stop a process timer
+ */
+
+#include "pm.h"
+#include <signal.h>
+#include <sys/time.h>
+#include <string.h>
+#include <minix/com.h>
+#include "mproc.h"
+#include "param.h"
+
+#define US 1000000     /* shortcut for microseconds per second */
+
+FORWARD _PROTOTYPE( clock_t ticks_from_timeval, (struct timeval *tv)   );
+FORWARD _PROTOTYPE( void timeval_from_ticks, (struct timeval *tv,
+                       clock_t ticks)                                  );
+FORWARD _PROTOTYPE( int is_sane_timeval, (struct timeval *tv)          );
+FORWARD _PROTOTYPE( void get_realtimer, (struct mproc *mp,
+                                        struct itimerval *value)       );
+FORWARD _PROTOTYPE( void set_realtimer, (struct mproc *mp,
+                                        struct itimerval *value)       );
+FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp)             );
+
+/*===========================================================================*
+ *                             ticks_from_timeval                           * 
+ *===========================================================================*/
+PRIVATE clock_t ticks_from_timeval(tv)
+struct timeval *tv;
+{
+  clock_t ticks;
+
+  /* Large delays cause a lot of problems.  First, the alarm system call
+   * takes an unsigned seconds count and the library has cast it to an int.
+   * That probably works, but on return the library will convert "negative"
+   * unsigneds to errors.  Presumably no one checks for these errors, so
+   * force this call through.  Second, If unsigned and long have the same
+   * size, converting from seconds to ticks can easily overflow.  Finally,
+   * the kernel has similar overflow bugs adding ticks.
+   *
+   * Fixing this requires a lot of ugly casts to fit the wrong interface
+   * types and to avoid overflow traps.  ALRM_EXP_TIME has the right type
+   * (clock_t) although it is declared as long.  How can variables like
+   * this be declared properly without combinatorial explosion of message
+   * types?
+   */
+       
+  /* In any case, the following conversion must always round up. */
+
+  ticks = (clock_t) (system_hz * (unsigned long) tv->tv_sec);
+  if ( (unsigned long) ticks / system_hz != (unsigned long) tv->tv_sec) {
+       ticks = LONG_MAX;
+  } else {
+       ticks += (clock_t)
+               ((system_hz * (unsigned long) tv->tv_usec + (US-1)) / US);
+  }
+
+  if (ticks < 0) ticks = LONG_MAX;
+
+  return(ticks);
+}
+
+/*===========================================================================*
+ *                             timeval_from_ticks                           * 
+ *===========================================================================*/
+PRIVATE void timeval_from_ticks(tv, ticks)
+struct timeval *tv;
+clock_t ticks;
+{
+  tv->tv_sec = (long) (ticks / system_hz);
+  tv->tv_usec = (long) ((ticks % system_hz) * US / system_hz);
+}
+
+/*===========================================================================*
+ *                             is_sane_timeval                              * 
+ *===========================================================================*/
+PRIVATE int is_sane_timeval(tv)
+struct timeval *tv;
+{
+  /* This imposes a reasonable time value range for setitimer. */
+  return (tv->tv_sec >= 0 && tv->tv_sec <= MAX_SECS &&
+         tv->tv_usec >= 0 && tv->tv_usec < US);
+}
+/*===========================================================================*
+ *                             do_itimer                                    *
+ *===========================================================================*/
+PUBLIC int do_itimer()
+{
+  struct itimerval ovalue, value;      /* old and new interval timers */
+  int setval, getval;                  /* set and/or retrieve the values? */
+  int r;
+
+  /* Make sure 'which' is one of the defined timers. */
+  if (m_in.which_timer < ITIMER_REAL || m_in.which_timer > ITIMER_PROF)
+       return(EINVAL);
+
+  /* Determine whether to set and/or return the given timer value, based on
+   * which of the new_val and old_val parameters are nonzero. At least one of
+   * them must be nonzero.
+   */
+  setval = (m_in.new_val != NULL);
+  getval = (m_in.old_val != NULL);
+
+  if (!setval && !getval) return(EINVAL);
+
+  /* If we're setting a new value, copy the new timer from user space.
+   * Also, make sure its fields have sane values.
+   */
+  if (setval) {
+       r = sys_datacopy(who_e, (vir_bytes) m_in.new_val,
+               PM_PROC_NR, (vir_bytes) &value, (phys_bytes) sizeof(value));
+       if (r != OK) return(r);
+
+       if (!is_sane_timeval(&value.it_value) ||
+           !is_sane_timeval(&value.it_interval))
+               return(EINVAL);
+  }
+
+  switch (m_in.which_timer) {
+       case ITIMER_REAL :
+               if (getval) get_realtimer(mp, &ovalue);
+
+               if (setval) set_realtimer(mp, &value);
+
+               r = OK;
+               break;
+
+       case ITIMER_VIRTUAL :
+       case ITIMER_PROF :
+               /* Not implemented. */
+               r = ENOSYS;
+               break;
+  }
+
+  /* If requested, copy the old interval timer to user space. */
+  if (r == OK && getval) {
+       r = sys_datacopy(PM_PROC_NR, (vir_bytes) &ovalue,
+               who_e, (vir_bytes) m_in.old_val, (phys_bytes) sizeof(ovalue));
+  }
+
+  return(r);
+}
+
+/*===========================================================================*
+ *                             do_alarm                                     *
+ *===========================================================================*/
+PUBLIC int do_alarm()
+{
+  struct itimerval value, ovalue;
+  int remaining;               /* previous time left in seconds */
+
+  /* retrieve the old timer value, in seconds (rounded up) */
+  get_realtimer(mp, &ovalue);
+  
+  remaining = ovalue.it_value.tv_sec;
+  if (ovalue.it_value.tv_usec > 0) remaining++;
+
+  /* set the new timer value */
+  memset(&value, 0, sizeof(value));
+  value.it_value.tv_sec = m_in.seconds;
+
+  set_realtimer(mp, &value);
+
+  /* and return the old timer value */
+  return(remaining);
+}
+
+/*===========================================================================*
+ *                             get_realtimer                                * 
+ *===========================================================================*/
+PRIVATE void get_realtimer(rmp, value)
+struct mproc *rmp;
+struct itimerval *value;
+{
+  clock_t exptime;     /* time at which alarm will expire */
+  clock_t uptime;      /* current system time */
+  clock_t remaining;   /* time left on alarm */
+  int s;
+
+  /* First determine remaining time, in ticks, of previous alarm, if set. */
+  if (rmp->mp_flags & ALARM_ON) {
+       if ( (s = getuptime(&uptime)) != OK)
+               panic(__FILE__, "get_realtimer couldn't get uptime", s);
+       exptime = *tmr_exp_time(&rmp->mp_timer);
+
+       remaining = exptime - uptime;
+
+       /* If the alarm expired already, we should take into account the
+        * interval. Return zero only if the interval is zero as well.
+        */
+       if (remaining <= 0) remaining = rmp->mp_interval;
+  } else {
+       remaining = 0;
+  }
+
+  /* Convert the result to a timeval structure. */
+  timeval_from_ticks(&value->it_value, remaining);
+
+  /* Similarly convert and store the interval of the timer. */
+  timeval_from_ticks(&value->it_interval, rmp->mp_interval);
+}
+
+/*===========================================================================*
+ *                             set_realtimer                                * 
+ *===========================================================================*/
+PRIVATE void set_realtimer(rmp, value)
+struct mproc *rmp;
+struct itimerval *value;
+{
+  clock_t ticks;       /* New amount of ticks to the next alarm. */
+  clock_t interval;    /* New amount of ticks for the alarm's interval. */
+
+  /* Convert the timeval structures in the 'value' structure to ticks. */
+  ticks = ticks_from_timeval(&value->it_value);
+  interval = ticks_from_timeval(&value->it_interval);
+
+  /* If no timer is set, the interval must be zero. */
+  if (ticks <= 0) interval = 0;
+
+  /* Apply these values. */
+  set_alarm(rmp, ticks);
+  rmp->mp_interval = interval;
+}
+
+/*===========================================================================*
+ *                             set_alarm                                    * 
+ *===========================================================================*/
+PUBLIC void set_alarm(rmp, ticks)
+struct mproc *rmp;             /* process that wants the alarm */
+clock_t ticks;                 /* how many ticks delay before the signal */
+{
+  if (ticks > 0) {
+       pm_set_timer(&rmp->mp_timer, ticks, cause_sigalrm, rmp->mp_endpoint);
+       rmp->mp_flags |=  ALARM_ON;
+  } else if (rmp->mp_flags & ALARM_ON) {
+       pm_cancel_timer(&rmp->mp_timer);
+       rmp->mp_flags &= ~ALARM_ON;
+  }
+}
+
+/*===========================================================================*
+ *                             cause_sigalrm                                * 
+ *===========================================================================*/
+PRIVATE void cause_sigalrm(tp)
+struct timer *tp;
+{
+  int proc_nr_n;
+  register struct mproc *rmp;
+
+  /* get process from timer */
+  if(pm_isokendpt(tmr_arg(tp)->ta_int, &proc_nr_n) != OK) {
+       printf("PM: ignoring timer for invalid endpoint %d\n",
+               tmr_arg(tp)->ta_int);
+       return;
+  }
+
+  rmp = &mproc[proc_nr_n];
+
+  if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) return;
+  if ((rmp->mp_flags & ALARM_ON) == 0) return;
+
+  /* If an interval is set, set a new timer; otherwise clear the ALARM_ON flag.
+   * The set_alarm call will be calling pm_set_timer from within this callback
+   * from the pm_expire_timers function. This is safe, but we must not use the
+   * "tp" structure below this point anymore. */
+  if (rmp->mp_interval > 0)
+       set_alarm(rmp, rmp->mp_interval);
+  else rmp->mp_flags &= ~ALARM_ON;
+
+  check_sig(rmp->mp_pid, SIGALRM);
+}
index 886380a7c6169e9c9767ccaadabcfb54ccc6e62b..64558475e0491b1820f0e9b906b9e1816ea37305 100644 (file)
@@ -10,3 +10,5 @@
 
 #define DUMPED          0200   /* bit set in status when core dumped */
 
+#define MAX_SECS (((1<<(sizeof(clock_t)*8-1))-1)/system_hz)
+                               /* max.secs for setitimer() ((2^31-1)/HZ) */
index 11a96061dbe51f4c3b40c12f2aca4fc794a5c01a..da8d8a9f8295499f26e1ccf776073ea6aa98efad 100644 (file)
@@ -86,6 +86,7 @@ PUBLIC int do_fork()
   rmc->mp_exitstatus = 0;
   rmc->mp_sigstatus = 0;
   rmc->mp_endpoint = child_ep;         /* passed back by VM */
+  rmc->mp_interval = 0;                        /* reset interval timer */
 
   /* Find a free pid for the child and put it in the table. */
   new_pid = get_free_pid();
@@ -222,7 +223,7 @@ int dump_core;                      /* flag indicating whether to dump core */
   procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
 
   /* If the exited process has a timer pending, kill it. */
-  if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr_e, (unsigned) 0);
+  if (rmp->mp_flags & ALARM_ON) set_alarm(rmp, (clock_t) 0);
 
   /* Do accounting: fetch usage times and accumulate at parent. */
   if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK)
index e5d3e56ace57eb8aff01875d84e06ee8f84246bd..7e113680ce16307cefe7d760700a76d96c37fcc4 100644 (file)
@@ -38,7 +38,8 @@ EXTERN struct mproc {
   struct sigmsg mp_sigmsg;     /* Save the details of the signal until the
                                 * PM_UNPAUSE request is delivered.
                                 */
-  struct timer mp_timer;       /* watchdog timer for alarm(2) */
+  struct timer mp_timer;       /* watchdog timer for alarm(2), setitimer(2) */
+  clock_t mp_interval;         /* repetition interval for setitimer(2) */
 
   unsigned mp_flags;           /* flag bits */
   vir_bytes mp_procargs;        /* ptr to proc's initial stack arguments */
index 47f4aedbaf58edccba4eb3d33e6f97c861b43670..c199c55944eea822c9d58574b30119043f8425e6 100644 (file)
@@ -9,6 +9,9 @@
 #define endpt          m1_i1
 #define pendpt         m1_i2
 #define seconds                m1_i1
+#define which_timer    m1_i1
+#define new_val                m1_p1
+#define old_val                m1_p2
 #define sig            m6_i1
 #define stack_bytes    m1_i2
 #define stack_ptr      m1_p2
index ceaeccfc1a5bf03d50ca119c96ec0cf622e9a596..5bfee1eeb5ce7fbe101ffa128d9dd3ac56a2c4ab 100644 (file)
@@ -7,6 +7,11 @@ struct memory;
 
 #include <timers.h>
 
+/* alarm.c */
+_PROTOTYPE( int do_alarm, (void)                                       );
+_PROTOTYPE( int do_itimer, (void)                                      );
+_PROTOTYPE( void set_alarm, (struct mproc *rmp, clock_t ticks)         );
+
 /* break.c */
 _PROTOTYPE( int do_brk, (void)                                         );
 
@@ -73,11 +78,9 @@ _PROTOTYPE( int do_sprofile, (void)                                    );
 _PROTOTYPE( int do_cprofile, (void)                                    );
 
 /* signal.c */
-_PROTOTYPE( int do_alarm, (void)                                       );
 _PROTOTYPE( int do_kill, (void)                                                );
 _PROTOTYPE( int ksig_pending, (void)                                   );
 _PROTOTYPE( int do_pause, (void)                                       );
-_PROTOTYPE( int set_alarm, (int proc_nr, int sec)                      );
 _PROTOTYPE( int check_sig, (pid_t proc_id, int signo)                  );
 _PROTOTYPE( void sig_proc, (struct mproc *rmp, int sig_nr)             );
 _PROTOTYPE( int do_sigaction, (void)                                   );
index f3a49baf8313c5bdb30bfa95e569780b1d69bd58..2a05b37233e5dd4756c5e0896e153579cba66fae 100644 (file)
@@ -11,8 +11,6 @@
  *   do_sigreturn:   perform the SIGRETURN system call
  *   do_sigsuspend:  perform the SIGSUSPEND system call
  *   do_kill:  perform the KILL system call
- *   do_alarm: perform the ALARM system call by calling set_alarm()
- *   set_alarm:        tell the clock task to start or stop a timer
  *   do_pause: perform the PAUSE system call
  *   ksig_pending: the kernel notified about pending signals
  *   sig_proc: interrupt or terminate a signaled process
@@ -36,7 +34,6 @@
 
 FORWARD _PROTOTYPE( void unpause, (int pro, int for_trace)             );
 FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map)  );
-FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp)             );
 
 /*===========================================================================*
  *                             do_sigaction                                 *
@@ -290,101 +287,6 @@ sigset_t sig_map;
   }
 }
 
-/*===========================================================================*
- *                             do_alarm                                     *
- *===========================================================================*/
-PUBLIC int do_alarm()
-{
-/* Perform the alarm(seconds) system call. */
-  return(set_alarm(who_e, m_in.seconds));
-}
-
-/*===========================================================================*
- *                             set_alarm                                    *
- *===========================================================================*/
-PUBLIC int set_alarm(proc_nr_e, sec)
-int proc_nr_e;                 /* process that wants the alarm */
-int sec;                       /* how many seconds delay before the signal */
-{
-/* This routine is used by do_alarm() to set the alarm timer.  It is also used
- * to turn the timer off when a process exits with the timer still on.
- */
-  clock_t ticks;       /* number of ticks for alarm */
-  clock_t exptime;     /* needed for remaining time on previous alarm */
-  clock_t uptime;      /* current system time */
-  int remaining;       /* previous time left in seconds */
-  int s;
-  int proc_nr_n;
-
-  if(pm_isokendpt(proc_nr_e, &proc_nr_n) != OK)
-       return EINVAL;
-
-  /* First determine remaining time of previous alarm, if set. */
-  if (mproc[proc_nr_n].mp_flags & ALARM_ON) {
-       if ( (s=getuptime(&uptime)) != OK) 
-               panic(__FILE__,"set_alarm couldn't get uptime", s);
-       exptime = *tmr_exp_time(&mproc[proc_nr_n].mp_timer);
-       remaining = (int) ((exptime - uptime + (system_hz-1))/system_hz);
-       if (remaining < 0) remaining = 0;       
-  } else {
-       remaining = 0; 
-  }
-
-  /* Tell the clock task to provide a signal message when the time comes.
-   *
-   * Large delays cause a lot of problems.  First, the alarm system call
-   * takes an unsigned seconds count and the library has cast it to an int.
-   * That probably works, but on return the library will convert "negative"
-   * unsigneds to errors.  Presumably no one checks for these errors, so
-   * force this call through.  Second, If unsigned and long have the same
-   * size, converting from seconds to ticks can easily overflow.  Finally,
-   * the kernel has similar overflow bugs adding ticks.
-   *
-   * Fixing this requires a lot of ugly casts to fit the wrong interface
-   * types and to avoid overflow traps.  ALRM_EXP_TIME has the right type
-   * (clock_t) although it is declared as long.  How can variables like
-   * this be declared properly without combinatorial explosion of message
-   * types?
-   */
-  ticks = (clock_t) (system_hz * (unsigned long) (unsigned) sec);
-  if ( (unsigned long) ticks / system_hz != (unsigned) sec)
-       ticks = LONG_MAX;       /* eternity (really TMR_NEVER) */
-
-  if (ticks != 0) {
-       pm_set_timer(&mproc[proc_nr_n].mp_timer, ticks,
-               cause_sigalrm, proc_nr_e);
-       mproc[proc_nr_n].mp_flags |=  ALARM_ON;
-  } else if (mproc[proc_nr_n].mp_flags & ALARM_ON) {
-       pm_cancel_timer(&mproc[proc_nr_n].mp_timer);
-       mproc[proc_nr_n].mp_flags &= ~ALARM_ON;
-  }
-  return(remaining);
-}
-
-/*===========================================================================*
- *                             cause_sigalrm                                *
- *===========================================================================*/
-PRIVATE void cause_sigalrm(tp)
-struct timer *tp;
-{
-  int proc_nr_n;
-  register struct mproc *rmp;
-
-  /* get process from timer */
-  if(pm_isokendpt(tmr_arg(tp)->ta_int, &proc_nr_n) != OK) {
-       printf("PM: ignoring timer for invalid endpoint %d\n",
-               tmr_arg(tp)->ta_int);
-       return;
-  }
-
-  rmp = &mproc[proc_nr_n];
-
-  if ((rmp->mp_flags & (IN_USE | EXITING)) != IN_USE) return;
-  if ((rmp->mp_flags & ALARM_ON) == 0) return;
-  rmp->mp_flags &= ~ALARM_ON;
-  check_sig(rmp->mp_pid, SIGALRM);
-}
-
 /*===========================================================================*
  *                             do_pause                                     *
  *===========================================================================*/
index e1a1e2c428e4918cd2afcdf1d9e86b16353a45e4..25187286398048ef440c369a6b116e42836f6ba6 100644 (file)
@@ -78,8 +78,7 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
        no_sys,         /* 61 = chroot  */
        do_getset,      /* 62 = setsid  */
        do_getset,      /* 63 = getpgrp */
-
-       no_sys,         /* 64 = unused  */
+       do_itimer,      /* 64 = itimer  */
        no_sys,         /* 65 = unused  */
        no_sys,         /* 66 = unused  */
        no_sys,         /* 67 = unused  */
index 91d21218bb350da670e759334d74a416eb192d64..7cc20b3495ad5b73e388b154339e3d7902968e5b 100644 (file)
@@ -20,6 +20,7 @@
 #include <minix/com.h>
 
 PRIVATE timer_t *pm_timers = NULL;
+PRIVATE int pm_expiring = 0;
 
 /*===========================================================================*
  *                             pm_set_timer                                 *
@@ -37,7 +38,7 @@ PUBLIC void pm_set_timer(timer_t *tp, int ticks, tmr_func_t watchdog, int arg)
        prev_time = tmrs_settimer(&pm_timers,tp,now+ticks,watchdog,&next_time);
 
        /* Reschedule our synchronous alarm if necessary. */
-       if (! prev_time || prev_time > next_time) {
+       if (pm_expiring == 0 && (! prev_time || prev_time > next_time)) {
                if (sys_setalarm(next_time, 1) != OK)
                        panic(__FILE__, "PM set timer couldn't set alarm.", NO_NUM);
        }
@@ -52,8 +53,15 @@ PUBLIC void pm_expire_timers(clock_t now)
 {
        clock_t next_time;
 
-       /* Check for expired timers and possibly reschedule an alarm. */
+       /* Check for expired timers. Use a global variable to indicate that
+        * watchdog functions are called, so that sys_setalarm() isn't called
+        * more often than necessary when pm_set_timer or pm_cancel_timer are
+        * called from these watchdog functions. */
+       pm_expiring = 1;
        tmrs_exptimers(&pm_timers, now, &next_time);
+       pm_expiring = 0;
+
+       /* Reschedule an alarm if necessary. */
        if (next_time > 0) {
                if (sys_setalarm(next_time, 1) != OK)
                        panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
@@ -72,7 +80,7 @@ PUBLIC void pm_cancel_timer(timer_t *tp)
      * the next timer, or cancel the alarm altogether if the last timer has 
      * been cancelled (next_time will be 0 then).
         */
-       if (prev_time < next_time || ! next_time) {
+       if (pm_expiring == 0 && (prev_time < next_time || ! next_time)) {
                if (sys_setalarm(next_time, 1) != OK)
                        panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
        }
index 1b107b57ca974c6ef0ea5973a5faa1a2cbd8190c..cd350252ce41f947920ab43683990c91a9fbbd2b 100644 (file)
@@ -80,8 +80,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
        do_chroot,      /* 61 = chroot  */
        no_sys,         /* 62 = (setsid) */
        no_sys,         /* 63 = (getpgrp) */
-
-       no_sys,         /* 64 = unused  */
+       no_sys,         /* 64 = (itimer) */
        no_sys,         /* 65 = unused  */
        no_sys,         /* 66 = unused  */
        no_sys,         /* 67 = unused  */
@@ -95,7 +94,6 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
        no_sys,         /* 75 = (sigreturn) */
        no_sys,         /* 76 = (reboot) */
        do_svrctl,      /* 77 = svrctl */
-
        no_sys,         /* 78 = (sysuname) */
        do_getsysinfo,  /* 79 = getsysinfo */
        do_getdents,    /* 80 = getdents */