-- File: DynamicZoneHot.mesa
-- Last edited by Levin:   4-Dec-80  9:36:45

DIRECTORY
  AltoDefs USING [PageSize],
  DynamicZonePrivate USING [LargeNode, MDSZoneHandle],
  FSPDefs USING [
    AddToNewZone, FreeNode, MakeNode, NodeHeader, NodeOverhead,
    NoRoomInZone, ZoneOverhead],
  Inline USING [BITXOR],
  SegmentDefs USING [
    DataSegmentHandle, DataSegmentType, InsufficientVM, VMtoDataSegment],
  Storage USING [FreePages, Pages, PagesForWords];

DynamicZoneHot: PROGRAM
  IMPORTS FSPDefs, Inline, SegmentDefs, Storage
  EXPORTS DynamicZonePrivate =

  BEGIN OPEN DynamicZonePrivate, FSPDefs;


  -- Miscellaneous Declarations --

  FreeToWrongZone: ERROR = CODE;
  IllegalRequest: ERROR = CODE;
  IllegalNode: ERROR = CODE;
  NoMemory: ERROR [needed: CARDINAL] = CODE;


  -- Procedures exported to DynamicZonePrivate --

  AllocateNode: PUBLIC PROCEDURE [zone: MDSZoneHandle, size: CARDINAL]
    RETURNS [p: POINTER] =
    BEGIN OPEN Storage;
    IF INTEGER[size] < 0 THEN ERROR IllegalRequest;
    IF size + NodeOverhead > LargeNode THEN
      BEGIN
      p ← GetPages[PagesForWords[size+NodeOverhead], zone.segType];
      p↑ ← NodeHeader[length: size+NodeOverhead, extension: inuse[]];
      RETURN[p+1]
      END;
    p ← MakeNode[zone.fspZone, size ! NoRoomInZone =>
      {pages: CARDINAL = PagesForWords[size+ZoneOverhead+NodeOverhead];
       AddToNewZone[
	z: zone.fspZone, base: GetPages[pages, zone.segType],
	length: pages*AltoDefs.PageSize, deallocate: FreePages];
       RESUME}];
    END;

  DeallocateNode: PUBLIC PROCEDURE [zone: MDSZoneHandle, object: POINTER] =
    BEGIN OPEN SegmentDefs;
    seg: DataSegmentHandle = VMtoDataSegment[object];
    IF object = NIL OR seg = NIL THEN ERROR IllegalNode;
    IF Inline.BITXOR[seg.type, zone.segType] > 1 THEN ERROR FreeToWrongZone;
    IF LOOPHOLE[object-1, POINTER TO inuse NodeHeader].length > LargeNode THEN
      Storage.FreePages[object-1]
    ELSE FreeNode[zone.fspZone, object];
    END;

  GetPages: PUBLIC PROCEDURE [pages: CARDINAL, segType: SegmentDefs.DataSegmentType]
    RETURNS [p: POINTER] =
    BEGIN OPEN SegmentDefs;
    seg: DataSegmentHandle;
    p ← Storage.Pages[pages ! InsufficientVM => ERROR NoMemory[needed]];
    seg ← VMtoDataSegment[p];
    seg.type ← segType;
    END;

  END.