.
.         SCHEDULING PRIMITIVES
.
.                                       JOHN WALKER   APRIL 1972
.
.
.           (C)  Copyright 1972  John Walker
.
.         This software is in the public domain
.
          AXR$
          DEFUNCT$
          FANG
          LIT$      1
.
.         THE FOLLOWING PARAMETERS CONFIGURE THE SCHEDULER BY
.         SELECTING THOSE ROUTINES WHICH ARE NEEDED BY THE USER.
.
PMAYN     EQU       ;                   ONE IF 'PMAY' IS NEEDED
                    0
.
IRN       EQU       ;                   ONE IF INSERT / REMOVE NEEDED
                    1
.
PUSHN     EQU       ;                   ONE IF PUSH NEEDED
                    0
.
BBN       EQU       ;                   ONE IF PUT / GET NEEDED
                    1
.
FEN       EQU       ;                   ONE IF FORK / EXIT NEEDED
                    1
.
ACTN      EQU       ;                   ONE IF ACTIVITY NAMING IN TSQ MODE
                    1
.
SWL       EQU       ;                   ONE IF SWL'S WANTED IN TSQ MODE
                    1
.
.         THE PARAMETER 'DYNQ' SHOULD BE SET NONZERO IF THE SUBROUTINE
.         'INITQ' IS NEEDED TO DYNAMICALLY INITIALISE AN INSERT / REMOVE
.         QUEUE.
.
DYNQ      EQU       ;                   ONE TO GENERATE INITQ
                    1
.
.         THE PARAMETER 'DYNPVQ' SHOULD BE SET NONZERO IF THE SUBROUTINE
.         'INITPVQ' IS NEEDED TO DYNAMICALLY INITIALISE A P/V QUEUE.
.
DYNPVQ    EQU       ;                   ONE TO GENERATE INITPVQ
                    1
.
.         THE PARAMETER 'DYNBB' SHOULD BE SET NONZERO IF THE SUBROUTINE
.         'INITBB' IS NEEDED TO DYNAMICALLY INITIALISE A BOUNDED BUFFER.
.         SETTING THIS PARAMETER NONZERO ALSO CAUSES THE GENERATION
.         OF 'INITQ' AND 'INITPVQ' REGARDLESS OF THE VALUE OF THE TAGS
.         'DYNQ' AND 'DYNPVQ' ABOVE.
.
DYNBB     EQU       ;                   ONE TO GENERATE INITBB, INITQ, INITPVQ
                    1
.
.
ACTNAM    EQU       ACTN++(TSQ=0)
SWLUSE    EQU       SWL++(TSQ=0)
.
.         DATA FORMATS
.
.
          ON        SWLUSE
.
.         ACTIVITY SWITCHLIST ENTRY
.
PHNAME    EQUF      QL                  ACTIVITY NAME
PHL       EQU       QL+1                ACTIVITY SWL LENGTH
.
          OFF       SWLUSE
.
.         CLEAR TEST AND SET INSTRUCTION
.
P         PROC      *1
CTS*      NAME      0
          DO        TSQ=0 , SZ,S1 P(1,1),P(1,2)
          DO        TSQ , C$TS P(1,1),P(1,2)
          END
/.
.
.         P AND V FUNCTIONS
.
.
.         DIJKSTRA P FUNCTION
.
.
.         LA,U      A0,<QUEUE>
.         LMJ       X11,P
.         <RETURN>                      X5 DESTROYED
.
P*        TS        QHEAD,A0            LOCK THE QUEUE
          LX        X5,QN,A0            LOAD QUEUE COUNT
          ANX,U     X5,1                BACK UP THE COUNT
          SX        X5,QN,A0            REPLACE THE COUNT IN THE QUEUE
          TN        X5                  DO WE NEED TO DEACTIVATE HIM ?
          J         PDONE               NO.  SKIP DEACTIVATION
          ON        TSQ=0
          LX        X5,QHL,A0           LOAD BACK LINK OF QUEUE
          SX        X5,QHL,X4           PUT INTO BACK LINK OF ACTIVITY
          SX        X4,QFL,X5           CHAIN ACTIVITY TO LAST ACTIVITY
          SA        A0,QFL,X4           CHAIN HEAD TO NEW ACTIVITY
          SX        X4,QHL,A0           MAKE THE NEW ACTIVITY LAST ON QUEUE
          CTS       QHEAD,A0            RELEASE PROTECTION ON QUEUE HEAD
