mirror of
https://github.com/Interlisp/maiko.git
synced 2026-01-17 00:22:59 +00:00
This removes SYSVSIGNALS as we're always and only using POSIX signals now. Some platform differences have been papered over. We used to only ignore SIGPIPE when using BSD signals, but we now ignore it all the time. While the SIGFPE code will now compile, it hasn't been updated to work on modern OSes fully yet as it will need to enable the correct FP exceptions.
883 lines
26 KiB
C
883 lines
26 KiB
C
/* $Id: timer.c,v 1.5 2001/12/26 22:17:05 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved */
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* t i m e r . c */
|
|
/* */
|
|
/* Timer handling routines, plus set-up for the other interrupts */
|
|
/* Medley uses on Unix. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* (C) Copyright 1989-99 Venue. All Rights Reserved. */
|
|
/* Manufactured in the United States of America. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
#include "version.h"
|
|
|
|
#include <fcntl.h>
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
|
|
#ifdef DOS
|
|
#include <dos.h>
|
|
#include <i32.h> /* "#pragma interrupt" & '_chain_intr'*/
|
|
/******************************************************************************
|
|
* Global variables
|
|
******************************************************************************/
|
|
void (*prev_int_1c)(); /* keeps address of previous 1c handlr*/
|
|
/* used for chaining & restore at exit*/
|
|
#pragma interrupt(DOStimer)
|
|
void DOStimer();
|
|
|
|
unsigned long tick_count = 0; /* approx 18 ticks per sec */
|
|
#else /* DOS */
|
|
#include <sys/resource.h>
|
|
#include <sys/time.h>
|
|
#endif /* DOS */
|
|
|
|
#ifdef USE_DLPI
|
|
#include <stropts.h>
|
|
extern int ether_fd;
|
|
#endif
|
|
|
|
#include "lispemul.h"
|
|
#include "emlglob.h"
|
|
#include "lspglob.h"
|
|
#include "adr68k.h"
|
|
#include "lsptypes.h"
|
|
#include "arith.h"
|
|
#include "lispmap.h"
|
|
#include "stack.h"
|
|
#include "dbprint.h"
|
|
|
|
#include "timerdefs.h"
|
|
#include "commondefs.h"
|
|
#include "mkcelldefs.h"
|
|
#include "keyeventdefs.h"
|
|
|
|
#ifdef XWINDOW
|
|
#include "devif.h"
|
|
extern DspInterface currentdsp;
|
|
#endif /* XWINDOW */
|
|
|
|
#define LISP_UNIX_TIME_DIFF 29969152
|
|
#define LISP_ALTO_TIME_MASK 0x80000000
|
|
#define UNIX_ALTO_TIME_DIFF 2177452800U
|
|
|
|
/* Interlisp time is signed; MIN.FIXP = "01-JAN-01 00:00:00 GMT"
|
|
* Interlisp 0 is at "19-Jan-69 12:14:08 PST"
|
|
* Unix begins at " 1-Jan-70 0:00:00 GMT"
|
|
* (CL:- (IL:IDATE " 1-Jan-70 0:00:00 GMT")
|
|
* (IL:IDATE "19-Jan-69 12:14:08 PST"))
|
|
* => 29969152, amount to add to Lisp time to get Unix time
|
|
* Alto time is unsigned; 0 = "01-JAN-01 00:00:00 GMT"
|
|
* UNIX_ALTO_TIME_DIFF is amount to add to Unix time
|
|
* to get Alto time.
|
|
*/
|
|
|
|
int TIMEOUT_TIME; /* For file system timeout */
|
|
|
|
#ifdef XWINDOW
|
|
#define FALSE 0
|
|
#define TRUE !FALSE
|
|
int Event_Req = FALSE;
|
|
#endif /* XWINDOW */
|
|
|
|
static int gettime(int casep);
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* u p d a t e _ m i s c s t a t s */
|
|
/* */
|
|
/* Updates counters and timers in the MISCSTATS "page". */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void update_miscstats() {
|
|
#ifdef DOS
|
|
struct dostime_t dtm; /* holds DOS time, so we can get .01 secs */
|
|
_dos_gettime(&dtm);
|
|
|
|
MiscStats->totaltime = (time(0) * 1000) + (10 * dtm.hsecond);
|
|
MiscStats->swapwaittime = 0;
|
|
MiscStats->pagefaults = 0;
|
|
MiscStats->swapwrites = 0;
|
|
MiscStats->diskiotime = 0; /* ?? not available ?? */
|
|
MiscStats->diskops = 0;
|
|
MiscStats->secondstmp = MiscStats->secondsclock = (time(0) + UNIX_ALTO_TIME_DIFF);
|
|
#else
|
|
struct timeval timev;
|
|
struct rusage ru;
|
|
|
|
getrusage(RUSAGE_SELF, &ru);
|
|
|
|
MiscStats->totaltime = ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000;
|
|
MiscStats->swapwaittime = ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000;
|
|
MiscStats->pagefaults = ru.ru_minflt + ru.ru_majflt;
|
|
MiscStats->swapwrites = ru.ru_majflt;
|
|
MiscStats->diskiotime = 0; /* ?? not available ?? */
|
|
MiscStats->diskops = ru.ru_inblock
|
|
/* ?? this doesn't work ???
|
|
+ ru.ru_outblock */
|
|
;
|
|
gettimeofday(&timev, NULL);
|
|
MiscStats->secondstmp = MiscStats->secondsclock = (timev.tv_sec + UNIX_ALTO_TIME_DIFF);
|
|
#endif /* DOS */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n i t _ m i s c s t a t s */
|
|
/* */
|
|
/* Called at initialization time to set miscstats words. */
|
|
/* ?? and to periodically update them ?? [JDS 11/22/89] */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void init_miscstats() {
|
|
MiscStats->starttime = gettime(0);
|
|
MiscStats->gctime = 0;
|
|
update_miscstats();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* s u b r _ g e t t i m e */
|
|
/* */
|
|
/* Handler for Lisps GETTIME subr call, dispatched thru */
|
|
/* subr.c/miscn.c sub-dispatch. */
|
|
/* */
|
|
/* Calls gettime, and returns the result to Lisp as a SMALLP */
|
|
/* or FIXP, as appropriate. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
DLword *createcell68k();
|
|
|
|
LispPTR subr_gettime(LispPTR args[])
|
|
{
|
|
int result;
|
|
result = gettime(args[0] & 0xffff);
|
|
if (args[1]) {
|
|
*((int *)Addr68k_from_LADDR(args[1])) = result;
|
|
return (args[1]);
|
|
} else
|
|
N_ARITH_SWITCH(result);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* g e t t i m e */
|
|
/* */
|
|
/* Get the value of one of the various time counters, as */
|
|
/* specified by the argument casep. casep's values & meanings: */
|
|
/* */
|
|
/* 0 elapsed time, in milliseconds. */
|
|
/* 1 start of elapsed-time period, in milliseconds */
|
|
/* 2 this process's run time, in milliseconds */
|
|
/* 3 total GC time, in milliseconds */
|
|
/* 4 current time-of-day, in ALTO format */
|
|
/* 5 current time-of-day, in Interlisp format */
|
|
/* 6 start of daylight-savings, as day-in-year */
|
|
/* 7 end of daylight-savings, as day-in-year */
|
|
/* 8 time zone, as hours of offset from GMT (whole hours only) */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
static int gettime(int casep)
|
|
{
|
|
#ifdef DOS
|
|
struct dostime_t dtm; /* for hundredths of secs */
|
|
#else
|
|
struct timeval timev;
|
|
#endif /* DOS */
|
|
switch (casep) {
|
|
case 0: /* elapsed time in alto milliseconds */
|
|
#ifdef DOS
|
|
_dos_gettime(&dtm);
|
|
return ((time(0) + UNIX_ALTO_TIME_DIFF) * 1000) + (10 * dtm.hsecond);
|
|
#else /* DOS */
|
|
gettimeofday(&timev, NULL);
|
|
return ((timev.tv_sec + UNIX_ALTO_TIME_DIFF) * 1000 + timev.tv_usec / 1000);
|
|
#endif /* DOS */
|
|
|
|
case 1: /* starting elapsed time in milliseconds */ return (MiscStats->starttime);
|
|
|
|
case 2: /* run time, this process, in milliseconds */
|
|
update_miscstats();
|
|
return (MiscStats->totaltime);
|
|
|
|
case 3: /* total GC time in milliseconds */ return (MiscStats->gctime);
|
|
|
|
case 4: /* current time of day in Alto format */
|
|
#ifdef DOS
|
|
return (time(0) + UNIX_ALTO_TIME_DIFF);
|
|
#else
|
|
gettimeofday(&timev, NULL);
|
|
return (timev.tv_sec + UNIX_ALTO_TIME_DIFF);
|
|
#endif
|
|
|
|
case 5: /* current time of day in Interlisp format */
|
|
#ifdef DOS
|
|
return (time(0) + LISP_UNIX_TIME_DIFF);
|
|
#else
|
|
gettimeofday(&timev, NULL);
|
|
return (timev.tv_sec + LISP_UNIX_TIME_DIFF);
|
|
#endif
|
|
|
|
case 6:
|
|
return (98); /* this is wrong, only works in PST */
|
|
|
|
case 7:
|
|
return (305); /* this is wrong, only works in PST */
|
|
|
|
case 8:
|
|
/* other methods of determining timezone offset are unreliable and/or deprecated */
|
|
/* timezone is declared in <time.h>; the time mechanisms must be initialized */
|
|
/* Unfortunately, FreeBSD does not support the timezone external variable, nor */
|
|
/* does gettimeofday() seem to produce the correct timezone values. */
|
|
tzset();
|
|
#if defined(FREEBSD)
|
|
time_t tv = time(NULL);
|
|
struct tm *tm = localtime(&tv);
|
|
return (tm->tm_gmtoff / -3600);
|
|
#else
|
|
return (timezone / 3600); /* timezone, extern, is #secs diff GMT to local. */
|
|
#endif
|
|
default: return (0);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* s u b r _ s e t t i m e */
|
|
/* */
|
|
/* Converts its argument, a time in ALTO seconds, to the */
|
|
/* UNIX time format, and sets the UNIX clock. You must be */
|
|
/* the super-user for this to work. */
|
|
/* */
|
|
/* Implements the SETTIME subr call, sub-dispatched from subr.c */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void subr_settime(LispPTR args[])
|
|
{
|
|
#ifdef DOS
|
|
struct dostime_t dostime;
|
|
struct dosdate_t dosday;
|
|
struct tm uxtime;
|
|
|
|
uxtime = *localtime((time_t *)(*((int *)Addr68k_from_LADDR(args[0])) - UNIX_ALTO_TIME_DIFF));
|
|
dostime.hsecond = 0;
|
|
dostime.second = uxtime.tm_sec;
|
|
dostime.minute = uxtime.tm_min;
|
|
dostime.hour = uxtime.tm_hour;
|
|
_dos_settime(&dostime);
|
|
|
|
dosday.day = uxtime.tm_mday;
|
|
dosday.month = uxtime.tm_mon;
|
|
dosday.year = uxtime.tm_year;
|
|
dosday.dayofweek = uxtime.tm_wday;
|
|
_dos_setdate(&dosday);
|
|
#else
|
|
struct timeval timev;
|
|
timev.tv_sec = *((int *)Addr68k_from_LADDR(args[0])) - UNIX_ALTO_TIME_DIFF;
|
|
timev.tv_usec = 0;
|
|
settimeofday(&timev, NULL);
|
|
#endif
|
|
} /* end subr_settime */
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* s u b r _ c o p y t i m e s t a t s */
|
|
/* */
|
|
/* Given source and destination MISCSTATS structure pointers, */
|
|
/* copy the contents of the source structure into the dest. */
|
|
/* */
|
|
/* Also calls update_miscstats, to keep stats current. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void subr_copytimestats(LispPTR args[])
|
|
{
|
|
MISCSTATS *source;
|
|
MISCSTATS *dest;
|
|
source = (MISCSTATS *)Addr68k_from_LADDR(args[0]);
|
|
dest = (MISCSTATS *)Addr68k_from_LADDR(args[1]);
|
|
update_miscstats();
|
|
*dest = *source;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* N _ O P _ r c l k */
|
|
/* */
|
|
/* Get the current time in UNIX format, convert it to micro- */
|
|
/* seconds in ALTO format, and store the low 32 bits into */
|
|
/* the FIXP cell passed in to us on the top of stack. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
LispPTR N_OP_rclk(LispPTR tos)
|
|
{
|
|
unsigned int usec;
|
|
#ifdef DOS
|
|
struct dostime_t dtm;
|
|
#endif /* DOS */
|
|
|
|
#ifdef DOS
|
|
_dos_gettime(&dtm);
|
|
usec = (time(0) * 1000000) + (10000 * dtm.hsecond);
|
|
#else
|
|
struct timeval timev;
|
|
|
|
gettimeofday(&timev, NULL);
|
|
usec = (timev.tv_sec * 1000000UL) + timev.tv_usec;
|
|
#endif /* DOS */
|
|
*((unsigned int *)(Addr68k_from_LADDR(tos))) = usec;
|
|
return (tos);
|
|
} /* end N_OP_rclk */
|
|
|
|
/**********************************************************************/
|
|
/* update_timer called periodically */
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void update_timer() {
|
|
#ifdef DOS
|
|
MiscStats->secondstmp = MiscStats->secondsclock = time(0) + UNIX_ALTO_TIME_DIFF;
|
|
#else
|
|
struct timeval timev;
|
|
gettimeofday(&timev, NIL);
|
|
MiscStats->secondstmp = MiscStats->secondsclock = (timev.tv_sec + UNIX_ALTO_TIME_DIFF);
|
|
#endif /* DOS */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
/**********************************************************************/
|
|
/* timer interrupt handling system
|
|
|
|
int_init() should be called before first entering dispatch loop.
|
|
int_timer_init() is called by int_init() and arms the timer interrupt.
|
|
int_io_init() is called by int_init() and arms the I/O interrupt.
|
|
int_timer_service() catches the timer signal and sets
|
|
Irq_Stk_Check & Irq_Stk_End to 0
|
|
so the rest of the system will see it and respond.
|
|
int_block() and int_unblock() block timer interrupts and release them.
|
|
int_io_open(fd) should be called whenever a file that should interrupt
|
|
us is opened; it enables the interrupt on that fd.
|
|
int_io_close(fd) should be called whenever a file that should interrupt
|
|
us is closed; it disables the interrupt on that fd.
|
|
*/
|
|
|
|
/* TIMER_INTERVAL usec ~ 20 per second. This should live in some
|
|
machine-configuration
|
|
file somewhere - it can be changed as the -t parameter to lisp*/
|
|
|
|
#ifdef sparc
|
|
int TIMER_INTERVAL = 100000;
|
|
#else
|
|
int TIMER_INTERVAL = 25000;
|
|
#endif
|
|
|
|
int FileIOFlag = 0;
|
|
int TimerFlag = 0;
|
|
extern int LispWindowFd;
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n t _ t i m e r _ s e r v i c e */
|
|
/* */
|
|
/* Handle the virtual-time alarm signal VTALRM. */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
static void int_timer_service(int sig)
|
|
{
|
|
/* this may have to do more in the future, like check for nested interrupts,
|
|
etc... */
|
|
|
|
Irq_Stk_Check = 0;
|
|
Irq_Stk_End = 0;
|
|
TimerFlag = 1;
|
|
|
|
#ifdef XWINDOW
|
|
Event_Req = TRUE;
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
static void int_timer_init()
|
|
|
|
{
|
|
#ifdef DOS
|
|
/******************************************************************************
|
|
* All code and data touched during the processing of an interrupt should
|
|
* locked prior to receiving any interrupts. This prevents the Timer
|
|
* function from being swapped out during an interrupt.
|
|
******************************************************************************/
|
|
_dpmi_lockregion((void *)TimerFlag, sizeof(TimerFlag));
|
|
_dpmi_lockregion((void *)Irq_Stk_End, sizeof(Irq_Stk_End));
|
|
_dpmi_lockregion((void *)Irq_Stk_Check, sizeof(Irq_Stk_Check));
|
|
_dpmi_lockregion((void *)tick_count, sizeof(tick_count));
|
|
_dpmi_lockregion((void *)&DOStimer, 4096);
|
|
_dpmi_lockregion((void *)prev_int_1c, sizeof(prev_int_1c));
|
|
|
|
/* Set up the DOS time handler. */
|
|
prev_int_1c = _dos_getvect(0x1c); /* get addr of currnt 1c hndlr, */
|
|
/* if any*/
|
|
_dos_setvect(0x1c, DOStimer); /* hook our int handler to timer int */
|
|
|
|
#else
|
|
struct itimerval timert, tmpt;
|
|
struct sigaction timer_action;
|
|
|
|
timer_action.sa_handler = int_timer_service;
|
|
sigemptyset(&timer_action.sa_mask);
|
|
timer_action.sa_flags = 0;
|
|
|
|
if (sigaction(SIGVTALRM, &timer_action, NULL) == -1) {
|
|
perror("sigaction: SIGVTALRM");
|
|
}
|
|
|
|
/* then attach a timer to it and turn it loose */
|
|
timert.it_interval.tv_sec = timert.it_value.tv_sec = 0;
|
|
timert.it_interval.tv_usec = timert.it_value.tv_usec = TIMER_INTERVAL;
|
|
|
|
timerclear(&tmpt.it_value);
|
|
timerclear(&tmpt.it_interval);
|
|
setitimer(ITIMER_VIRTUAL, &timert, &tmpt);
|
|
getitimer(ITIMER_VIRTUAL, &tmpt);
|
|
|
|
DBPRINT(("Timer interval set to %d usec\n", timert.it_value.tv_usec));
|
|
#endif /* DOS */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void int_io_open(int fd)
|
|
{
|
|
#ifdef DOS
|
|
/* would turn on DOS kbd signal handler here */
|
|
#elif KBINT
|
|
|
|
DBPRINT(("int_io_opening %d\n", fd));
|
|
if (fcntl(fd, F_SETOWN, getpid()) == -1) {
|
|
#ifdef DEBUG
|
|
perror("fcntl F_SETOWN ERROR");
|
|
#endif
|
|
};
|
|
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_ASYNC) == -1) perror("fcntl F_SETFL error");
|
|
#endif
|
|
}
|
|
|
|
void int_io_close(int fd)
|
|
{
|
|
#ifdef DOS
|
|
/* Turn off signaller here */
|
|
#elif KBINT
|
|
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_ASYNC);
|
|
#endif
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n t _ i o _ i n i t */
|
|
/* */
|
|
/* Set up handling for the SIGIO signals, in */
|
|
/* support of keyboard event handling and ethernet incoming- */
|
|
/* packet handling. */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
static void int_io_init() {
|
|
#ifndef DOS
|
|
struct sigaction io_action;
|
|
io_action.sa_handler = getsignaldata;
|
|
sigemptyset(&io_action.sa_mask);
|
|
io_action.sa_flags = 0;
|
|
|
|
if (sigaction(SIGIO, &io_action, NULL) == -1) {
|
|
perror("sigaction: SIGIO");
|
|
} else {
|
|
DBPRINT(("I/O interrupts enabled\n"));
|
|
}
|
|
|
|
#if defined(XWINDOW) && defined(I_SETSIG)
|
|
if (ioctl(ConnectionNumber(currentdsp->display_id), I_SETSIG, S_INPUT) < 0)
|
|
perror("ioctl on X fd - SETSIG for input handling failed");
|
|
#endif
|
|
|
|
#ifdef USE_DLPI
|
|
DBPRINT(("INIT ETHER: Doing I_SETSIG.\n"));
|
|
if (ether_fd > 0)
|
|
if (ioctl(ether_fd, I_SETSIG, S_INPUT) != 0) {
|
|
perror("init_ether: I_SETSIG failed:\n");
|
|
close(ether_fd);
|
|
ether_fd = -1;
|
|
return;
|
|
}
|
|
#endif /* USE_DLPI */
|
|
#endif /* DOS */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n t _ b l o c k */
|
|
/* */
|
|
/* Temporarily turn off interrupts. */
|
|
/* */
|
|
/* NOTE that these interrupts must also be turned off in ldeboot's */
|
|
/* forking code; if you change these, go fix that one too */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void int_block() {
|
|
/* temporarily turn off interrupts */
|
|
#ifdef DOS
|
|
_dos_setvect(0x1c, prev_int_1c);
|
|
#else /* DOS */
|
|
sigset_t signals;
|
|
sigemptyset(&signals);
|
|
sigaddset(&signals, SIGVTALRM);
|
|
sigaddset(&signals, SIGIO);
|
|
sigaddset(&signals, SIGALRM);
|
|
sigaddset(&signals, SIGXFSZ);
|
|
#ifdef FLTINT
|
|
sigaddset(&signals, SIGFPE);
|
|
#endif
|
|
sigprocmask(SIG_BLOCK, &signals, NULL);
|
|
#endif /* DOS */
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void int_unblock() {
|
|
#ifdef DOS
|
|
_dos_setvect(0x1c, DOStimer);
|
|
#else /* DOS */
|
|
sigset_t signals;
|
|
sigemptyset(&signals);
|
|
sigaddset(&signals, SIGVTALRM);
|
|
sigaddset(&signals, SIGIO);
|
|
sigaddset(&signals, SIGALRM);
|
|
sigaddset(&signals, SIGXFSZ);
|
|
#ifdef FLTINT
|
|
sigaddset(&signals, SIGFPE);
|
|
#endif
|
|
sigprocmask(SIG_UNBLOCK, &signals, NULL);
|
|
#endif /* DOS */
|
|
}
|
|
|
|
void int_timer_on() { int_unblock(); }
|
|
void int_timer_off() { int_block(); }
|
|
|
|
#ifdef FLTINT
|
|
/************************************************************************/
|
|
/* */
|
|
/* F L O A T I N G - P O I N T I N T E R R U P T H A N D L I N G */
|
|
/* */
|
|
/* This is the handler for the SIGFPE signal, to catch floating- */
|
|
/* point exceptions. Sets the global 'FP_error' to the error */
|
|
/* code passed in by the signal; FP_error is checked by the */
|
|
/* Lisp emulator FP code to make sure everything is OK. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
/* The global used to signal floating-point errors */
|
|
volatile int FP_error = 0;
|
|
|
|
void int_fp_service(int sig, siginfo_t *info, void *context)
|
|
{
|
|
switch (info->si_code) {
|
|
case FPE_FLTDIV:
|
|
case FPE_FLTUND:
|
|
case FPE_FLTOVF:
|
|
case FPE_FLTINV:
|
|
|
|
FP_error = info->si_code;
|
|
break;
|
|
default: {
|
|
#ifdef DEBUG
|
|
char stuff[100];
|
|
snprintf(stuff, sizeof(stuff), "Unexpected FP error signal code: %d", info->si_code);
|
|
perror(stuff);
|
|
#else
|
|
FP_error = info->si_code;
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
void int_fp_init() {
|
|
struct sigaction fpe_action;
|
|
|
|
fpe_action.sa_handler = int_fp_service;
|
|
sigemptyset(&fpe_action.sa_mask);
|
|
fpe_action.sa_flags = SA_SIGINFO;
|
|
|
|
if (sigaction(SIGFPE, &fpe_action, NULL) == -1) {
|
|
perror("Sigset for FPE failed");
|
|
} else {
|
|
DBPRINT(("FP interrupts enabled\n"));
|
|
}
|
|
}
|
|
|
|
#endif /* FLTINT */
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* t i m e o u t _ e r r o r */
|
|
/* */
|
|
/* Error handling routine for SIGALRM. Called when any */
|
|
/* TIMEOUT(...) forms spend more than TIMEOUT_TIME (normally */
|
|
/* 10 sec.) trying to do an I/O operation. */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
jmp_buf jmpbuf;
|
|
static void timeout_error(int sig) {
|
|
longjmp(jmpbuf, 1);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n t _ f i l e _ i n i t */
|
|
/* */
|
|
/* Set up the signal handler for SIGALRM, to catch TIMEOUTs: */
|
|
/* TIMEOUT(...) forms spend more than TIMEOUT_TIME (normally */
|
|
/* 10 sec.) trying to do an I/O operation. */
|
|
/* */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
static void int_file_init() {
|
|
char *envtime;
|
|
int timeout_time;
|
|
struct sigaction timer_action;
|
|
|
|
timer_action.sa_handler = timeout_error;
|
|
sigemptyset(&timer_action.sa_mask);
|
|
timer_action.sa_flags = 0;
|
|
|
|
if (sigaction(SIGALRM, &timer_action, NULL) == -1) {
|
|
perror("sigaction: SIGALRM");
|
|
}
|
|
|
|
/* Set Timeout period */
|
|
if ((envtime = getenv("LDEFILETIMEOUT")) == NULL) {
|
|
TIMEOUT_TIME = 10;
|
|
} else {
|
|
if ((timeout_time = atoi(envtime)) > 0)
|
|
TIMEOUT_TIME = timeout_time;
|
|
else
|
|
TIMEOUT_TIME = 10;
|
|
}
|
|
DBPRINT(("File timeout interrupts enabled\n"));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* p a n i c u r a i d */
|
|
/* */
|
|
/* Most of the unused process-killing interrupts end up here; you */
|
|
/* can't do a whole lot safely here but dump your sysout for */
|
|
/* post-mortem analysis, but you MIGHT be able to get a clue */
|
|
/* about what killed you. */
|
|
/* */
|
|
/************************************************************************/
|
|
void panicuraid(int sig, siginfo_t *info, void *context)
|
|
{
|
|
static char errormsg[200];
|
|
static char *stdmsg =
|
|
"Please record the signal and code information\n\
|
|
and do a 'v' before trying anything else.";
|
|
|
|
switch (sig) {
|
|
case SIGBUS:
|
|
case SIGILL:
|
|
case SIGSEGV:
|
|
snprintf(errormsg, sizeof(errormsg), "%s at address %p.\n%s", strsignal(sig), info->si_addr, stdmsg);
|
|
break;
|
|
case SIGPIPE:
|
|
snprintf(errormsg, sizeof(errormsg), "Broken PIPE.\n%s", stdmsg);
|
|
break;
|
|
case SIGHUP:
|
|
snprintf(errormsg, sizeof(errormsg), "HANGUP signalled.\n%s", stdmsg);
|
|
/* Assume that a user tried to exit UNIX shell */
|
|
killpg(getpgrp(), SIGKILL);
|
|
exit(0);
|
|
break;
|
|
case SIGFPE:
|
|
snprintf(errormsg, sizeof(errormsg), "%s (%d) at address %p.\n%s", strsignal(sig), info->si_code, info->si_addr, stdmsg);
|
|
break;
|
|
default: snprintf(errormsg, sizeof(errormsg), "Uncaught SIGNAL %s (%d).\n%s", strsignal(sig), sig, stdmsg);
|
|
}
|
|
|
|
error(errormsg);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n t _ p a n i c _ i n i t */
|
|
/* */
|
|
/* A catch for all the deadly interupts (but KILL, of course) */
|
|
/* Dumps you into uraid; you probably can't get back from it, */
|
|
/* but there is hope that you will be able to poke around with */
|
|
/* uraid and get a clue about why you're dying. */
|
|
/* */
|
|
/************************************************************************/
|
|
static void int_panic_init() {
|
|
#ifndef DOS
|
|
struct sigaction panic_action, ignore_action;
|
|
|
|
panic_action.sa_sigaction = panicuraid;
|
|
sigemptyset(&panic_action.sa_mask);
|
|
panic_action.sa_flags = SA_SIGINFO;
|
|
|
|
ignore_action.sa_handler = SIG_IGN;
|
|
sigemptyset(&panic_action.sa_mask);
|
|
panic_action.sa_flags = 0;
|
|
|
|
sigaction(SIGHUP, &panic_action, NULL);
|
|
sigaction(SIGQUIT, &panic_action, NULL);
|
|
sigaction(SIGILL, &panic_action, NULL);
|
|
#ifdef SIGEMT
|
|
sigaction(SIGEMT, &panic_action, NULL);
|
|
#endif
|
|
sigaction(SIGBUS, &panic_action, NULL);
|
|
sigaction(SIGSEGV, &panic_action, NULL);
|
|
sigaction(SIGSYS, &panic_action, NULL);
|
|
sigaction(SIGTERM, &panic_action, NULL);
|
|
|
|
/* Ignore SIGPIPE */
|
|
sigaction(SIGPIPE, &ignore_action, NULL);
|
|
#endif
|
|
|
|
DBPRINT(("Panic interrupts enabled\n"));
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* */
|
|
/* i n t _ i n i t */
|
|
/* */
|
|
/* Initialize all the interrupts for Lisp & the emulator. */
|
|
/* */
|
|
/************************************************************************/
|
|
|
|
void int_init() {
|
|
int_timer_init(); /* periodic interrupt timer */
|
|
int_io_init(); /* SIGIO async I/O handlers */
|
|
int_file_init(); /* file-io TIMEOUT support */
|
|
int_panic_init(); /* catch for all other dangerous interrupts */
|
|
|
|
#ifdef FLTINT
|
|
int_fp_init(); /* Floating-point exception handler */
|
|
#endif
|
|
|
|
int_unblock(); /* Turn on interrupts */
|
|
}
|
|
|
|
#ifdef DOS
|
|
/******************************************************************************
|
|
* DOStimer()
|
|
*
|
|
* The interrupt 0x1c handler. This routine must be declared using the
|
|
* '#pragma interrupt()' statement to ensure that all registers are preserved.
|
|
* It is also needed to ensure the proper functioning of '_chain_intr()'.
|
|
*
|
|
* The timer interrupt (normally) occurs 18.2 times per second. This routine
|
|
* waits one extra tick every 91 ticks (18.2*5).
|
|
*
|
|
* Before this interrupt was installed, 'prev_int_1c' was set to the current
|
|
* 0x1c interrupt. 'DOStimer()' chains to this interrupt using '_chain_intr()',
|
|
* rather than returning back to the caller.
|
|
*
|
|
* Note that as little as possible should be done within a timer interrupt,
|
|
* since further clock ticks are disabled until the interrupt returns.
|
|
******************************************************************************/
|
|
void DOStimer() {
|
|
/* if (--tick_count == 0) { */
|
|
Irq_Stk_Check = 0;
|
|
Irq_Stk_End = 0;
|
|
TimerFlag = 1;
|
|
/* _dos_setvect(0x1c, prev_int_1c);
|
|
} else if (tick_count <= 0) { */
|
|
/* I'm dead, uninstal me */
|
|
/* _dos_setvect(0x1c, prev_int_1c);
|
|
tick_count = 0;
|
|
} */
|
|
_chain_intr(prev_int_1c); /* call previous int 1c handlr, if any*/
|
|
/* (pts to 'ret' if no prev installed)*/
|
|
}
|
|
|
|
void alarm(unsigned long sec)
|
|
{
|
|
/* tick_count = sec * 18;
|
|
_dos_setvect(0x1c, DOStimer); */
|
|
}
|
|
#endif /* DOS */
|