Support for setitimer(ITIMER_REAL).
This commit is contained in:
parent
062bb2c1e8
commit
d82e260a90
20 changed files with 449 additions and 111 deletions
|
@ -53,6 +53,7 @@
|
||||||
#define CHROOT 61
|
#define CHROOT 61
|
||||||
#define SETSID 62
|
#define SETSID 62
|
||||||
#define GETPGRP 63
|
#define GETPGRP 63
|
||||||
|
#define ITIMER 64
|
||||||
|
|
||||||
/* Posix signal handling. */
|
/* Posix signal handling. */
|
||||||
#define SIGACTION 71
|
#define SIGACTION 71
|
||||||
|
|
|
@ -24,4 +24,19 @@ int gettimeofday(struct timeval *_RESTRICT tp, void *_RESTRICT tzp);
|
||||||
/* Compatibility with other Unix systems */
|
/* Compatibility with other Unix systems */
|
||||||
int settimeofday(const struct timeval *tp, const void *tzp);
|
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 */
|
#endif /* _SYS__TIME_H */
|
||||||
|
|
|
@ -40,6 +40,7 @@ libc_FILES=" \
|
||||||
_geteuid.c \
|
_geteuid.c \
|
||||||
_getgid.c \
|
_getgid.c \
|
||||||
_getgroups.c \
|
_getgroups.c \
|
||||||
|
_getitimer.c \
|
||||||
_getpgrp.c \
|
_getpgrp.c \
|
||||||
_getpid.c \
|
_getpid.c \
|
||||||
_getppid.c \
|
_getppid.c \
|
||||||
|
@ -69,6 +70,7 @@ libc_FILES=" \
|
||||||
_rmdir.c \
|
_rmdir.c \
|
||||||
_select.c \
|
_select.c \
|
||||||
_setgid.c \
|
_setgid.c \
|
||||||
|
_setitimer.c \
|
||||||
_setsid.c \
|
_setsid.c \
|
||||||
_setuid.c \
|
_setuid.c \
|
||||||
_sigaction.c \
|
_sigaction.c \
|
||||||
|
|
18
lib/posix/_getitimer.c
Normal file
18
lib/posix/_getitimer.c
Normal file
|
@ -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);
|
||||||
|
}
|
24
lib/posix/_setitimer.c
Normal file
24
lib/posix/_setitimer.c
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ libc_FILES=" \
|
||||||
geteuid.s \
|
geteuid.s \
|
||||||
getgid.s \
|
getgid.s \
|
||||||
getgroups.s \
|
getgroups.s \
|
||||||
|
getitimer.s \
|
||||||
getnpid.s \
|
getnpid.s \
|
||||||
getnprocnr.s \
|
getnprocnr.s \
|
||||||
getpgrp.s \
|
getpgrp.s \
|
||||||
|
@ -86,6 +87,7 @@ libc_FILES=" \
|
||||||
select.s \
|
select.s \
|
||||||
seekdir.s \
|
seekdir.s \
|
||||||
setgid.s \
|
setgid.s \
|
||||||
|
setitimer.s \
|
||||||
setsid.s \
|
setsid.s \
|
||||||
setuid.s \
|
setuid.s \
|
||||||
sigaction.s \
|
sigaction.s \
|
||||||
|
|
7
lib/syscall/getitimer.s
Normal file
7
lib/syscall/getitimer.s
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.sect .text
|
||||||
|
.extern __getitimer
|
||||||
|
.define _getitimer
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
_getitimer:
|
||||||
|
jmp __getitimer
|
7
lib/syscall/setitimer.s
Normal file
7
lib/syscall/setitimer.s
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
.sect .text
|
||||||
|
.extern __setitimer
|
||||||
|
.define _setitimer
|
||||||
|
.align 2
|
||||||
|
|
||||||
|
_setitimer:
|
||||||
|
jmp __setitimer
|
67
man/man2/getitimer.2
Normal file
67
man/man2/getitimer.2
Normal file
|
@ -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>
|
|
@ -16,7 +16,7 @@ CPPFLAGS=-I../../kernel/arch/$(ARCH)/include -I$i
|
||||||
CFLAGS = $(CPROFILE) $(CPPFLAGS)
|
CFLAGS = $(CPROFILE) $(CPPFLAGS)
|
||||||
LDFLAGS = -i
|
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 \
|
signal.o utility.o table.o trace.o getset.o misc.o \
|
||||||
profile.o dma.o
|
profile.o dma.o
|
||||||
|
|
||||||
|
|
278
servers/pm/alarm.c
Normal file
278
servers/pm/alarm.c
Normal file
|
@ -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);
|
||||||
|
}
|
|
@ -10,3 +10,5 @@
|
||||||
|
|
||||||
#define DUMPED 0200 /* bit set in status when core dumped */
|
#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) */
|
||||||
|
|
|
@ -86,6 +86,7 @@ PUBLIC int do_fork()
|
||||||
rmc->mp_exitstatus = 0;
|
rmc->mp_exitstatus = 0;
|
||||||
rmc->mp_sigstatus = 0;
|
rmc->mp_sigstatus = 0;
|
||||||
rmc->mp_endpoint = child_ep; /* passed back by VM */
|
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. */
|
/* Find a free pid for the child and put it in the table. */
|
||||||
new_pid = get_free_pid();
|
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;
|
procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp : 0;
|
||||||
|
|
||||||
/* If the exited process has a timer pending, kill it. */
|
/* 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. */
|
/* Do accounting: fetch usage times and accumulate at parent. */
|
||||||
if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK)
|
if((r=sys_times(proc_nr_e, &user_time, &sys_time, NULL)) != OK)
|
||||||
|
|
|
@ -38,7 +38,8 @@ EXTERN struct mproc {
|
||||||
struct sigmsg mp_sigmsg; /* Save the details of the signal until the
|
struct sigmsg mp_sigmsg; /* Save the details of the signal until the
|
||||||
* PM_UNPAUSE request is delivered.
|
* 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 */
|
unsigned mp_flags; /* flag bits */
|
||||||
vir_bytes mp_procargs; /* ptr to proc's initial stack arguments */
|
vir_bytes mp_procargs; /* ptr to proc's initial stack arguments */
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
#define endpt m1_i1
|
#define endpt m1_i1
|
||||||
#define pendpt m1_i2
|
#define pendpt m1_i2
|
||||||
#define seconds m1_i1
|
#define seconds m1_i1
|
||||||
|
#define which_timer m1_i1
|
||||||
|
#define new_val m1_p1
|
||||||
|
#define old_val m1_p2
|
||||||
#define sig m6_i1
|
#define sig m6_i1
|
||||||
#define stack_bytes m1_i2
|
#define stack_bytes m1_i2
|
||||||
#define stack_ptr m1_p2
|
#define stack_ptr m1_p2
|
||||||
|
|
|
@ -7,6 +7,11 @@ struct memory;
|
||||||
|
|
||||||
#include <timers.h>
|
#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 */
|
/* break.c */
|
||||||
_PROTOTYPE( int do_brk, (void) );
|
_PROTOTYPE( int do_brk, (void) );
|
||||||
|
|
||||||
|
@ -73,11 +78,9 @@ _PROTOTYPE( int do_sprofile, (void) );
|
||||||
_PROTOTYPE( int do_cprofile, (void) );
|
_PROTOTYPE( int do_cprofile, (void) );
|
||||||
|
|
||||||
/* signal.c */
|
/* signal.c */
|
||||||
_PROTOTYPE( int do_alarm, (void) );
|
|
||||||
_PROTOTYPE( int do_kill, (void) );
|
_PROTOTYPE( int do_kill, (void) );
|
||||||
_PROTOTYPE( int ksig_pending, (void) );
|
_PROTOTYPE( int ksig_pending, (void) );
|
||||||
_PROTOTYPE( int do_pause, (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( int check_sig, (pid_t proc_id, int signo) );
|
||||||
_PROTOTYPE( void sig_proc, (struct mproc *rmp, int sig_nr) );
|
_PROTOTYPE( void sig_proc, (struct mproc *rmp, int sig_nr) );
|
||||||
_PROTOTYPE( int do_sigaction, (void) );
|
_PROTOTYPE( int do_sigaction, (void) );
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
* do_sigreturn: perform the SIGRETURN system call
|
* do_sigreturn: perform the SIGRETURN system call
|
||||||
* do_sigsuspend: perform the SIGSUSPEND system call
|
* do_sigsuspend: perform the SIGSUSPEND system call
|
||||||
* do_kill: perform the KILL 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
|
* do_pause: perform the PAUSE system call
|
||||||
* ksig_pending: the kernel notified about pending signals
|
* ksig_pending: the kernel notified about pending signals
|
||||||
* sig_proc: interrupt or terminate a signaled process
|
* sig_proc: interrupt or terminate a signaled process
|
||||||
|
@ -36,7 +34,6 @@
|
||||||
|
|
||||||
FORWARD _PROTOTYPE( void unpause, (int pro, int for_trace) );
|
FORWARD _PROTOTYPE( void unpause, (int pro, int for_trace) );
|
||||||
FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
|
FORWARD _PROTOTYPE( void handle_ksig, (int proc_nr, sigset_t sig_map) );
|
||||||
FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp) );
|
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* do_sigaction *
|
* 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 *
|
* do_pause *
|
||||||
*===========================================================================*/
|
*===========================================================================*/
|
||||||
|
|
|
@ -78,8 +78,7 @@ _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
||||||
no_sys, /* 61 = chroot */
|
no_sys, /* 61 = chroot */
|
||||||
do_getset, /* 62 = setsid */
|
do_getset, /* 62 = setsid */
|
||||||
do_getset, /* 63 = getpgrp */
|
do_getset, /* 63 = getpgrp */
|
||||||
|
do_itimer, /* 64 = itimer */
|
||||||
no_sys, /* 64 = unused */
|
|
||||||
no_sys, /* 65 = unused */
|
no_sys, /* 65 = unused */
|
||||||
no_sys, /* 66 = unused */
|
no_sys, /* 66 = unused */
|
||||||
no_sys, /* 67 = unused */
|
no_sys, /* 67 = unused */
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <minix/com.h>
|
#include <minix/com.h>
|
||||||
|
|
||||||
PRIVATE timer_t *pm_timers = NULL;
|
PRIVATE timer_t *pm_timers = NULL;
|
||||||
|
PRIVATE int pm_expiring = 0;
|
||||||
|
|
||||||
/*===========================================================================*
|
/*===========================================================================*
|
||||||
* pm_set_timer *
|
* 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);
|
prev_time = tmrs_settimer(&pm_timers,tp,now+ticks,watchdog,&next_time);
|
||||||
|
|
||||||
/* Reschedule our synchronous alarm if necessary. */
|
/* 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)
|
if (sys_setalarm(next_time, 1) != OK)
|
||||||
panic(__FILE__, "PM set timer couldn't set alarm.", NO_NUM);
|
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;
|
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);
|
tmrs_exptimers(&pm_timers, now, &next_time);
|
||||||
|
pm_expiring = 0;
|
||||||
|
|
||||||
|
/* Reschedule an alarm if necessary. */
|
||||||
if (next_time > 0) {
|
if (next_time > 0) {
|
||||||
if (sys_setalarm(next_time, 1) != OK)
|
if (sys_setalarm(next_time, 1) != OK)
|
||||||
panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
|
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
|
* the next timer, or cancel the alarm altogether if the last timer has
|
||||||
* been cancelled (next_time will be 0 then).
|
* 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)
|
if (sys_setalarm(next_time, 1) != OK)
|
||||||
panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
|
panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,8 +80,7 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
||||||
do_chroot, /* 61 = chroot */
|
do_chroot, /* 61 = chroot */
|
||||||
no_sys, /* 62 = (setsid) */
|
no_sys, /* 62 = (setsid) */
|
||||||
no_sys, /* 63 = (getpgrp) */
|
no_sys, /* 63 = (getpgrp) */
|
||||||
|
no_sys, /* 64 = (itimer) */
|
||||||
no_sys, /* 64 = unused */
|
|
||||||
no_sys, /* 65 = unused */
|
no_sys, /* 65 = unused */
|
||||||
no_sys, /* 66 = unused */
|
no_sys, /* 66 = unused */
|
||||||
no_sys, /* 67 = unused */
|
no_sys, /* 67 = unused */
|
||||||
|
@ -95,7 +94,6 @@ PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
|
||||||
no_sys, /* 75 = (sigreturn) */
|
no_sys, /* 75 = (sigreturn) */
|
||||||
no_sys, /* 76 = (reboot) */
|
no_sys, /* 76 = (reboot) */
|
||||||
do_svrctl, /* 77 = svrctl */
|
do_svrctl, /* 77 = svrctl */
|
||||||
|
|
||||||
no_sys, /* 78 = (sysuname) */
|
no_sys, /* 78 = (sysuname) */
|
||||||
do_getsysinfo, /* 79 = getsysinfo */
|
do_getsysinfo, /* 79 = getsysinfo */
|
||||||
do_getdents, /* 80 = getdents */
|
do_getdents, /* 80 = getdents */
|
||||||
|
|
Loading…
Reference in a new issue