SCHDACT*  DACT$     .                   DEACTIVATE PROCESS
          OFF
          ON        TSQ
          C$TSQ     QHEAD,A0            WAIT FOR C$TSA
          OFF
          J         0,X11               RETURN AFTER ACTIVATION
.
PDONE     CTS       QHEAD,A0            UNLOCK THE QUEUE
          J         0,X11               RETURN
.
.
.         DIJKSTRA V FUNCTION
.
.         LA,U      A0,<QUEUE>
.         LMJ       X11,V
.         <RETURN>                      X5 DESTROYED; X6 IFF NOT TSQ.
.
V*        TS        QHEAD,A0            LOCK THE QUEUE HEAD
          LX        X5,QN,A0            LOAD QUEUE COUNT
          AX,U      X5,1                COUNT IT UP
          SX        X5,QN,A0            UPDATE QUEUE COUNT
          ANX,U     X5,1                BACK UP THE COUNT
          TN        X5                  DID WE WAKE UP AN ACTIVITY ?
          J         VDONE               NO.  SKIP THIS STUFF
          ON        TSQ=0
          LX        X5,QFL,A0           GET FIRST WAITING PROCESS
          LX        X6,QFL,X5           GET NEXT WAITING PROCESS
          SX        X6,QFL,A0           CHAIN NEXT TO HEAD
          SA        A0,QHL,X6           POINT NEW FIRST ONE TO HEAD
          SA        A0,X6               SAVE A0
          LA        A0,PHNAME,X5        LOAD PROCESS HEADER NAME
          ACT$      .                   ACTIVATE THE PROCESS
          LA        A0,X6               RESTORE NAME
          OFF
          ON        TSQ
          C$TSA     QHEAD,A0            ACTIVATE THE FIRST ONE.
          J         0,X11               RETURN.
          OFF
VDONE     CTS       QHEAD,A0            UNLOCK THE QUEUE
          J         0,X11               RETURN
