Support for setitimer(ITIMER_VIRTUAL/ITIMER_PROF). New test (41) for setitimer.
This commit is contained in:
parent
d82e260a90
commit
323f0abdd6
27 changed files with 772 additions and 32 deletions
|
@ -131,8 +131,8 @@ struct sig sigtab[] = {
|
|||
#ifdef SIGXFSZ
|
||||
SIGXFSZ, "XFSZ", NULL,
|
||||
#endif
|
||||
#ifdef SIGVTALARM
|
||||
SIGVTALARM, "VTALARM", "Virtual alarm",
|
||||
#ifdef SIGVTALRM
|
||||
SIGVTALRM, "VTALARM", "Virtual alarm",
|
||||
#endif
|
||||
#ifdef SIGPROF
|
||||
SIGPROF, "PROF", "Profiling alarm",
|
||||
|
|
|
@ -548,6 +548,8 @@ int sig;
|
|||
case SIGTTIN: return "ttin"; /* 21 */
|
||||
case SIGTTOU: return "ttou"; /* 22 */
|
||||
case SIGWINCH: return "winch"; /* 23 */
|
||||
case SIGVTALRM: return "vtalrm"; /* 24 */
|
||||
case SIGPROF: return "prof"; /* 25 */
|
||||
#ifdef __minix_vmd
|
||||
case SIGFPEMU: return "fpemu"; /* 30 */
|
||||
#endif
|
||||
|
|
|
@ -41,6 +41,8 @@ struct signames {
|
|||
#ifdef SIGWINCH
|
||||
{ "WINCH", SIGWINCH },
|
||||
#endif
|
||||
{ "VTALRM", SIGVTALRM },
|
||||
{ "PROF", SIGPROF },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
|
|
@ -328,7 +328,9 @@
|
|||
# define SYS_VMCTL (KERNEL_CALL + 43) /* sys_vmctl() */
|
||||
# define SYS_SYSCTL (KERNEL_CALL + 44) /* sys_sysctl() */
|
||||
|
||||
#define NR_SYS_CALLS 45 /* number of system calls */
|
||||
# define SYS_VTIMER (KERNEL_CALL + 45) /* sys_vtimer() */
|
||||
|
||||
#define NR_SYS_CALLS 46 /* number of system calls */
|
||||
|
||||
/* Pseudo call for use in kernel/table.c. */
|
||||
#define SYS_ALL_CALLS (NR_SYS_CALLS)
|
||||
|
@ -604,6 +606,14 @@
|
|||
#define VMCTL_INCSP 16
|
||||
#define VMCTL_NOPAGEZERO 18
|
||||
|
||||
/* Field names for SYS_VTIMER. */
|
||||
#define VT_WHICH m2_i1 /* which timer to set/retrieve */
|
||||
# define VT_VIRTUAL 1 /* the ITIMER_VIRTUAL timer */
|
||||
# define VT_PROF 2 /* the ITIMER_PROF timer */
|
||||
#define VT_SET m2_i2 /* 1 for setting a timer, 0 retrieval only */
|
||||
#define VT_VALUE m2_l1 /* new/previous value of the timer */
|
||||
#define VT_ENDPT m2_l2 /* process to set/retrieve the timer for */
|
||||
|
||||
/*===========================================================================*
|
||||
* Messages for the Reincarnation Server *
|
||||
*===========================================================================*/
|
||||
|
|
|
@ -86,10 +86,14 @@ _PROTOTYPE(void *alloc_contig, (size_t len, int flags, phys_bytes *phys));
|
|||
#define AC_LOWER16M 0x02
|
||||
#define AC_ALIGN64K 0x04
|
||||
|
||||
/* Clock functionality: get system times or (un)schedule an alarm call. */
|
||||
/* Clock functionality: get system times, (un)schedule an alarm call, or
|
||||
* retrieve/set a process-virtual timer.
|
||||
*/
|
||||
_PROTOTYPE( int sys_times, (endpoint_t proc_nr, clock_t *user_time,
|
||||
clock_t *sys_time, clock_t *uptime));
|
||||
_PROTOTYPE(int sys_setalarm, (clock_t exp_time, int abs_time));
|
||||
_PROTOTYPE( int sys_vtimer, (endpoint_t proc_nr, int which, clock_t *newval,
|
||||
clock_t *oldval));
|
||||
|
||||
/* Shorthands for sys_irqctl() system call. */
|
||||
#define sys_irqdisable(hook_id) \
|
||||
|
|
|
@ -44,6 +44,8 @@ typedef unsigned long sigset_t;
|
|||
#define SIGEMT 16 /* EMT instruction */
|
||||
#define SIGCHLD 17 /* child process terminated or stopped */
|
||||
#define SIGWINCH 21 /* window size has changed */
|
||||
#define SIGVTALRM 24 /* virtual alarm */
|
||||
#define SIGPROF 25 /* profiler alarm */
|
||||
|
||||
/* POSIX requires the following signals to be defined, even if they are
|
||||
* not supported. Here are the definitions, but they are not supported.
|
||||
|
@ -54,7 +56,7 @@ typedef unsigned long sigset_t;
|
|||
#define SIGTTIN 22 /* background process wants to read */
|
||||
#define SIGTTOU 23 /* background process wants to write */
|
||||
|
||||
#define _NSIG 24 /* highest signal number plus one */
|
||||
#define _NSIG 26 /* highest signal number plus one */
|
||||
|
||||
#ifdef _MINIX
|
||||
#define SIGIOT SIGABRT /* for people who speak PDP-11 */
|
||||
|
|
|
@ -96,6 +96,8 @@ PUBLIC void clock_task()
|
|||
PRIVATE void do_clocktick(m_ptr)
|
||||
message *m_ptr; /* pointer to request message */
|
||||
{
|
||||
register struct proc *bill_copy = bill_ptr;
|
||||
|
||||
/* Despite its name, this routine is not called on every clock tick. It
|
||||
* is called on those clock ticks when a lot of work needs to be done.
|
||||
*/
|
||||
|
@ -120,6 +122,18 @@ message *m_ptr; /* pointer to request message */
|
|||
}
|
||||
}
|
||||
|
||||
/* Check if a process-virtual timer expired. Check prev_ptr, but also
|
||||
* bill_ptr - one process's user time is another's system time, and the
|
||||
* profile timer decreases for both! Do this before the queue operations
|
||||
* below, which may alter bill_ptr. Note the use a copy of bill_ptr, because
|
||||
* bill_ptr may have been changed above, and this code can't be put higher
|
||||
* up because otherwise cause_sig() may dequeue prev_ptr before we do.
|
||||
*/
|
||||
vtimer_check(prev_ptr);
|
||||
|
||||
if (prev_ptr != bill_copy)
|
||||
vtimer_check(bill_copy);
|
||||
|
||||
/* Check if a clock timer expired and run its watchdog function. */
|
||||
if (next_timeout <= realtime) {
|
||||
tmrs_exptimers(&clock_timers, realtime, NULL);
|
||||
|
@ -180,11 +194,13 @@ irq_hook_t *hook;
|
|||
* realtime:
|
||||
* The current uptime is incremented with all outstanding ticks.
|
||||
* proc_ptr, bill_ptr:
|
||||
* These are used for accounting. It does not matter if proc.c
|
||||
* is changing them, provided they are always valid pointers,
|
||||
* since at worst the previous process would be billed.
|
||||
* These are used for accounting and virtual timers. It does not
|
||||
* matter if proc.c is changing them, provided they are always
|
||||
* valid pointers, since at worst the previous process would be
|
||||
* billed.
|
||||
*/
|
||||
register unsigned ticks;
|
||||
register int expired;
|
||||
|
||||
if(minix_panicing) return;
|
||||
|
||||
|
@ -208,6 +224,20 @@ irq_hook_t *hook;
|
|||
bill_ptr->p_ticks_left -= ticks;
|
||||
}
|
||||
|
||||
/* Decrement virtual timers, if applicable. We decrement both the virtual
|
||||
* and the profile timer of the current process, and if the current process
|
||||
* is not billable, the timer of the billed process as well.
|
||||
* If any of the timers expire, do_clocktick() will send out signals.
|
||||
*/
|
||||
expired = 0;
|
||||
if ((proc_ptr->p_misc_flags & VIRT_TIMER) &&
|
||||
(proc_ptr->p_virt_left -= ticks) <= 0) expired = 1;
|
||||
if ((proc_ptr->p_misc_flags & PROF_TIMER) &&
|
||||
(proc_ptr->p_prof_left -= ticks) <= 0) expired = 1;
|
||||
if (! (priv(proc_ptr)->s_flags & BILLABLE) &&
|
||||
(bill_ptr->p_misc_flags & PROF_TIMER) &&
|
||||
(bill_ptr->p_prof_left -= ticks) <= 0) expired = 1;
|
||||
|
||||
#if 0
|
||||
/* Update load average. */
|
||||
load_update();
|
||||
|
@ -216,7 +246,7 @@ irq_hook_t *hook;
|
|||
/* Check if do_clocktick() must be called. Done for alarms and scheduling.
|
||||
* Some processes, such as the kernel tasks, cannot be preempted.
|
||||
*/
|
||||
if ((next_timeout <= realtime) || (proc_ptr->p_ticks_left <= 0)) {
|
||||
if ((next_timeout <= realtime) || (proc_ptr->p_ticks_left <= 0) || expired) {
|
||||
prev_ptr = proc_ptr; /* store running process */
|
||||
lock_notify(HARDWARE, CLOCK); /* send notification */
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#define USE_GETINFO 1 /* retrieve a copy of kernel data */
|
||||
#define USE_TIMES 1 /* get process and system time info */
|
||||
#define USE_SETALARM 1 /* schedule a synchronous alarm */
|
||||
#define USE_VTIMER 1 /* set or retrieve a process-virtual timer */
|
||||
#define USE_DEVIO 1 /* read or write a single I/O port */
|
||||
#define USE_VDEVIO 1 /* process vector with I/O requests */
|
||||
#define USE_SDEVIO 1 /* perform I/O request on a buffer */
|
||||
|
|
|
@ -33,6 +33,9 @@ struct proc {
|
|||
clock_t p_user_time; /* user time in ticks */
|
||||
clock_t p_sys_time; /* sys time in ticks */
|
||||
|
||||
clock_t p_virt_left; /* number of ticks left on virtual timer */
|
||||
clock_t p_prof_left; /* number of ticks left on profile timer */
|
||||
|
||||
struct proc *p_nextready; /* pointer to next ready process */
|
||||
struct proc *p_caller_q; /* head of list of procs wishing to send */
|
||||
struct proc *p_q_link; /* link to next proc wishing to send */
|
||||
|
@ -169,6 +172,8 @@ struct proc {
|
|||
|
||||
/* Misc flags */
|
||||
#define REPLY_PENDING 0x01 /* reply to IPC_REQUEST is pending */
|
||||
#define VIRT_TIMER 0x02 /* process-virtual timer is running */
|
||||
#define PROF_TIMER 0x04 /* process-virtual profile timer is running */
|
||||
#define MF_VM 0x08 /* process uses VM */
|
||||
#define MF_ASYNMSG 0x10 /* Asynchrous message pending */
|
||||
#define MF_FULLVM 0x20
|
||||
|
|
|
@ -70,10 +70,12 @@ _PROTOTYPE( void clear_endpoint, (struct proc *rc) );
|
|||
_PROTOTYPE( phys_bytes umap_bios, (vir_bytes vir_addr, vir_bytes bytes));
|
||||
_PROTOTYPE( phys_bytes umap_verify_grant, (struct proc *rp, endpoint_t grantee, cp_grant_id_t grant, vir_bytes offset, vir_bytes bytes, int access));
|
||||
|
||||
|
||||
/* system/do_newmap.c */
|
||||
_PROTOTYPE( int newmap, (struct proc *rp, struct mem_map *map_ptr) );
|
||||
|
||||
/* system/do_vtimer.c */
|
||||
_PROTOTYPE( void vtimer_check, (struct proc *rp) );
|
||||
|
||||
/* interrupt.c */
|
||||
_PROTOTYPE( void intr_handle, (irq_hook_t *hook) );
|
||||
_PROTOTYPE( void put_irq_handler, (irq_hook_t *hook, int irq,
|
||||
|
|
|
@ -239,6 +239,7 @@ PRIVATE void initialize(void)
|
|||
map(SYS_TIMES, do_times); /* get uptime and process times */
|
||||
map(SYS_SETALARM, do_setalarm); /* schedule a synchronous alarm */
|
||||
map(SYS_STIME, do_stime); /* set the boottime */
|
||||
map(SYS_VTIMER, do_vtimer); /* set or retrieve a virtual timer */
|
||||
|
||||
/* System control. */
|
||||
map(SYS_ABORT, do_abort); /* abort MINIX */
|
||||
|
|
|
@ -173,6 +173,11 @@ _PROTOTYPE( int do_setalarm, (message *m_ptr) );
|
|||
|
||||
_PROTOTYPE( int do_stime, (message *m_ptr) );
|
||||
|
||||
_PROTOTYPE( int do_vtimer, (message *m_ptr) );
|
||||
#if ! USE_VTIMER
|
||||
#define do_vtimer do_unused
|
||||
#endif
|
||||
|
||||
_PROTOTYPE( int do_safecopy, (message *m_ptr) );
|
||||
_PROTOTYPE( int do_vsafecopy, (message *m_ptr) );
|
||||
_PROTOTYPE( int do_iopenable, (message *m_ptr) );
|
||||
|
|
|
@ -32,6 +32,7 @@ OBJECTS = \
|
|||
$(SYSTEM)(do_times.o) \
|
||||
$(SYSTEM)(do_setalarm.o) \
|
||||
$(SYSTEM)(do_stime.o) \
|
||||
$(SYSTEM)(do_vtimer.o) \
|
||||
$(SYSTEM)(do_irqctl.o) \
|
||||
$(SYSTEM)(do_devio.o) \
|
||||
$(SYSTEM)(do_vdevio.o) \
|
||||
|
@ -101,6 +102,9 @@ $(SYSTEM)(do_setalarm.o): do_setalarm.c
|
|||
$(SYSTEM)(do_stime.o): do_stime.c
|
||||
$(CC) do_stime.c
|
||||
|
||||
$(SYSTEM)(do_vtimer.o): do_vtimer.c
|
||||
$(CC) do_vtimer.c
|
||||
|
||||
$(SYSTEM)(do_irqctl.o): do_irqctl.c
|
||||
$(CC) do_irqctl.c
|
||||
|
||||
|
|
|
@ -57,6 +57,10 @@ register message *m_ptr; /* pointer to request message */
|
|||
|
||||
rpc->p_reg.psw &= ~TRACEBIT; /* clear trace bit */
|
||||
|
||||
rpc->p_misc_flags &= ~(VIRT_TIMER | PROF_TIMER);
|
||||
rpc->p_virt_left = 0; /* disable, clear the process-virtual timers */
|
||||
rpc->p_prof_left = 0;
|
||||
|
||||
/* Parent and child have to share the quantum that the forked process had,
|
||||
* so that queued processes do not have to wait longer because of the fork.
|
||||
* If the time left is odd, the child gets an extra tick.
|
||||
|
|
116
kernel/system/do_vtimer.c
Normal file
116
kernel/system/do_vtimer.c
Normal file
|
@ -0,0 +1,116 @@
|
|||
/* The kernel call implemented in this file:
|
||||
* m_type: SYS_VTIMER
|
||||
*
|
||||
* The parameters for this kernel call are:
|
||||
* m2_i1: VT_WHICH (the timer: VT_VIRTUAL or VT_PROF)
|
||||
* m2_i2: VT_SET (whether to set, or just retrieve)
|
||||
* m2_l1: VT_VALUE (new/old expiration time, in ticks)
|
||||
* m2_l2: VT_ENDPT (process to which the timer belongs)
|
||||
*/
|
||||
|
||||
#include "../system.h"
|
||||
|
||||
#include <signal.h>
|
||||
#include <minix/endpoint.h>
|
||||
|
||||
#if USE_VTIMER
|
||||
|
||||
/*===========================================================================*
|
||||
* do_vtimer *
|
||||
*===========================================================================*/
|
||||
PUBLIC int do_vtimer(m_ptr)
|
||||
message *m_ptr; /* pointer to request message */
|
||||
{
|
||||
/* Set and/or retrieve the value of one of a process' virtual timers. */
|
||||
struct proc *rrp; /* pointer to requesting process */
|
||||
struct proc *rp; /* pointer to process the timer belongs to */
|
||||
register int pt_flag; /* the misc on/off flag for the req.d timer */
|
||||
register clock_t *pt_left; /* pointer to the process' ticks-left field */
|
||||
clock_t old_value; /* the previous number of ticks left */
|
||||
int proc_nr, proc_nr_e;
|
||||
|
||||
/* The requesting process must be privileged. */
|
||||
rrp = proc_addr(who_p);
|
||||
if (! (priv(rrp)->s_flags & SYS_PROC)) return(EPERM);
|
||||
|
||||
if (m_ptr->VT_WHICH != VT_VIRTUAL && m_ptr->VT_WHICH != VT_PROF)
|
||||
return(EINVAL);
|
||||
|
||||
/* The target process must be valid. */
|
||||
proc_nr_e = (m_ptr->VT_ENDPT == SELF) ? m_ptr->m_source : m_ptr->VT_ENDPT;
|
||||
if (!isokendpt(proc_nr_e, &proc_nr)) return(EINVAL);
|
||||
rp = proc_addr(proc_nr);
|
||||
|
||||
/* Determine which flag and which field in the proc structure we want to
|
||||
* retrieve and/or modify. This saves us having to differentiate between
|
||||
* VT_VIRTUAL and VT_PROF multiple times below.
|
||||
*/
|
||||
if (m_ptr->VT_WHICH == VT_VIRTUAL) {
|
||||
pt_flag = VIRT_TIMER;
|
||||
pt_left = &rp->p_virt_left;
|
||||
} else { /* VT_PROF */
|
||||
pt_flag = PROF_TIMER;
|
||||
pt_left = &rp->p_prof_left;
|
||||
}
|
||||
|
||||
/* Retrieve the old value. */
|
||||
if (rp->p_misc_flags & pt_flag) {
|
||||
old_value = *pt_left;
|
||||
|
||||
if (old_value < 0) old_value = 0;
|
||||
} else {
|
||||
old_value = 0;
|
||||
}
|
||||
|
||||
/* Set the new value, if requested. This is called from the system task, so
|
||||
* we can be interrupted by the clock interrupt, but not by the clock task.
|
||||
* Therefore we only have to protect against interference from clock.c's
|
||||
* clock_handler(). We can do this without disabling interrupts, by removing
|
||||
* the timer's flag before changing the ticks-left field; in that case the
|
||||
* clock interrupt will not touch the latter anymore.
|
||||
*/
|
||||
if (m_ptr->VT_SET) {
|
||||
rp->p_misc_flags &= ~pt_flag; /* disable virtual timer */
|
||||
|
||||
if (m_ptr->VT_VALUE > 0) {
|
||||
*pt_left = m_ptr->VT_VALUE; /* set new timer value */
|
||||
rp->p_misc_flags |= pt_flag; /* (re)enable virtual timer */
|
||||
} else {
|
||||
*pt_left = 0; /* clear timer value */
|
||||
}
|
||||
}
|
||||
|
||||
m_ptr->VT_VALUE = old_value;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
#endif /* USE_VTIMER */
|
||||
|
||||
/*===========================================================================*
|
||||
* vtimer_check *
|
||||
*===========================================================================*/
|
||||
PUBLIC void vtimer_check(rp)
|
||||
struct proc *rp; /* pointer to the process */
|
||||
{
|
||||
/* This is called from the clock task, so we can be interrupted by the clock
|
||||
* interrupt, but not by the system task. Therefore we only have to protect
|
||||
* against interference from the clock handler. We can safely perform the
|
||||
* following actions without locking as well though, as the clock handler
|
||||
* never alters p_misc_flags, and only decreases p_virt_left/p_prof_left.
|
||||
*/
|
||||
|
||||
/* Check if the virtual timer expired. If so, send a SIGVTALRM signal. */
|
||||
if ((rp->p_misc_flags & VIRT_TIMER) && rp->p_virt_left <= 0) {
|
||||
rp->p_misc_flags &= ~VIRT_TIMER;
|
||||
rp->p_virt_left = 0;
|
||||
cause_sig(rp->p_nr, SIGVTALRM);
|
||||
}
|
||||
|
||||
/* Check if the profile timer expired. If so, send a SIGPROF signal. */
|
||||
if ((rp->p_misc_flags & PROF_TIMER) && rp->p_prof_left <= 0) {
|
||||
rp->p_misc_flags &= ~PROF_TIMER;
|
||||
rp->p_prof_left = 0;
|
||||
cause_sig(rp->p_nr, SIGPROF);
|
||||
}
|
||||
}
|
|
@ -71,6 +71,7 @@ libsys_FILES=" \
|
|||
sys_voutb.c \
|
||||
sys_voutl.c \
|
||||
sys_voutw.c \
|
||||
sys_vtimer.c \
|
||||
taskcall.c \
|
||||
ds.c \
|
||||
vm_allocmem.c \
|
||||
|
|
28
lib/syslib/sys_vtimer.c
Normal file
28
lib/syslib/sys_vtimer.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include "syslib.h"
|
||||
|
||||
PUBLIC int sys_vtimer(proc, which, newval, oldval)
|
||||
endpoint_t proc; /* proc to retrieve/set the timer for */
|
||||
int which; /* timer to retrieve/set */
|
||||
clock_t *newval; /* if non-NULL, set to this new value */
|
||||
clock_t *oldval; /* if non-NULL, old value is stored here */
|
||||
{
|
||||
message m;
|
||||
int r;
|
||||
|
||||
m.VT_ENDPT = proc;
|
||||
m.VT_WHICH = which;
|
||||
if (newval != NULL) {
|
||||
m.VT_SET = 1;
|
||||
m.VT_VALUE = *newval;
|
||||
} else {
|
||||
m.VT_SET = 0;
|
||||
}
|
||||
|
||||
r = _taskcall(SYSTASK, SYS_VTIMER, &m);
|
||||
|
||||
if (oldval != NULL) {
|
||||
*oldval = m.VT_VALUE;
|
||||
}
|
||||
|
||||
return(r);
|
||||
}
|
|
@ -32,10 +32,14 @@ A timer that is decremented in realtime. When it expires, a
|
|||
signal is delivered to the process.
|
||||
.TP
|
||||
.B ITIMER_VIRTUAL
|
||||
Not supported on Minix.
|
||||
A timer that is decremented in process user time. When it expires, a
|
||||
.BR SIGVTALRM
|
||||
signal is delivered to the process.
|
||||
.TP
|
||||
.B ITIMER_PROF
|
||||
Not supported on Minix.
|
||||
A timer that is decremented in process user+system time. When it expires, a
|
||||
.BR SIGPROF
|
||||
signal is delivered to the process.
|
||||
.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
|
||||
|
@ -58,9 +62,6 @@ Either \fIwhich\fP is not one of the ITIMER_* constants above, or one of the tim
|
|||
.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
|
||||
|
|
|
@ -148,6 +148,8 @@ SIGTSTP 20 ps Interactive stop signal
|
|||
SIGTTIN 21 ps Background read
|
||||
SIGTTOU 22 ps Background write
|
||||
SIGWINCH 23 xvi Window size change
|
||||
SIGVTALRM 24 xk Virtual alarm clock
|
||||
SIGPROF 25 xk Profiler alarm clock
|
||||
.ft R
|
||||
.fi
|
||||
.PP
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* 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
|
||||
* check_vtimer: check if one of the virtual timers needs to be restarted
|
||||
*/
|
||||
|
||||
#include "pm.h"
|
||||
|
@ -22,6 +23,8 @@ 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 getset_vtimer, (struct mproc *mp, int nwhich,
|
||||
struct itimerval *value, struct itimerval *ovalue) );
|
||||
FORWARD _PROTOTYPE( void get_realtimer, (struct mproc *mp,
|
||||
struct itimerval *value) );
|
||||
FORWARD _PROTOTYPE( void set_realtimer, (struct mproc *mp,
|
||||
|
@ -98,7 +101,7 @@ PUBLIC int do_itimer()
|
|||
int r;
|
||||
|
||||
/* Make sure 'which' is one of the defined timers. */
|
||||
if (m_in.which_timer < ITIMER_REAL || m_in.which_timer > ITIMER_PROF)
|
||||
if (m_in.which_timer < 0 || m_in.which_timer >= NR_ITIMERS)
|
||||
return(EINVAL);
|
||||
|
||||
/* Determine whether to set and/or return the given timer value, based on
|
||||
|
@ -134,8 +137,11 @@ PUBLIC int do_itimer()
|
|||
|
||||
case ITIMER_VIRTUAL :
|
||||
case ITIMER_PROF :
|
||||
/* Not implemented. */
|
||||
r = ENOSYS;
|
||||
getset_vtimer(mp, m_in.which_timer,
|
||||
(setval) ? &value : NULL,
|
||||
(getval) ? &ovalue : NULL);
|
||||
|
||||
r = OK;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -172,6 +178,97 @@ PUBLIC int do_alarm()
|
|||
return(remaining);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* getset_vtimer *
|
||||
*===========================================================================*/
|
||||
PRIVATE void getset_vtimer(rmp, which, value, ovalue)
|
||||
struct mproc *rmp;
|
||||
int which;
|
||||
struct itimerval *value;
|
||||
struct itimerval *ovalue;
|
||||
{
|
||||
clock_t newticks, *nptr; /* the new timer value, in ticks */
|
||||
clock_t oldticks, *optr; /* the old ticks value, in ticks */
|
||||
int r, num;
|
||||
|
||||
/* The default is to provide sys_vtimer with two null pointers, i.e. to do
|
||||
* nothing at all.
|
||||
*/
|
||||
optr = nptr = NULL;
|
||||
|
||||
/* If the old timer value is to be retrieved, have 'optr' point to the
|
||||
* location where the old value is to be stored, and copy the interval.
|
||||
*/
|
||||
if (ovalue != NULL) {
|
||||
optr = &oldticks;
|
||||
|
||||
timeval_from_ticks(&ovalue->it_interval, rmp->mp_interval[which]);
|
||||
}
|
||||
|
||||
/* If a new timer value is to be set, store the new timer value and have
|
||||
* 'nptr' point to it. Also, store the new interval.
|
||||
*/
|
||||
if (value != NULL) {
|
||||
newticks = ticks_from_timeval(&value->it_value);
|
||||
nptr = &newticks;
|
||||
|
||||
/* If no timer is set, the interval must be zero. */
|
||||
if (newticks <= 0)
|
||||
rmp->mp_interval[which] = 0;
|
||||
else
|
||||
rmp->mp_interval[which] =
|
||||
ticks_from_timeval(&value->it_interval);
|
||||
}
|
||||
|
||||
/* Find out which kernel timer number to use. */
|
||||
switch (which) {
|
||||
case ITIMER_VIRTUAL: num = VT_VIRTUAL; break;
|
||||
case ITIMER_PROF: num = VT_PROF; break;
|
||||
default: panic(__FILE__, "invalid vtimer type", which);
|
||||
}
|
||||
|
||||
/* Make the kernel call. If requested, also retrieve and store
|
||||
* the old timer value.
|
||||
*/
|
||||
if ((r = sys_vtimer(rmp->mp_endpoint, num, nptr, optr)) != OK)
|
||||
panic(__FILE__, "sys_vtimer failed", r);
|
||||
|
||||
if (ovalue != NULL) {
|
||||
/* If the alarm expired already, we should take into account the
|
||||
* interval. Return zero only if the interval is zero as well.
|
||||
*/
|
||||
if (oldticks <= 0) oldticks = rmp->mp_interval[which];
|
||||
|
||||
timeval_from_ticks(&ovalue->it_value, oldticks);
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* check_vtimer *
|
||||
*===========================================================================*/
|
||||
PUBLIC void check_vtimer(proc_nr, sig)
|
||||
int proc_nr;
|
||||
int sig;
|
||||
{
|
||||
register struct mproc *rmp;
|
||||
int which, num;
|
||||
|
||||
rmp = &mproc[proc_nr];
|
||||
|
||||
/* Translate back the given signal to a timer type and kernel number. */
|
||||
switch (sig) {
|
||||
case SIGVTALRM: which = ITIMER_VIRTUAL; num = VT_VIRTUAL; break;
|
||||
case SIGPROF: which = ITIMER_PROF; num = VT_PROF; break;
|
||||
default: panic(__FILE__, "invalid vtimer signal", sig);
|
||||
}
|
||||
|
||||
/* If a repetition interval was set for this virtual timer, tell the
|
||||
* kernel to set a new timeout for the virtual timer.
|
||||
*/
|
||||
if (rmp->mp_interval[which] > 0)
|
||||
sys_vtimer(rmp->mp_endpoint, num, &rmp->mp_interval[which], NULL);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
* get_realtimer *
|
||||
*===========================================================================*/
|
||||
|
@ -195,7 +292,7 @@ struct itimerval *value;
|
|||
/* 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;
|
||||
if (remaining <= 0) remaining = rmp->mp_interval[ITIMER_REAL];
|
||||
} else {
|
||||
remaining = 0;
|
||||
}
|
||||
|
@ -204,7 +301,7 @@ struct itimerval *value;
|
|||
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);
|
||||
timeval_from_ticks(&value->it_interval, rmp->mp_interval[ITIMER_REAL]);
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -226,7 +323,7 @@ struct itimerval *value;
|
|||
|
||||
/* Apply these values. */
|
||||
set_alarm(rmp, ticks);
|
||||
rmp->mp_interval = interval;
|
||||
rmp->mp_interval[ITIMER_REAL] = interval;
|
||||
}
|
||||
|
||||
/*===========================================================================*
|
||||
|
@ -270,8 +367,8 @@ struct timer *tp;
|
|||
* 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);
|
||||
if (rmp->mp_interval[ITIMER_REAL] > 0)
|
||||
set_alarm(rmp, rmp->mp_interval[ITIMER_REAL]);
|
||||
else rmp->mp_flags &= ~ALARM_ON;
|
||||
|
||||
check_sig(rmp->mp_pid, SIGALRM);
|
||||
|
|
|
@ -12,3 +12,4 @@
|
|||
|
||||
#define MAX_SECS (((1<<(sizeof(clock_t)*8-1))-1)/system_hz)
|
||||
/* max.secs for setitimer() ((2^31-1)/HZ) */
|
||||
#define NR_ITIMERS 3 /* number of supported interval timers */
|
||||
|
|
|
@ -41,7 +41,7 @@ PUBLIC int do_fork()
|
|||
register struct mproc *rmc; /* pointer to child */
|
||||
pid_t new_pid;
|
||||
static int next_child;
|
||||
int n = 0, r, s;
|
||||
int i, n = 0, r, s;
|
||||
endpoint_t child_ep;
|
||||
|
||||
/* If tables might fill up during FORK, don't even start since recovery half
|
||||
|
@ -86,7 +86,8 @@ 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 */
|
||||
for (i = 0; i < NR_ITIMERS; i++)
|
||||
rmc->mp_interval[i] = 0; /* reset timer intervals */
|
||||
|
||||
/* Find a free pid for the child and put it in the table. */
|
||||
new_pid = get_free_pid();
|
||||
|
@ -115,7 +116,7 @@ PUBLIC int do_fork_nb()
|
|||
int s;
|
||||
pid_t new_pid;
|
||||
static int next_child;
|
||||
int n = 0, r;
|
||||
int i, n = 0, r;
|
||||
endpoint_t child_ep;
|
||||
|
||||
/* Only system processes are allowed to use fork_nb */
|
||||
|
@ -159,6 +160,8 @@ PUBLIC int do_fork_nb()
|
|||
rmc->mp_child_utime = 0; /* reset administration */
|
||||
rmc->mp_child_stime = 0; /* reset administration */
|
||||
rmc->mp_endpoint = child_ep; /* passed back by VM */
|
||||
for (i = 0; i < NR_ITIMERS; i++)
|
||||
rmc->mp_interval[i] = 0; /* reset timer intervals */
|
||||
|
||||
/* Find a free pid for the child and put it in the table. */
|
||||
new_pid = get_free_pid();
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <timers.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "const.h"
|
||||
|
||||
EXTERN struct mproc {
|
||||
char mp_exitstatus; /* storage for status when process exits */
|
||||
char mp_sigstatus; /* storage for signal # for killed procs */
|
||||
|
@ -39,7 +41,7 @@ EXTERN struct mproc {
|
|||
* PM_UNPAUSE request is delivered.
|
||||
*/
|
||||
struct timer mp_timer; /* watchdog timer for alarm(2), setitimer(2) */
|
||||
clock_t mp_interval; /* repetition interval for setitimer(2) */
|
||||
clock_t mp_interval[NR_ITIMERS]; /* setitimer(2) repetition intervals */
|
||||
|
||||
unsigned mp_flags; /* flag bits */
|
||||
vir_bytes mp_procargs; /* ptr to proc's initial stack arguments */
|
||||
|
|
|
@ -11,6 +11,7 @@ struct memory;
|
|||
_PROTOTYPE( int do_alarm, (void) );
|
||||
_PROTOTYPE( int do_itimer, (void) );
|
||||
_PROTOTYPE( void set_alarm, (struct mproc *rmp, clock_t ticks) );
|
||||
_PROTOTYPE( void check_vtimer, (int proc_nr, int sig) );
|
||||
|
||||
/* break.c */
|
||||
_PROTOTYPE( int do_brk, (void) );
|
||||
|
|
|
@ -264,9 +264,10 @@ sigset_t sig_map;
|
|||
/* Check each bit in turn to see if a signal is to be sent. Unlike
|
||||
* kill(), the kernel may collect several unrelated signals for a
|
||||
* process and pass them to PM in one blow. Thus loop on the bit
|
||||
* map. For SIGINT, SIGWINCH and SIGQUIT, use proc_id 0 to indicate
|
||||
* a broadcast to the recipient's process group. For SIGKILL, use
|
||||
* proc_id -1 to indicate a systemwide broadcast.
|
||||
* map. For SIGVTALRM and SIGPROF, see if we need to restart a
|
||||
* virtual timer. For SIGINT, SIGWINCH and SIGQUIT, use proc_id 0
|
||||
* to indicate a broadcast to the recipient's process group. For
|
||||
* SIGKILL, use proc_id -1 to indicate a systemwide broadcast.
|
||||
*/
|
||||
for (i = 1; i <= _NSIG; i++) {
|
||||
if (!sigismember(&sig_map, i)) continue;
|
||||
|
@ -279,6 +280,10 @@ sigset_t sig_map;
|
|||
case SIGQUIT:
|
||||
case SIGWINCH:
|
||||
id = 0; break; /* broadcast to process group */
|
||||
case SIGVTALRM:
|
||||
case SIGPROF:
|
||||
check_vtimer(proc_nr, i);
|
||||
/* fall-through */
|
||||
default:
|
||||
id = proc_id;
|
||||
break;
|
||||
|
|
|
@ -7,7 +7,7 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
|||
test10 test12 test13 test14 test15 test16 test17 test18 test19 \
|
||||
test21 test22 test23 test25 test26 test27 test28 test29 \
|
||||
test30 test31 test32 test34 test35 test36 test37 test38 \
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41
|
||||
|
||||
BIGOBJ= test20 test24
|
||||
ROOTOBJ= test11 test33
|
||||
|
@ -28,7 +28,8 @@ $(ROOTOBJ):
|
|||
|
||||
clean:
|
||||
cd select && make clean
|
||||
-rm -rf *.o *.s *.bak test? test?? t10a t11a t11b t40a t40b t40c t40d t40e t40f DIR*
|
||||
-rm -rf *.o *.s *.bak test? test?? t10a t11a t11b \
|
||||
t40a t40b t40c t40d t40e t40f DIR*
|
||||
|
||||
test1: test1.c
|
||||
test2: test2.c
|
||||
|
@ -79,3 +80,4 @@ t40c: t40c.c
|
|||
t40d: t40d.c
|
||||
t40e: t40e.c
|
||||
t40f: t40f.c
|
||||
test41: test41.c
|
||||
|
|
409
test/test41.c
Normal file
409
test/test41.c
Normal file
|
@ -0,0 +1,409 @@
|
|||
/* Tests for getitimer(2)/setitimer(2) - by D.C. van Moolenbroek */
|
||||
/* Warning: this test deals with (real and virtual) time, and, lacking a proper
|
||||
* point of reference, its correctness depends on circumstances like CPU speed
|
||||
* and system load. A succeeding test run says a lot - failure not so much. */
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <minix/config.h>
|
||||
#include <minix/sysinfo.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define ITERATIONS 3
|
||||
#define MAX_ERROR 4
|
||||
|
||||
/* we have to keep in mind the millisecond values are rounded up */
|
||||
#define UPPERUSEC(us) ((us)+(1000000/system_hz))
|
||||
#define EQUSEC(l,r) \
|
||||
((l) <= ((r) + (1000000/system_hz)) && (l) >= ((r) - (1000000/system_hz)))
|
||||
|
||||
#define FILLITIMER(it, vs, vu, is, iu) \
|
||||
(it).it_value.tv_sec = (vs); \
|
||||
(it).it_value.tv_usec = (vu); \
|
||||
(it).it_interval.tv_sec = (is); \
|
||||
(it).it_interval.tv_usec = (iu);
|
||||
|
||||
/* these two macros are not fully working for all possible values;
|
||||
* the tests only use values that the macros can deal with, though. */
|
||||
#define EQITIMER(it, vs, vu, is, iu) \
|
||||
((it).it_value.tv_sec == (vs) && EQUSEC((it).it_value.tv_usec,vu) && \
|
||||
(it).it_interval.tv_sec == (is) && (it).it_interval.tv_usec == (iu))
|
||||
|
||||
#define LEITIMER(it, vs, vu, is, iu) \
|
||||
((it).it_value.tv_sec > 0 && ((it).it_value.tv_sec < (vs) || \
|
||||
((it).it_value.tv_sec == (vs) && (it).it_value.tv_usec <= \
|
||||
UPPERUSEC(vu))) && \
|
||||
(it).it_interval.tv_sec == (is) && EQUSEC((it).it_interval.tv_usec,iu))
|
||||
|
||||
_PROTOTYPE(int main, (int argc, char **argv));
|
||||
_PROTOTYPE(void test, (int m, int t));
|
||||
_PROTOTYPE(void test_which, (void));
|
||||
_PROTOTYPE(void test_getset, (void));
|
||||
_PROTOTYPE(void test_neglarge, (void));
|
||||
_PROTOTYPE(void test_zero, (void));
|
||||
_PROTOTYPE(void test_timer, (void));
|
||||
_PROTOTYPE(void test_alarm, (void));
|
||||
_PROTOTYPE(void test_fork, (void));
|
||||
_PROTOTYPE(void test_exec, (void));
|
||||
_PROTOTYPE(int do_check, (void));
|
||||
_PROTOTYPE(void got_alarm, (int sig));
|
||||
_PROTOTYPE(void busy_wait, (int secs));
|
||||
_PROTOTYPE(void e, (int n));
|
||||
_PROTOTYPE(void quit, (void));
|
||||
|
||||
static char *executable;
|
||||
static int signals;
|
||||
static int timer;
|
||||
static int errct = 0, subtest;
|
||||
static long system_hz;
|
||||
|
||||
static int sigs[] = { SIGALRM, SIGVTALRM, SIGPROF };
|
||||
static const char *names[] = { "REAL", "VIRTUAL", "PROF" };
|
||||
|
||||
int main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i, m = 0xFFFF, n = 0xF;
|
||||
|
||||
getsysinfo_up(PM_PROC_NR, SIU_SYSTEMHZ, sizeof(system_hz), &system_hz);
|
||||
|
||||
if (strcmp(argv[0], "DO CHECK") == 0) {
|
||||
timer = atoi(argv[1]);
|
||||
|
||||
exit(do_check());
|
||||
}
|
||||
|
||||
printf("Test 41 ");
|
||||
fflush(stdout);
|
||||
|
||||
executable = argv[0];
|
||||
|
||||
if (argc >= 2) m = atoi(argv[1]);
|
||||
if (argc >= 3) n = atoi(argv[2]);
|
||||
|
||||
for (i = 0; i < ITERATIONS; i++) {
|
||||
if (n & 1) test(m, ITIMER_REAL);
|
||||
if (n & 2) test(m, ITIMER_VIRTUAL);
|
||||
if (n & 4) test(m, ITIMER_PROF);
|
||||
}
|
||||
|
||||
quit();
|
||||
return(-1); /* impossible */
|
||||
}
|
||||
|
||||
void test(m, t)
|
||||
int m;
|
||||
int t;
|
||||
{
|
||||
timer = t;
|
||||
|
||||
if (m & 0001) test_which();
|
||||
if (m & 0002) test_getset();
|
||||
if (m & 0004) test_neglarge();
|
||||
if (m & 0010) test_zero();
|
||||
if (m & 0020) test_timer();
|
||||
if (m & 0040) test_alarm();
|
||||
if (m & 0100) test_fork();
|
||||
if (m & 0200) test_exec();
|
||||
}
|
||||
|
||||
/* test invalid and unsupported 'which' values */
|
||||
void test_which()
|
||||
{
|
||||
struct itimerval it;
|
||||
|
||||
subtest = 0;
|
||||
|
||||
errno = 0; if (!getitimer(-1, &it) || errno != EINVAL) e(1);
|
||||
errno = 0; if ( getitimer(timer, &it) ) e(2);
|
||||
errno = 0; if (!getitimer( 3, &it) || errno != EINVAL) e(3);
|
||||
}
|
||||
|
||||
/* test if we get back what we set */
|
||||
void test_getset()
|
||||
{
|
||||
struct itimerval it, oit;
|
||||
|
||||
subtest = 1;
|
||||
|
||||
/* no alarm should be set initially */
|
||||
if (getitimer(timer, &it)) e(1);
|
||||
if (!EQITIMER(it, 0, 0, 0, 0)) e(2);
|
||||
|
||||
if (setitimer(timer, &it, &oit)) e(3);
|
||||
if (setitimer(timer, &oit, NULL)) e(4);
|
||||
if (!EQITIMER(oit, 0, 0, 0, 0)) e(5);
|
||||
|
||||
FILLITIMER(it, 123, 0, 456, 0);
|
||||
if (setitimer(timer, &it, NULL)) e(6);
|
||||
|
||||
FILLITIMER(it, 987, 0, 654, 0);
|
||||
if (setitimer(timer, &it, &oit)) e(7);
|
||||
if (!LEITIMER(oit, 123, 0, 456, 0)) e(8);
|
||||
|
||||
if (getitimer(timer, &oit)) e(9);
|
||||
if (!LEITIMER(oit, 987, 0, 654, 0)) e(10);
|
||||
|
||||
FILLITIMER(it, 0, 0, 0, 0);
|
||||
if (setitimer(timer, &it, &oit)) e(11);
|
||||
if (!LEITIMER(oit, 987, 0, 654, 0)) e(12);
|
||||
|
||||
if (getitimer(timer, &oit)) e(13);
|
||||
if (!EQITIMER(oit, 0, 0, 0, 0)) e(14);
|
||||
}
|
||||
|
||||
/* test negative/large values */
|
||||
void test_neglarge()
|
||||
{
|
||||
struct itimerval it;
|
||||
|
||||
subtest = 2;
|
||||
|
||||
FILLITIMER(it, 4, 0, 5, 0);
|
||||
if (setitimer(timer, &it, NULL)) e(1);
|
||||
|
||||
FILLITIMER(it, 1000000000, 0, 0, 0);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(2);
|
||||
|
||||
FILLITIMER(it, 0, 1000000, 0, 0);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(3);
|
||||
|
||||
FILLITIMER(it, 0, 0, 0, 1000000);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(4);
|
||||
|
||||
FILLITIMER(it, -1, 0, 0, 0);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(5);
|
||||
|
||||
FILLITIMER(it, 0, -1, 0, 0);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(6);
|
||||
|
||||
FILLITIMER(it, 0, 0, -1, 0);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(7);
|
||||
|
||||
FILLITIMER(it, 0, 0, 0, -1);
|
||||
if (!setitimer(timer, &it, NULL) || errno != EINVAL) e(8);
|
||||
|
||||
if (getitimer(timer, &it)) e(9);
|
||||
if (!LEITIMER(it, 4, 0, 5, 0)) e(10);
|
||||
}
|
||||
|
||||
/* setitimer with a zero timer has to set the interval to zero as well */
|
||||
void test_zero()
|
||||
{
|
||||
struct itimerval it;
|
||||
|
||||
subtest = 3;
|
||||
|
||||
it.it_value.tv_sec = 0;
|
||||
it.it_value.tv_usec = 0;
|
||||
it.it_interval.tv_sec = 1;
|
||||
it.it_interval.tv_usec = 1;
|
||||
|
||||
if (setitimer(timer, &it, NULL)) e(1);
|
||||
if (getitimer(timer, &it)) e(2);
|
||||
if (!EQITIMER(it, 0, 0, 0, 0)) e(3);
|
||||
}
|
||||
|
||||
/* test actual timer functioning */
|
||||
void test_timer()
|
||||
{
|
||||
struct itimerval it;
|
||||
|
||||
subtest = 4;
|
||||
|
||||
if (signal(sigs[timer], got_alarm) == SIG_ERR) e(1);
|
||||
|
||||
FILLITIMER(it, 0, 1, 0, 1);
|
||||
|
||||
if (setitimer(timer, &it, NULL)) e(2);
|
||||
|
||||
signals = 0;
|
||||
busy_wait(1);
|
||||
|
||||
FILLITIMER(it, 0, 0, 0, 0);
|
||||
if (setitimer(timer, &it, NULL)) e(3);
|
||||
|
||||
/* we don't know how many signals we'll actually get in practice,
|
||||
* so these checks more or less cover the extremes of the acceptable */
|
||||
if (signals < 2) e(4);
|
||||
if (signals > system_hz * 2) e(5);
|
||||
|
||||
/* only for REAL timer can we check against the clock */
|
||||
if (timer == ITIMER_REAL) {
|
||||
FILLITIMER(it, 1, 0, 0, 0);
|
||||
if (setitimer(timer, &it, NULL)) e(6);
|
||||
|
||||
signals = 0;
|
||||
busy_wait(1);
|
||||
|
||||
FILLITIMER(it, 0, 0, 0, 0);
|
||||
if (setitimer(timer, &it, NULL)) e(7);
|
||||
|
||||
if (signals != 1) e(8);
|
||||
}
|
||||
|
||||
signals = 0;
|
||||
busy_wait(1);
|
||||
|
||||
if (signals != 0) e(9);
|
||||
}
|
||||
|
||||
/* test itimer/alarm interaction */
|
||||
void test_alarm(void) {
|
||||
struct itimerval it;
|
||||
|
||||
/* only applicable for ITIMER_REAL */
|
||||
if (timer != ITIMER_REAL) return;
|
||||
|
||||
subtest = 5;
|
||||
|
||||
if (signal(SIGALRM, got_alarm) == SIG_ERR) e(1);
|
||||
|
||||
FILLITIMER(it, 3, 0, 1, 0);
|
||||
if (setitimer(timer, &it, NULL)) e(2);
|
||||
|
||||
if (alarm(2) != 3) e(3);
|
||||
|
||||
if (getitimer(timer, &it)) e(4);
|
||||
if (!LEITIMER(it, 2, 0, 0, 0)) e(5);
|
||||
|
||||
signals = 0;
|
||||
busy_wait(5);
|
||||
|
||||
if (signals != 1) e(6);
|
||||
|
||||
if (getitimer(timer, &it)) e(7);
|
||||
if (!EQITIMER(it, 0, 0, 0, 0)) e(8);
|
||||
}
|
||||
|
||||
/* test that the timer is reset on forking */
|
||||
void test_fork(void) {
|
||||
struct itimerval it, oit;
|
||||
pid_t pid;
|
||||
int status;
|
||||
|
||||
subtest = 6;
|
||||
|
||||
FILLITIMER(it, 12, 34, 56, 78);
|
||||
|
||||
if (setitimer(timer, &it, NULL)) e(1);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) e(2);
|
||||
|
||||
if (pid == 0) {
|
||||
if (getitimer(timer, &it)) exit(5);
|
||||
if (!EQITIMER(it, 0, 0, 0, 0)) exit(6);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (wait(&status) != pid) e(3);
|
||||
if (!WIFEXITED(status)) e(4);
|
||||
if (WEXITSTATUS(status) != 0) e(WEXITSTATUS(status));
|
||||
|
||||
FILLITIMER(it, 0, 0, 0, 0);
|
||||
if (setitimer(timer, &it, &oit)) e(7);
|
||||
if (!LEITIMER(oit, 12, 34, 56, 78)) e(8);
|
||||
}
|
||||
|
||||
/* test if timer is carried over to exec()'ed process */
|
||||
void test_exec(void) {
|
||||
struct itimerval it;
|
||||
pid_t pid;
|
||||
int status;
|
||||
char buf[2];
|
||||
|
||||
subtest = 7;
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0) e(1);
|
||||
|
||||
if (pid == 0) {
|
||||
FILLITIMER(it, 3, 0, 1, 0);
|
||||
if (setitimer(timer, &it, NULL)) exit(2);
|
||||
|
||||
sprintf(buf, "%d", timer);
|
||||
execl(executable, "DO CHECK", buf, NULL);
|
||||
|
||||
exit(3);
|
||||
}
|
||||
|
||||
if (wait(&status) != pid) e(4);
|
||||
if (WIFSIGNALED(status)) {
|
||||
/* process should have died from corresponding signal */
|
||||
if (WTERMSIG(status) != sigs[timer]) e(5);
|
||||
}
|
||||
else {
|
||||
if (WIFEXITED(status)) e(WEXITSTATUS(status));
|
||||
else e(6);
|
||||
}
|
||||
}
|
||||
|
||||
/* procedure of the exec()'ed process */
|
||||
int do_check()
|
||||
{
|
||||
struct itimerval it;
|
||||
|
||||
if (getitimer(timer, &it)) return(81);
|
||||
if (!LEITIMER(it, 3, 0, 1, 0)) return(82);
|
||||
|
||||
busy_wait(60);
|
||||
|
||||
return(83);
|
||||
}
|
||||
|
||||
void busy_wait(secs)
|
||||
int secs;
|
||||
{
|
||||
time_t now, exp;
|
||||
int i;
|
||||
|
||||
exp = time(&now) + secs + 1;
|
||||
|
||||
while (now < exp) {
|
||||
for (i = 0; i < 100000; i++);
|
||||
|
||||
time(&now);
|
||||
}
|
||||
}
|
||||
|
||||
void got_alarm(sig)
|
||||
int sig;
|
||||
{
|
||||
if (sig != sigs[timer]) e(1001);
|
||||
|
||||
signals++;
|
||||
}
|
||||
|
||||
void e(n)
|
||||
int n;
|
||||
{
|
||||
|
||||
printf("Timer %s, subtest %d, error %d, errno %d: %s\n",
|
||||
names[timer], subtest, n, errno, strerror(errno));
|
||||
|
||||
if (errct++ > MAX_ERROR) {
|
||||
printf("Too many errors; test aborted\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void quit()
|
||||
{
|
||||
|
||||
if (errct == 0) {
|
||||
printf("ok\n");
|
||||
exit(0);
|
||||
} else {
|
||||
printf("%d errors\n", errct);
|
||||
exit(1);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue