#define CHROOT 61
#define SETSID 62
#define GETPGRP 63
+#define ITIMER 64
/* Posix signal handling. */
#define SIGACTION 71
/* 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 */
_geteuid.c \
_getgid.c \
_getgroups.c \
+ _getitimer.c \
_getpgrp.c \
_getpid.c \
_getppid.c \
_rmdir.c \
_select.c \
_setgid.c \
+ _setitimer.c \
_setsid.c \
_setuid.c \
_sigaction.c \
--- /dev/null
+#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);
+}
--- /dev/null
+#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);
+}
geteuid.s \
getgid.s \
getgroups.s \
+ getitimer.s \
getnpid.s \
getnprocnr.s \
getpgrp.s \
select.s \
seekdir.s \
setgid.s \
+ setitimer.s \
setsid.s \
setuid.s \
sigaction.s \
--- /dev/null
+.sect .text
+.extern __getitimer
+.define _getitimer
+.align 2
+
+_getitimer:
+ jmp __getitimer
--- /dev/null
+.sect .text
+.extern __setitimer
+.define _setitimer
+.align 2
+
+_setitimer:
+ jmp __setitimer
--- /dev/null
+.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>
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
--- /dev/null
+/* 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);
+}
#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) */
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();
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)
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 */
#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
#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) );
_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) );
* 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
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 *
}
}
-/*===========================================================================*
- * 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 *
*===========================================================================*/
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 */
#include <minix/com.h>
PRIVATE timer_t *pm_timers = NULL;
+PRIVATE int pm_expiring = 0;
/*===========================================================================*
* pm_set_timer *
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);
}
{
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);
* 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);
}
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 */
no_sys, /* 75 = (sigreturn) */
no_sys, /* 76 = (reboot) */
do_svrctl, /* 77 = svrctl */
-
no_sys, /* 78 = (sysuname) */
do_getsysinfo, /* 79 = getsysinfo */
do_getdents, /* 80 = getdents */