%RECORDFORMAT PARMF(%INTEGER DEST,SRCE,P1,P2,P3,P4,P5,P6)
%EXTERNALROUTINESPEC PTREC(%RECORDNAME P)
%EXTRINSICLONGINTEGER KMON
%EXTERNALSTRING(15)%FNSPEC STRINT(%INTEGER N)
%EXTERNALSTRING(15)%FNSPEC HTOS(%INTEGER N,M)
%EXTERNALROUTINESPEC OPMESS(%STRING(63) S)
%EXTERNALROUTINESPEC MONITOR(%STRING(63) S)
%EXTERNALROUTINESPEC PON(%RECORDNAME P)  
!-----------------------------------------------------------------------
%EXTERNALROUTINE SEMAPHORE(%RECORDNAME P)
%RECORDSPEC P(PARMF)
%OWNBYTEINTEGERARRAY HASH(0:31)=0(32)
! ARRAY DIMENSIONS ASSUME ONLY 'MAXPROCS' SEMAPHORES IN USE AT ONCE
%OWNINTEGERARRAY CELL(1:64)=0(64)    ;  ! (1:MAXPROCS)
%OWNBYTEINTEGERARRAY LINK(1:64)=2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,
  17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,
  40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,
  63,64,1
%OWNINTEGER ASL=64
%INTEGERFNSPEC NEWCELL(%INTEGER S)
%INTEGERFNSPEC RETURN CELL(%INTEGER I)
%INTEGER SEMA, HASHP, NCELL, I
%BYTEINTEGERNAME CELLP
%SWITCH ACT(1:3)
   %IF KMON&1<<7#0 %THEN PRINT STRING('SEMAPHORE:') %C
      %AND PTREC(P)
   ->ACT(P_DEST&X'FFFF')
!-----------------------------------------------------------------------
ACT(1):                                 ! P OPERATION
   SEMA=P_P1&X'FFFF'
   HASHP=SEMA-SEMA//31*31
   CELLP==HASH(HASHP)
   %WHILE CELLP#0 %CYCLE
      %IF SEMA=CELL(CELLP)&X'FFFF' %THEN %START
         I=CELL(CELLP)>>16&X'FF'
         %IF I=0 %THEN %START;          ! ALREADY HAD V OPERATION
            P_DEST=P_SRCE
            P_SRCE=X'70001'
            PON(P)
            CELLP=RETURN CELL(CELLP)
         %FINISH %ELSE %START
            NCELL=NEWCELL(P_SRCE)
            LINK(I)=NCELL
            CELL(CELLP)=CELL(CELLP)&X'FF00FFFF'!NCELL<<16
         %FINISH
         %RETURN
      %FINISH
      CELLP==LINK(CELLP)
   %REPEAT
! NO QUEUE YET
   NCELL=NEWCELL(P_SRCE)
   CELLP=NEWCELL(NCELL<<24!NCELL<<16!SEMA)
   %RETURN
!-----------------------------------------------------------------------
ACT(2):                                 ! V OPERATION
   SEMA=P_P1&X'FFFF'
   HASHP=SEMA-SEMA//31*31
   CELLP==HASH(HASHP)
   %WHILE CELLP#0 %CYCLE
      %IF SEMA=CELL(CELLP)&X'FFFF' %THEN %START
         I=CELL(CELLP)>>24
         P_DEST=CELL(I)
         P_SRCE=X'70001'
         PON(P)
         I=RETURN CELL(I)
         %IF I=0 %THEN CELLP=RETURN CELL(CELLP) %C
            %ELSE CELL(CELLP)=CELL(CELLP)&X'00FFFFFF'!I<<24
         %RETURN
      %FINISH
      CELLP==LINK(CELLP)
   %REPEAT
! P OPERATION NOT HERE YET
   CELLP=NEWCELL(SEMA)
   %RETURN
!-----------------------------------------------------------------------
ACT(3):                                 ! DISPLAY SEMAPHORE QUEUES
   %CYCLE HASHP=0,1,31
      %IF HASH(HASHP)#0 %THEN %START
         CELLP==HASH(HASHP)
         %WHILE CELLP#0 %CYCLE
            SEMA=CELL(CELLP)&X'FFFF'
            I=CELL(CELLP)>>24
            %WHILE I#0 %THEN OPMESS('SEMA '.STRINT(SEMA). %C
               ' QUEUE :'.HTOS(CELL(I)>>16,2)) %AND I=LINK(I)
            CELLP==LINK(CELLP)
         %REPEAT
      %FINISH
   %REPEAT
   %RETURN
!-----------------------------------------------------------------------
%INTEGERFN NEWCELL(%INTEGER S)
%INTEGER I
   %IF ASL=0 %THEN MONITOR('SEMAPHORE ASL EMPTY')
   I=LINK(ASL)
   %IF I=ASL %THEN ASL=0 %ELSE LINK(ASL)=LINK(I)
   CELL(I)=S
   LINK(I)=0
   %RESULT =I
%END
!-----------------------------------------------------------------------
%INTEGERFN RETURN CELL(%INTEGER I)
%INTEGER J
   J=LINK(I)
   %IF ASL=0 %THEN LINK(I)=I %C
      %ELSE LINK(I)=LINK(ASL) %AND LINK(ASL)=I
   ASL=I
   %RESULT =J
%END
!-----------------------------------------------------------------------
%END
%ENDOFFILE