-- File: PilotCommUtil.mesa - last edit:
-- AOF                 22-Jun-87  8:55:32
-- MI                  25-Jul-86 23:40:54
-- SMA                 21-May-86 10:46:56
-- Copyright (C) 1984, 1985, 1986, 1987 by Xerox Corporation. All rights reserved. 

DIRECTORY
  BufferOps USING [],
  CommFlags USING [doErrors],
  CommHeap USING [],
  CommUtil USING [],
  Driver USING [],
  Environment USING [bytesPerPage, bytesPerWord, PageNumber, PageCount],
  Heap USING [Create, Delete, Error, systemZone],
  Inline USING [LowHalf],
  PilotSwitches USING [heapOwnerChecking],
  Process USING [MsecToTicks, SecondsToTicks, Ticks],
  ResidentHeap USING [MakeNode, FreeNode, first64K],
  Runtime USING [CallDebugger],
  Space USING [
    Allocate, Interval, GetMapUnitAttributes, PageFromLongPointer, Deallocate],
  SpaceUsage USING [CommunicationUsage],
  System USING [
    isUtilityPilot, Pulses, MicrosecondsToPulses, PulsesToMicroseconds,
    switches],
  VM USING [Map, nullBackingStoreRuns, Unmap],
  Zone USING [Status, Base];

PilotCommUtil: MONITOR
  IMPORTS Inline, Heap, Process, ResidentHeap, Runtime, Space, System, VM
  EXPORTS BufferOps, CommHeap, CommUtil, Driver =
  BEGIN


  ZoneNotEmpty: ERROR = CODE;
  zone: PUBLIC UNCOUNTED ZONE ← NIL;
  pagesForBuffers: PUBLIC LONG CARDINAL ← 0;
  ResidentZoneTrouble: PUBLIC ERROR = CODE;

  --the following constant is used in setting wait times, etc
  maxPulsesToUsecs: LONG CARDINAL = System.MicrosecondsToPulses[
    LAST[LONG CARDINAL]];


  -- IOCB allocation, all from the first 64K bank of virtual memory.
  AllocateIocbs: PUBLIC PROC [nbytes: CARDINAL] RETURNS [LONG POINTER] =
    BEGIN
    status: Zone.Status;
    p: Zone.Base RELATIVE POINTER;
    [p, status] ← ResidentHeap.MakeNode[
      (nbytes + Environment.bytesPerWord - 1) / Environment.bytesPerWord, a8];
    IF status # okay THEN Glitch[ResidentZoneTrouble];
    RETURN[@ResidentHeap.first64K[p]]; -- make into a LONG absolute
    END;

  FreeIocbs: PUBLIC PROC [base: LONG POINTER] =
    BEGIN
    p: Zone.Base RELATIVE POINTER ← Inline.LowHalf[
      base - LOOPHOLE[ResidentHeap.first64K, LONG POINTER]];
    [] ← ResidentHeap.FreeNode[p];
    END;

  IncrementPageCount: ENTRY PROC [pages: Environment.PageCount] = INLINE {
    pagesForBuffers ← pagesForBuffers + pages};
    
  DecrementPageCount: ENTRY PROC [pages: Environment.PageCount] = INLINE {
    pagesForBuffers ← pagesForBuffers - pages};
    
  -- Clumps of pages with no backing store
  AllocateBuffers: PUBLIC PROC [nbytes: CARDINAL] RETURNS [base: LONG POINTER] =
    BEGIN
    pages: Environment.PageCount =
      (nbytes + Environment.bytesPerPage - 1) / Environment.bytesPerPage;
    interval: Space.Interval = Space.Allocate[pages];
    page: Environment.PageNumber = Space.PageFromLongPointer[interval.pointer];
    VM.Map[
      interval: [page, pages], transferProc: NIL, swapUnits: [unitary[]],
      backingStoreRuns: VM.nullBackingStoreRuns, swappability: resident,
      class: data, usage: FIRST[SpaceUsage.CommunicationUsage]];
    IncrementPageCount[interval.count];
    RETURN[interval.pointer];
    END;

  FreeBuffers: PUBLIC PROC [base: LONG POINTER] =
    BEGIN
    interval: Space.Interval ← Space.GetMapUnitAttributes[base].interval;
    VM.Unmap[Space.PageFromLongPointer[interval.pointer]];
    Space.Deallocate[interval];
    DecrementPageCount[interval.count];
    END;

  --Standard heap stuff for CommHeap, etc
  Create: PUBLIC ENTRY PROCEDURE =
    BEGIN
    ENABLE UNWIND => NULL;
    IF zone # NIL THEN RETURN;
    zone ← IF System.isUtilityPilot THEN Heap.systemZone
    ELSE Heap.Create[
      initial: 2, increment: 10, threshold: 8,
      ownerChecking: System.switches[PilotSwitches.heapOwnerChecking] = down];
    END;

  Destroy: PUBLIC ENTRY PROCEDURE =
    BEGIN
    ENABLE UNWIND => zone ← NIL;
    IF zone = NIL THEN RETURN;
    IF ~System.isUtilityPilot THEN Heap.Delete[
      z: zone, checkEmpty: CommFlags.doErrors !
	Heap.Error => IF CommFlags.doErrors THEN Glitch[ZoneNotEmpty]];
    zone ← NIL;
    END;

  PulsesToTicks: PUBLIC --CommUtil-- PROC [pulses: System.Pulses]
    RETURNS [ticks: Process.Ticks] =
    BEGIN
    <<
    This code translates pulses to ticks, allowing for the roundoff errors.
    Present tests on a DLion indicate that the time represented in ticks is
    pulses < ticks < pulses+1%.  This should be verified on Dolphins.
    >>
    mSec: LONG CARDINAL;
    pulses ←  [MIN[pulses, maxPulsesToUsecs]];
    mSec ← System.PulsesToMicroseconds[pulses]/1000;
    ticks ← IF mSec > LONG[LAST[CARDINAL]] THEN
      Process.SecondsToTicks[CARDINAL[mSec/1000]]
    ELSE Process.MsecToTicks[CARDINAL[mSec]];
    ticks ← ticks + (ticks / 64) + 1;
    END;  --PulsesToTicks

  -- Communication error handler

  errorHandler: PROC [ERROR] ← DefaultErrorHandler;

  CaptureErrors: PUBLIC PROC [proc: PROC [ERROR]] = {errorHandler ← proc};

  DefaultErrorHandler: PROC [why: ERROR] =
    BEGIN
    Thoushallnot: ENTRY PROC = INLINE {WAIT filldoe};
    filldoe: CONDITION;
    Runtime.CallDebugger["Communication Glitch"L];
    Thoushallnot[];  --assumes disabled timeouts
    END;

  Glitch: PUBLIC PROC [why: ERROR] = {errorHandler[why]};


  END....  --PilotCommUtil module

LOG

16-May-84 14:11:28  AOF  Post Klamath
23-Aug-85  7:39:01  AOF  Copy systemZone's ownerChecking state
 3-Nov-85 12:03:45  AOF  Changed Heap's expansion value from 2 to 10
 5-Nov-85 14:01:11  AOF  Remove LOOPHOLE
21-May-86 10:46:38  SMA  Remove dependencies on PupDefs.
25-Jul-86 23:39:51  MI   Added pagesForBuffers to count pages used for buffers.
19-Jan-87 14:57:00  AOF  Arguments are bytes, not words.
 2-Feb-87 10:29:37  AOF  Initialize value of 'zone'.