-- File: PupSockets.mesa - last edit:
-- AOF                 17-Feb-88 16:00:33
-- Copyright (C) 1983, 1986, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Buffer USING [Buffer, Dequeue],
  CommFlags USING [doDebug],
  Frame USING [GetReturnFrame, ReadGlobalLink],
  Process USING [DisableTimeout, EnableAborts, SetTimeout],
  PrincOpsMinus USING [NewSelf],
  PupDefs USING [
    Buffer, Dequeue, GetLocalPupAddress, Pair, PupAddress, PupBuffer,
    PupRouterSendThis, PupSocket, PupSocketID, PupSocketObject, Tocks,
    veryLongWait, veryShortWait],
  PupRouterDefs USING [
    PupRouterForgetAboutSocket, PupRouterKnowAboutSocket, PupRouterSocketObject,
    routerLock],
  PupTypes USING [Pair, PupAddress],
  Runtime USING [GlobalFrame];

PupSockets: MONITOR LOCKS PupRouterDefs.routerLock
  IMPORTS Frame, Process, PrincOpsMinus, Runtime, PupRouterDefs, PupDefs
  EXPORTS PupRouterDefs, PupDefs =
  BEGIN OPEN PupRouterDefs, PupDefs;

  -- Manager data
  free: LONG POINTER TO FRAME[PupSockets] ←
    LOOPHOLE[Runtime.GlobalFrame[LOOPHOLE[PupSocketMake]]];
  next: LONG POINTER TO FRAME[PupSockets] ← NIL;

  GetInstance: ENTRY PROC RETURNS [him: LONG POINTER TO FRAME[PupSockets]] =
    BEGIN
    IF free = NIL THEN
      BEGIN
      him ← PrincOpsMinus.NewSelf[];
      START him;  -- Do initialization code
      RETURN;
      END;
    him ← free;
    free ← free.next;
    END;

  FreeInstance: ENTRY PROC[him: LONG POINTER TO FRAME[PupSockets]] =
    {him.next ← free; free ← him};

  myPupSocket: PupSocketObject ← [  -- data for the client
    put: Put, get: Get, setRemoteAddress: SetRemoteAddress,
    getLocalAddress: GetLocalAddress];

  dontWait, kick: BOOLEAN ← FALSE;

  myPupRouterSocket: PupRouterSocketObject;

  PupSocketMake: PUBLIC PROC[
    local: PupSocketID, remote: PupAddress, ticks: Tocks, id: Pair]
    RETURNS [PupSocket] =
    BEGIN
    him: LONG POINTER TO FRAME[PupSockets] ← GetInstance[];
    him.myPupRouterSocket.local ← GetLocalPupAddress[local, @remote];
    him.myPupRouterSocket.remote ← remote;
    him.myPupRouterSocket.id ← id;
    him.dontWait ← him.kick ← FALSE;
    PupRouterKnowAboutSocket[@him.myPupRouterSocket];
    SELECT ticks FROM
      veryShortWait => him.dontWait ← TRUE;
      veryLongWait => Process.DisableTimeout[@him.myPupRouterSocket.ready];
      ENDCASE => Process.SetTimeout[@him.myPupRouterSocket.ready, ticks];
    Process.EnableAborts[@him.myPupRouterSocket.ready];
    RETURN[@him.myPupSocket];
    END;

  PupSocketMakeFull: PUBLIC PROC[local, remote: PupAddress, ticks: Tocks]
    RETURNS [PupSocket] =
    BEGIN
    him: LONG POINTER TO FRAME[PupSockets] ← GetInstance[];
    -- We need to check local to verify that it is valid
    him.myPupRouterSocket.local ← local;
    him.myPupRouterSocket.remote ← remote;
    him.myPupRouterSocket.id ← [0, 0];
    him.dontWait ← him.kick ← FALSE;
    PupRouterKnowAboutSocket[@him.myPupRouterSocket];
    SELECT ticks FROM
      veryShortWait => him.dontWait ← TRUE;
      veryLongWait => Process.DisableTimeout[@him.myPupRouterSocket.ready];
      ENDCASE => Process.SetTimeout[@him.myPupRouterSocket.ready, ticks];
    Process.EnableAborts[@him.myPupRouterSocket.ready];
    RETURN[@him.myPupSocket];
    END;

  PupSocketKick: PUBLIC ENTRY PROC[s: PupSocket] =
    BEGIN
    him: LONG POINTER TO FRAME[PupSockets] ←
      LOOPHOLE[Runtime.GlobalFrame[LOOPHOLE[s.put]]];
    him.kick ← TRUE;
    NOTIFY him.myPupRouterSocket.ready;
    END;

  PupSocketDestroy: PUBLIC PROC[s: PupSocket] =
    BEGIN
    him: LONG POINTER TO FRAME[PupSockets] ←
      LOOPHOLE[Runtime.GlobalFrame[LOOPHOLE[s.put]]];
    PupRouterForgetAboutSocket[@him.myPupRouterSocket];
    FreeInstance[him];
    END;

  Get: ENTRY PROC RETURNS [b: PupBuffer] =
    BEGIN
    IF ~dontWait AND myPupRouterSocket.input.length = 0 THEN
      BEGIN IF ~kick THEN WAIT myPupRouterSocket.ready[ ! UNWIND => NULL]; END;
    kick ← FALSE;
    IF myPupRouterSocket.input.length = 0 THEN RETURN[NIL];
    b ← PupDefs.Dequeue[@myPupRouterSocket.input];
    IF CommFlags.doDebug AND b # NIL THEN
      b.fo.debug ← Frame.ReadGlobalLink[Frame.GetReturnFrame[]];
    END;

  Put: PROC[b: PupBuffer] =
    BEGIN
    b.pup.dest ← myPupRouterSocket.remote;
    b.pup.source ← myPupRouterSocket.local;
    PupRouterSendThis[b];
    END;

  SetRemoteAddress: ENTRY PROC[a: PupAddress] =
    BEGIN myPupRouterSocket.remote ← a; END;

  GetLocalAddress: ENTRY PROC RETURNS [PupAddress] =
    {RETURN[myPupRouterSocket.local]};

  -- initialization

  END.
  
LOG

20-May-83 10:15:11  By: SMA  Action: Converted to new BufferMgr.
12-Jul-83 13:22:57  By: AOF  Action: 32-bit procs.
17-Feb-88 15:16:08  By: AOF  PrincOpsMinus for NEWing.