/.
.
.         CONDITIONAL P FUNCTION
.
.         LA,U      A0,<QUEUE>
.         LMJ       X11,PMAY
.         <FAILED RETURN>                (YOU DON'T GO TO SLEEP)
.         <NORMAL RETURN>
.
          ON        PMAYN
PMAY$*    TS        QHEAD,A0            LOCK THE QUEUE
          LX        X5,QN,A0            LOAD THE COUNT
          ANX,U     X5,1                COUNT IT DOWN
          TP        X5                  IS IT POSITIVE OR ZERO ?
          J         PMAYF               NO.  IT FAILED
          SX        X5,QN,A0            STORE OUT DECREMENTED COUNT
          CTS       QHEAD,A0            UNLOCK THE QUEUE
          J         1,X11               RETURN TO NORMAL RETURN
.
PMAYF     CTS       QHEAD,A0            UNLOCK THE QUEUE
          J         0,X11               TAKE FAILED RETURN
          OFF       PMAYN
/.
.
.         QUEUE MANIPULATION PRIMITIVES
.
.         QUEUE INSERT
.
.         LA,U      A0,<QUEUE>
.         LA,U      A1,<DATA>
.         LMJ       X11,INSERT
.         <RETURN>                      X5 DESTROYED
.
          ON        IRN++BBN
INSERT*   TS        QHEAD,A0            LOCK THE QUEUE
          LX        X5,QHL,A0           X5 = LAST BUFFER ON QUEUE
          SX        X5,QHL,A1           POINT NEW ONE TO LAST
          SA        A1,QFL,X5           SET FORWARD LINK OF LAST ONE
          SA        A0,QFL,A1           POINT NEW ONE TO HEAD
          SA        A1,QHL,A0           POINT HEAD TO NEW ONE
          CTS       QHEAD,A0            UNLOCK THE QUEUE
          J         0,X11               RETURN
.
.
.         QUEUE REMOVE
.
.         LA,U      A0,<QUEUE>
.         LMJ       X11,REMOVE
.         <RETURN>                      A1 = DATA
.                                       X5 DESTROYED
.
REMOVE*   TS        QHEAD,A0            LOCK THE QUEUE
          LA        A1,QFL,A0           LOAD FIRST ALLOCATED PACKET
          LX        X5,QFL,A1           GET NEXT BUFFER
          SX        X5,QFL,A0           POINT HEAD TO IT
          SA        A0,QHL,X5           POINT IT BACK TO HEAD
          CTS       QHEAD,A0            UNLOCK THE HEAD
          J         0,X11               RETURN
          OFF       IRN++BBN
.
.
.         QUEUE PUSH (INSERT AT HEAD)
.
.         LA,U      A0,<QUEUE>
.         LA,U      A1,<DATA>
.         LMJ       X11,PUSH
.         <RETURN>                      X5 DESTROYED
.
          ON        PUSHN
PUSH*     TS        QHEAD,A0            LOCK QUEUE LINKS
          LX        X5,QFL,A0           LOAD LINK TO FIRST DATA ITEM
          SX        X5,QFL,A1           ATTACH FORWARD CHAIN TO NEW ITEM
          SA        A1,QHL,X5           POINT BACKPOINTER TO NEW ITEM
          SA        A0,QHL,A1           SET BACKPOINTER OF NEW ITEM TO HEAD
          SA        A1,QFL,A0           MAKE NEW ITEM FIRST ON QUEUE
          CTS       QHEAD,A0            UNLOCK QUEUE LINKS
          J         0,X11               RETURN TO CALLER
          OFF       PUSHN
/.
.
.         BOUNDED BUFFER OPERATIONS
.
.         PUT ONTO BOUNDED BUFFER
.
.         LA,U      A0,<BOUNDED BUFFER>
.         LA,U      A1,<DATA>
.         LMJ       A3,PUT
.         <RETURN>                      X11, X5 DESTROYED
.
          ON        BBN
PUT*      AA,U      A0,QL*2             POINT TO 'QUEUE NOT FULL'
          LXI       X11,A3              SAVE RETURN.
          P         .                   P 'QUEUE NOT FULL'
          ANA,U     A0,QL*2             POINT TO DATA QUEUE
          INSERT    .                   INSERT DATUM ON QUEUE
          AA,U      A0,QL               POINT TO QUEUE NOT EMPTY
          V         .                   V 'QUEUE NOT EMPTY'
          ANA,U     A0,QL               POINT BACK TO BEGINNING
          L         A3,X11              RETURN IN UPPER(A3)
          SSL       A3,18               PUT IT SOMEWHERE USEFUL.
          J         0,A3                RETURN
.
.         BOUNDED BUFFER ITEM GET
.
.         LA,U      A0,<BOUNDED BUFFER>
.         LMJ       A3,GET
.         <RETURN>                      A1 = <DATA>
.                                       X11, X5 DESTROYED
.
GET*      AA,U      A0,QL               POINT TO QUEUE NOT EMPTY
          LXI       X11,A3              SAVE RETURN.
          P         .                   P 'QUEUE NOT EMPTY'
          ANA,U     A0,QL               BACK UP TO DATA QUEUE
          REMOVE    .                   REMOVE THE ITEM FROM THE QUEUE
          AA,U      A0,QL*2             POINT TO QUEUE NOT FULL
          V         .                   V 'QUEUE NOT FULL'
          ANA,U     A0,QL*2             BACK UP TO HEAD OF BOUNDED BUFFER
          L         A3,X11              RETURN IS IN INCREMENT.
          SSL       A3,18               MOVE IT DOWN.
          J         0,A3                RETURN
          OFF       BBN
/.
.
.         CREATE / DESTROY ACTIVITY
.
.         CREATE A NEW ACTIVITY
.
.         LA,U      A1,<ENTRY POINT>
.         LMJ       X11,FORK
.
          ON        FEN
FORK*     FORK$     FSETUP,1            GET A NEW ACTIVITY
          J         0,X11               RETURN
.
FSETUP    .
          ON        SWLUSE
          BGET      PHL                 ALLOCATE A PROCESS HEADER.
          LX,U      X4,,A0              LOAD RUNNING SWITCHLIST POINTER
          OFF       SWLUSE
          ON        ACTNAM
          la        a0,uactn            load unique activity name cell
          aa,u      a0,1                increment it
          sa        a0,uactn            update unique activity name
          NAME$     .                   ATTACH A NAME TO THE ACTIVITY
          ON        SWLUSE
          SA        A0,PHNAME,X4        SET ACTIVITY NAME IN SWL
          OFF       SWLUSE
          OFF       ACTNAM
          J         0,A1                ENTER NEW ACTIVITY
.
.         TERMINATE ACTIVITY
.
.         THE SWITCHLIST IS RELEASED BY THIS ROUTINE
.
EXIT*.
          ON        SWLUSE
          BRELP     X4                  RELEASE THE SWITCH LIST.
          OFF       SWLUSE
          EXIT$     .                   BYE !
.
          OFF       FEN
/.
.
.         DYNAMIC QUEUE INITIALISATION
.
.
.         INITIALISE AN INSERT / REMOVE QUEUE
.
.         LA,U      A0,<QUEUE>
.         LMJ       X11,INITQ
.         <RETURN>                      A1 DESTROYED
.
          ON        DYNQ++DYNBB
INITQ*    SA        A0,QFL,A0           POINT FORWARD LINK TO QUEUE
          SA        A0,QHL,A0           POINT BACK LINK TO QUEUE
          ON        TSQ=0
          SZ        QHEAD,A0            CLEAR TEST AND SET ON QUEUE HEAD
          OFF       TSQ=0
          ON        TSQ
          LA        A1,(T$CELL 0)       LOAD A TEST AND SET CELL
          SA        A1,QHEAD,A0         INITIALISE THE QUEUE HEAD
          OFF       TSQ
          J         0,X11               RETURN TO CALLER
          OFF       DYNQ++DYNBB
.
.
.         INITIALISE A P/V QUEUE
.
.         LA,U      A1,<COUNT>
.         LA,U      A0,<QUEUE>
.         LMJ       X11,INITPVQ
.         <RETURN>
.
          ON        DYNPVQ++DYNBB
INITPVQ*  SA        A1,QN,A0            SET COUNT IN QUEUE
          ON        TSQ=0
          SZ,H1     QHEAD,A0            CLEAR TEST AND SET
          SA        A0,QFL,A0           LINK FORWARD LINK TO QUEUE
          SA        A0,QHL,A0           LINK BACK LINK TO QUEUE
          OFF       TSQ=0
          ON        TSQ
          LA        A1,(T$CELL 0)       LOAD A TEST AND SET CELL
          SA        A1,QHEAD,A0         SET CELL IN QUEUE HEAD
          LA        A1,QN,A0            RELOAD ORIGINAL COUNT
          OFF       TSQ
          J         0,X11               RETURN TO CALLER
          OFF       DYNPVQ++DYNBB
.
.
.         INITIALISE A BOUNDED BUFFER
.
.         LA,U      A1,<COUNT>          COUNT FOR NOT FULL QUEUE
.         LA,U      A0,<BUFFER>
.         LMJ       X11,INITBB
.         <RETURN>                      H1(X11), A1 DESTROYED
.
          ON        DYNBB
INITBB*   LXI,U     X11,,X11            SAVE ORIGINAL CALL ADDRESS
          AA,U      A0,QL+QPL           ADVANCE TO NOT FULL QUEUE
          INITPVQ   .                   INITIALISE THE NOT FULL P/V QUEUE
          ANA,U     A0,QPL              BACK UP TO THE NOT EMPTY QUEUE
          LA,U      A1                  CLEAR COUNT FOR NOT EMPTY QUEUE
          INITPVQ   .                   INITIALISE THE NOT EMPTY P/V QUEUE
          ANA,U     A0,QL               BACK UP TO DATA QUEUE AT BEGINNING
          LXM,U     X11                 CLEAR MODIFIER OF X11
          NOP       0,,*X11             RESTORE ORIGINAL CALL ADDRESS
          J         INITQ               GO INITIALISE THE DATA QUEUE
          OFF       DYNBB
          END