m3core/src/runtime/LINUXLIBC6/RTHeapDep.m3


 Copyright (C) 1993, Digital Equipment Corporation        
 All rights reserved.                                     
 See the file COPYRIGHT for a full description.           
                                                          
| Last modified on Fri Jan 20 09:39:09 PST 1995 by kalsow 
|      modified on Thu Jan 28 19:24:55 PST 1993 by jdd    

UNSAFE MODULE RTHeapDep;

IMPORT RT0u, RTMachine, RTHeapRep, RTCollectorSRC, RTVM;
IMPORT Cstdlib, Ctypes, Umman, Unix, Uresource, Usignal, Utypes, Word;

VAR
  initialized                           := FALSE;
  defaultActionSIGSEGV: Usignal.SignalActionHandler := NIL;
  defaultSIGSEGV: Usignal.SignalHandler := NIL; (* previous handler *)

PROCEDURE 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;
Init establishes a handler for SIGSEGV, caused by VM faults, and for all other signals that cause core dumps.

PROCEDURE 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 := Usignal.empty_sigset_t,
               sa_flags := Usignal.SA_RESTART,
               sa_restorer := NIL};
      ovec: Usignal.struct_sigaction;
      ret, tmp: Ctypes.int;

    BEGIN
      vec.sa_mask.val[0] := Word.LeftShift(1, Usignal.SIGVTALRM - 1);
      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 := Usignal.empty_sigset_t,
                 sa_flags := Usignal.SA_RESTART,
                 sa_restorer := NIL};
        ovec: Usignal.struct_sigaction;
        ret := Usignal.sigaction(sig, ADR(vec), ADR(ovec));
      BEGIN
        vec.sa_mask.val[0] := Word.LeftShift(1, Usignal.SIGVTALRM - 1);
        <* 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;
Fault 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.

PROCEDURE 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;
Core 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.

VAR dumped_core := FALSE;

PROCEDURE Core (             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 := Usignal.empty_sigset_t,
        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;
System-call faults are handled in RTHeapDepC.c

PROCEDURE TimeUsed (): 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;

PROCEDURE VMFaultTime (): REAL =
  BEGIN
    RETURN 0.010;                (* guess 10ms to handle a page fault *)
  END VMFaultTime;

BEGIN
  VM := RTVM.VMHeap();
  IF VM THEN
    RTMachine.RTHeapRep_Fault  := LOOPHOLE (RTHeapRep.Fault, ADDRESS);
    RTMachine.RTCSRC_FinishVM  := LOOPHOLE (RTCollectorSRC.FinishVM, ADDRESS);
  END;
END RTHeapDep.