From d82e260a90567a281541949311138fb2f4d76ba2 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Sat, 15 Aug 2009 16:09:32 +0000 Subject: [PATCH] Support for setitimer(ITIMER_REAL). --- include/minix/callnr.h | 1 + include/sys/time.h | 15 +++ lib/posix/Makefile.in | 2 + lib/posix/_getitimer.c | 18 +++ lib/posix/_setitimer.c | 24 ++++ lib/syscall/Makefile.in | 2 + lib/syscall/getitimer.s | 7 + lib/syscall/setitimer.s | 7 + man/man2/getitimer.2 | 67 ++++++++++ servers/pm/Makefile | 2 +- servers/pm/alarm.c | 278 ++++++++++++++++++++++++++++++++++++++++ servers/pm/const.h | 2 + servers/pm/forkexit.c | 3 +- servers/pm/mproc.h | 3 +- servers/pm/param.h | 3 + servers/pm/proto.h | 7 +- servers/pm/signal.c | 98 -------------- servers/pm/table.c | 3 +- servers/pm/timers.c | 14 +- servers/vfs/table.c | 4 +- 20 files changed, 449 insertions(+), 111 deletions(-) create mode 100644 lib/posix/_getitimer.c create mode 100644 lib/posix/_setitimer.c create mode 100644 lib/syscall/getitimer.s create mode 100644 lib/syscall/setitimer.s create mode 100644 man/man2/getitimer.2 create mode 100644 servers/pm/alarm.c diff --git a/include/minix/callnr.h b/include/minix/callnr.h index 92b5fb3bb..1c91cce24 100755 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -53,6 +53,7 @@ #define CHROOT 61 #define SETSID 62 #define GETPGRP 63 +#define ITIMER 64 /* Posix signal handling. */ #define SIGACTION 71 diff --git a/include/sys/time.h b/include/sys/time.h index a2e22609d..1303aba4a 100644 --- a/include/sys/time.h +++ b/include/sys/time.h @@ -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 */ diff --git a/lib/posix/Makefile.in b/lib/posix/Makefile.in index 9303f1a9f..2c5014aea 100644 --- a/lib/posix/Makefile.in +++ b/lib/posix/Makefile.in @@ -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 index 000000000..a01c3449d --- /dev/null +++ b/lib/posix/_getitimer.c @@ -0,0 +1,18 @@ +#include +#define getitimer _getitimer +#include + +/* + * 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 index 000000000..8c487ab71 --- /dev/null +++ b/lib/posix/_setitimer.c @@ -0,0 +1,24 @@ +#include +#define setitimer _setitimer +#include + +/* + * 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); +} diff --git a/lib/syscall/Makefile.in b/lib/syscall/Makefile.in index 403883f38..b25f193d8 100644 --- a/lib/syscall/Makefile.in +++ b/lib/syscall/Makefile.in @@ -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 index 000000000..413dea463 --- /dev/null +++ b/lib/syscall/getitimer.s @@ -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 index 000000000..6018a1a46 --- /dev/null +++ b/lib/syscall/setitimer.s @@ -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 index 000000000..c30d2cd7b --- /dev/null +++ b/man/man2/getitimer.2 @@ -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 + +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 diff --git a/servers/pm/Makefile b/servers/pm/Makefile index 1e1a77fc4..b33e408de 100644 --- a/servers/pm/Makefile +++ b/servers/pm/Makefile @@ -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 index 000000000..0fcc1d151 --- /dev/null +++ b/servers/pm/alarm.c @@ -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 +#include +#include +#include +#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); +} diff --git a/servers/pm/const.h b/servers/pm/const.h index 886380a7c..64558475e 100644 --- a/servers/pm/const.h +++ b/servers/pm/const.h @@ -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) */ diff --git a/servers/pm/forkexit.c b/servers/pm/forkexit.c index 11a96061d..da8d8a9f8 100644 --- a/servers/pm/forkexit.c +++ b/servers/pm/forkexit.c @@ -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) diff --git a/servers/pm/mproc.h b/servers/pm/mproc.h index e5d3e56ac..7e113680c 100644 --- a/servers/pm/mproc.h +++ b/servers/pm/mproc.h @@ -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 */ diff --git a/servers/pm/param.h b/servers/pm/param.h index 47f4aedba..c199c5594 100644 --- a/servers/pm/param.h +++ b/servers/pm/param.h @@ -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 diff --git a/servers/pm/proto.h b/servers/pm/proto.h index ceaeccfc1..5bfee1eeb 100644 --- a/servers/pm/proto.h +++ b/servers/pm/proto.h @@ -7,6 +7,11 @@ struct memory; #include +/* 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) ); diff --git a/servers/pm/signal.c b/servers/pm/signal.c index f3a49baf8..2a05b3723 100644 --- a/servers/pm/signal.c +++ b/servers/pm/signal.c @@ -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 * *===========================================================================*/ diff --git a/servers/pm/table.c b/servers/pm/table.c index e1a1e2c42..251872863 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -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 */ diff --git a/servers/pm/timers.c b/servers/pm/timers.c index 91d21218b..7cc20b349 100644 --- a/servers/pm/timers.c +++ b/servers/pm/timers.c @@ -20,6 +20,7 @@ #include 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); } diff --git a/servers/vfs/table.c b/servers/vfs/table.c index 1b107b57c..cd350252c 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -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 */