Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kcc-4/lib/usys/alarm.c
There are 5 other files named alarm.c in the archive. Click here to see a list.
/* ALARM - Simulation of Unix alarm(2) system call.
**
** Copyright (c) 1987 by Ken Harrenstien, SRI International
**
** For T20 this uses the TIMER% JSYS.
** There is some inefficiency in that setting a new alarm after one has
** already gone off will attempt to flush the old alarm. This is the
** safest thing to do, however; there is no guarantee that a SIGALRM
** signal actually came from a TIMER% interrupt!
** But, being T20, things are worse than this. We cannot use
** absolute times because, for one thing, the TIMER% JSYS
** fails immediately (without deleting anything) if .TIMDD finds that
** the specified time is already past. But the clock queue may not have
** generated a PSI interrupt yet because it uses a different resolution
** (milliseconds) and a few thousand instructions can happen in each
** millisecond. This means that a TIMER% PSI can go off long after
** the call has failed to flush the request from the queue! Snarl!!!!!
** So, when we flush the request we use .TIMBF with a time 1 day
** in advance of the actual time we set. This zaps any other requests that
** the user may have made independently -- tough.
** Finally, we must use .TIMEL instead of .TIMDT so as to be absolutely
** sure that the TIMER% call which sets the time won't be screwed up
** because of some system delay between our GTAD% and TIMER% calls. Otherwise
** the GTAD% value we compute may already be past by the time TIMER% sees (and
** rejects) it. Sigh. We still remember our GTAD value so that alarm()
** return an approximately correct value for the # of seconds remaining.
*/
#include "c-env.h"
#include "signal.h"
#include "sys/usysig.h"
#include "errno.h"
#if SYS_T20
#include "jsys.h"
#endif
int
alarm(secs)
unsigned secs;
{
#if SYS_T20
extern int _chnalrm; /* PSI channel to use for TIMER% interrupt */
static int lastim = 0;
static int delerr, seterr; /* For debugging */
int remsec, curtim, acs[5];
extern void abort();
USYS_BEG();
if (_chnalrm == 0) { /* Ensure PSI system initialized */
signal(SIGALRM, abort); /* These calls leave PSI chan set up */
signal(SIGALRM, SIG_DFL); /* (activated but no handler) */
}
if (lastim == 0) { /* Is an alarm currently active? */
remsec = 0; /* No, just set return value zero */
if (secs) jsys(GTAD, acs); /* Get current time if will need it */
} else {
acs[1] = (_FHSLF<<18) | _TIMBF; /* Remove previous alarm requests */
acs[2] = lastim + (1<<18); /* for up to 1 day in advance! */
if (jsys(TIMER, acs) <= 0) { /* Remove it, ignore failure */
delerr = acs[0]; /* (has probably already gone off) */
}
jsys(GTAD, acs); /* Get current time */
if ((remsec = lastim - acs[1]) > 0) /* Determine time left */
remsec = (remsec * (24*60*60)) >> 18; /* Convert to secs */
else remsec = 0; /* Negative means probably went off */
lastim = 0; /* Say no currently pending alarm. */
}
/* remsec has time (in sec) that remained until last alarm. If user wants
** a new alarm, set it. Current time is in acs[1]; we add the # of
** seconds (in T20 GTAD form) to that number to get the new alarm time.
*/
if (secs) {
curtim = acs[1]; /* Remember current time */
acs[1] = (_FHSLF<<18) | _TIMEL; /* Use elapsed time in msec */
acs[2] = secs * 1000;
acs[3] = _chnalrm; /* Alarm PSI channel to use */
if (jsys(TIMER, acs) <= 0) {
seterr = acs[0];
USYS_RETERR(EINVAL); /* Not sure what else to do */
}
lastim = curtim + (secs << 18) / (24*60*60); /* Remember abs time */
}
USYS_RET(remsec);
#else
#error alarm() not supported for this system.
#endif
}