-- File: PupMiscServer.mesa - last edit:
-- AOF                  3-Feb-88 11:41:34
-- HGM                 25-Jun-85  1:14:30
-- Copyright (C) 1983, 1985, 1988 by Xerox Corporation. All rights reserved. 

DIRECTORY
  Event USING [aboutToSwap],
  EventTypes USING [aboutToBoot, aboutToBootPhysicalVolume],
  Process USING [Yield],
  Supervisor USING [
    AddDependency, AgentProcedure, CreateSubsystem, RemoveDependency,
    SubsystemHandle],
  MiscServerDefs,
  PupDefs USING [
    PupBuffer, PupRouterSendThis, PupSocket, PupSocketKick, PupSocketMake,
    PupSocketDestroy, PupPackageMake, PupPackageDestroy, ReturnBuffer, ReturnPup,
    SwapPupSourceAndDest, veryLongWait],
  PupTypes USING [fillInPupAddress, miscSrvSoc];

PupMiscServer: PROGRAM
  IMPORTS Event, Process, Supervisor, PupDefs EXPORTS MiscServerDefs =
  BEGIN OPEN PupDefs;

  useCount: CARDINAL ← 0;
  pleaseStop, running: BOOLEAN ← FALSE;
  miscSocket: PupSocket ← NIL;
  miscFork: PROCESS;

  bootServer: PROCEDURE [PupBuffer] ← IgnoreThisPacket;
  nameServer: PROCEDURE [PupBuffer] ← IgnoreThisPacket;
  directoryServer: PROCEDURE [PupBuffer] ← IgnoreThisPacket;
  timeServer: PROCEDURE [PupBuffer] ← IgnoreThisPacket;

  broom: Supervisor.SubsystemHandle = Supervisor.CreateSubsystem[Broom];

  PupMiscServerOn: PUBLIC PROCEDURE =
    BEGIN
    IF (useCount ← useCount + 1) = 1 THEN
      BEGIN
      Supervisor.AddDependency[client: broom, implementor: Event.aboutToSwap];
      running ← TRUE;
      Starter[];
      END;
    END;

  Starter: PROCEDURE =
    BEGIN
    pleaseStop ← FALSE;
    [] ← PupDefs.PupPackageMake[];
    miscSocket ← PupSocketMake[
      PupTypes.miscSrvSoc, PupTypes.fillInPupAddress, veryLongWait];
    miscFork ← FORK Misc[];
    END;

  PupMiscServerOff: PUBLIC PROCEDURE =
    BEGIN
    IF useCount # 0 AND (useCount ← useCount - 1) = 0 THEN
      BEGIN
      running ← FALSE;
      Supervisor.RemoveDependency[client: broom, implementor: Event.aboutToSwap];
      Stopper[];
      END;
    END;

  Stopper: PROCEDURE =
    BEGIN
    pleaseStop ← TRUE;
    PupSocketKick[miscSocket];
    JOIN miscFork[];
    PupSocketDestroy[miscSocket];
    PupDefs.PupPackageDestroy[];
    END;

  IgnoreThisPacket: PUBLIC PROCEDURE [b: PupBuffer] =
    BEGIN PupDefs.ReturnBuffer[b]; END;

  SetBootServer: PUBLIC PROCEDURE [proc: PROCEDURE [PupBuffer]] =
    BEGIN bootServer ← proc; END;

  SetNameServer: PUBLIC PROCEDURE [proc: PROCEDURE [PupBuffer]] =
    BEGIN nameServer ← proc; END;

  SetDirectoryServer: PUBLIC PROCEDURE [proc: PROCEDURE [PupBuffer]] =
    BEGIN directoryServer ← proc; END;

  SetTimeServer: PUBLIC PROCEDURE [proc: PROCEDURE [PupBuffer]] =
    BEGIN timeServer ← proc; END;

  -- This procedure is the only HOT chunk of code

  Misc: PROCEDURE =
    BEGIN OPEN MiscServerDefs;  -- lots of PupType values
    b: PupBuffer;
    UNTIL pleaseStop DO
      IF (b ← miscSocket.get[]) # NIL THEN
        BEGIN
        SELECT b.pup.pupType FROM
          bootFileSend, microcodeRequest, slowMicrocodeRequest, sunBootRequest,
	    bootDirReq, bootDirReply,
            lockBooterRequest, unlockBooterRequest, bootStatsRequest =>
            bootServer[b];
          netDirVersion, sendNetDir, lockDirRequest, unlockDirRequest =>
            directoryServer[b];
          nameLookup, addressLookup, nameStatsRequest,
	    nameToCacheRequest, addressToCacheRequest, hereIsCacheEntry => nameServer[b];
          dateTextRequest, dateTenexRequest, dateAltoRequest, lockTimeRequest,
            resetTimeRequest, timeStatsRequest => timeServer[b];
          whereIsUser =>
	    BEGIN  -- Hack to help Chatting to Dicentra get started
            PupDefs.ReturnPup[b, userIs, 0];
	    END;
          echoMe =>
	    BEGIN
            b.pup.pupType ← iAmEcho;
            PupDefs.SwapPupSourceAndDest[b];
            PupDefs.PupRouterSendThis[b];
	    END;
          ENDCASE => PupDefs.ReturnBuffer[b];
        END;
      Process.Yield[];  -- avoid hogging machine
      ENDLOOP;
    END;

  -- Beware of lockups if you try to make this an ENTRY proc
  Broom: Supervisor.AgentProcedure =
    BEGIN
    SELECT event FROM
      EventTypes.aboutToBoot, EventTypes.aboutToBootPhysicalVolume =>
        IF running THEN BEGIN useCount ← 0; Stopper[]; END;
      ENDCASE => NULL;
    END;

  END.