Copyright (C) 1994, Digital Equipment Corp.
UNSAFE MODULEInit establishes a handler for SIGSEGV, caused by VM faults, and for all other signals that cause core dumps.; IMPORT RT0u, RTMachine, RTHeapRep, RTCollectorSRC; IMPORT Cstdlib, Ctypes, Umman, Unix, Uresource, Usignal, Utypes, Word; VAR initialized := FALSE; defaultActionSIGSEGV: Usignal.SignalActionHandler := NIL; defaultSIGSEGV: Usignal.SignalHandler := NIL; (* previous handler *) PROCEDURE RTHeapDep Protect (p: Page; n: CARDINAL; readable, writable: BOOLEAN) = BEGIN IF NOT initialized THEN Init(); initialized := TRUE; END; IF NOT readable THEN writable := FALSE; END; (* processor limitation *) VAR prot: Ctypes.int := 0; BEGIN IF readable THEN prot := Word.Or(prot, Umman.PROT_READ); END; IF writable THEN prot := Word.Or(prot, Umman.PROT_WRITE); END; VAR ret := Umman.mprotect(LOOPHOLE(p * BytesPerPage, Utypes.caddr_t), n * BytesPerPage, prot); BEGIN <* ASSERT ret = 0 *> END; END; END Protect;
PROCEDUREFault is called upon a SIGSEGV signal, caused by a VM fault. If RTHeapRep.Fault is not able to handle the fault, it invokes the previous action.Init () = BEGIN (* sanity check *) VAR vmPageBytes := Unix.getpagesize(); BEGIN <* ASSERT BytesPerPage >= vmPageBytes *> <* ASSERT BytesPerPage MOD vmPageBytes = 0 *> END; (* establish SIGSEGV handler; remember previous handler *) VAR newHandler := LOOPHOLE(Fault,Usignal.SignalActionHandler); vec := Usignal.struct_sigaction{ sa_handler := newHandler, sa_mask := Word.LeftShift(1, Usignal.SIGVTALRM - 1), sa_flags := Usignal.SA_RESTART, sa_restorer := NIL}; ovec: Usignal.struct_sigaction; ret, tmp: Ctypes.int; BEGIN tmp := Usignal.SA_RESTART; ret := Usignal.sigaction(Usignal.SIGSEGV, ADR(vec), ADR(ovec)); <* ASSERT ret = 0 *> defaultActionSIGSEGV := ovec.sa_handler; defaultSIGSEGV := LOOPHOLE(defaultActionSIGSEGV,Usignal.SignalHandler); END; (* establish signal handler for all other signals that dump core, if no handler exists *) PROCEDURE OverrideDefault (sig: Ctypes.int) = VAR newHandler := LOOPHOLE(Core,Usignal.SignalActionHandler); vec := Usignal.struct_sigaction{ sa_handler := newHandler, sa_mask := Word.LeftShift(1, Usignal.SIGVTALRM - 1), sa_flags := Usignal.SA_RESTART, sa_restorer := NIL}; ovec: Usignal.struct_sigaction; ret := Usignal.sigaction(sig, ADR(vec), ADR(ovec)); BEGIN <* ASSERT ret = 0 *> IF ovec.sa_handler # Usignal.SIG_DFL THEN ret := Usignal.sigaction(sig, ADR(ovec), ADR(vec)); <* ASSERT ret = 0 *> END; END OverrideDefault; BEGIN OverrideDefault(Usignal.SIGQUIT); OverrideDefault(Usignal.SIGILL); OverrideDefault(Usignal.SIGTRAP); OverrideDefault(Usignal.SIGIOT); OverrideDefault(Usignal.SIGEMT); OverrideDefault(Usignal.SIGFPE); OverrideDefault(Usignal.SIGBUS); OverrideDefault(Usignal.SIGSYS); END; END Init;
PROCEDURECore is a signal handler for signals that dump core, to complete the current collection before dumping core. This makes core files easier to debug, and avoids an Ultrix bug that creates incomplete core files if heap pages are read-protected.Fault (sig : Ctypes.int; scp : Usignal.struct_sigcontext; code: Ctypes.int) = BEGIN IF RTHeapRep.Fault(LOOPHOLE(scp.cr2, ADDRESS)) THEN RETURN; END; IF defaultActionSIGSEGV = Usignal.SIG_IGN THEN RETURN; END; IF defaultActionSIGSEGV = Usignal.SIG_DFL THEN Core(sig, scp, code); ELSE defaultSIGSEGV(sig, scp, code); END; END Fault;
VAR dumped_core := FALSE; PROCEDURESystem-call faults are handled in RTHeapDepC.cCore ( sig : Ctypes.int; <* UNUSED *> scp : Usignal.struct_sigcontext; <* UNUSED *> code: Ctypes.int) = VAR ovec: Usignal.struct_sigaction; vec := Usignal.struct_sigaction{sa_handler := Usignal.SIG_DFL, sa_mask := 0, sa_flags := Usignal.SA_RESTART, sa_restorer := NIL}; BEGIN INC(RT0u.inCritical); IF NOT dumped_core THEN dumped_core := TRUE; EVAL RTHeapRep.Crash(); (* clean up the heap *) EVAL Usignal.sigaction(sig, ADR(vec), ADR(ovec)); (* establish default action *) EVAL Usignal.sigsetmask(0); (** EVAL Usignal.kill(Uprocess.getpid(), sig); (* dump core *) **) Cstdlib.abort (); (* dump core *) <* ASSERT FALSE *> END; DEC(RT0u.inCritical); END Core;
PROCEDURETimeUsed (): REAL = VAR usage: Uresource.struct_rusage; BEGIN VAR ret := Uresource.getrusage(Uresource.RUSAGE_SELF, ADR(usage)); BEGIN <* ASSERT ret # -1 *> END; RETURN (FLOAT(usage.ru_utime.tv_sec) + FLOAT(usage.ru_utime.tv_usec) / 1000000.0) + (FLOAT(usage.ru_utime.tv_sec) + FLOAT(usage.ru_utime.tv_usec) / 1000000.0); END TimeUsed; PROCEDUREVMFaultTime (): REAL = BEGIN RETURN 0.010; (* guess 10ms to handle a page fault *) END VMFaultTime; BEGIN IF VM THEN RTMachine.RTHeapRep_Fault := LOOPHOLE (RTHeapRep.Fault, ADDRESS); RTMachine.RTCSRC_FinishVM := LOOPHOLE (RTCollectorSRC.FinishVM, ADDRESS); END; END RTHeapDep.