*DECK DB$CMOH 
USETEXT CDCSCTX 
      PROC DB$CMOH((CALLNUM),REQSIZE);
      BEGIN 
 #
* *   DB$CMOH - CDCS CMM OVERFLOW HANDLER        PAGE  1
* *   J E ESLER                                  DATE  11/01/76 
* *   BOB MCALLESTER                             DATE  01/31/85 
* 
* DC  PURPOSE 
* 
*     RELEASE BLOCKS ON MANAGED MEMORY AS REQUIRED FOR NORMAL MEMORY
*     MANAGEMENT AND MEMORY OVERFLOW RECOVERY.
* 
* DC  ENTRY CONDITIONS
* 
*     CALLNUM = LEVEL OF MANAGEMENT TO PERFORM = 1 THRU 5 
*     REQSIZE = SIZE OF REQUEST CAUSING OVERFLOW
* 
* DC  EXIT CONDITIONS 
* 
*     BLOCKS MEETING RELEASE CRITERIA HAVE BEEN RELEASED. 
*     A DAYFILE DIAGNOSTIC IS ISSUED FOR CALLNUM = 5. 
* 
* DC  CALLING ROUTINES
* 
*     CMM    - COMMON MEMORY MANAGER
*     DB$MTR - CDCS MONITOR TASK
* 
* DC  CALLED ROUTINES 
# 
      XREF FUNC DB$COCB C(10);     #BINARY TO OCTAL WITH BLANK FILL#
      XREF PROC DB$DBPU;           #UNLOAD A DATABASE PROCEDURE#
      XREF PROC DB$FLOP;           #GENERATE FLOW POINT#
      XREF PROC DB$MFF;            #RELEASE MEMORY BLOCK (MAPPING CPSL)#
      XREF PROC DB$MSG;            #ISSUE DAYFILE MESSAGE#
      XREF PROC DB$OUEC;           # UNLOAD EXPIRED UNLOCKED OVCAPS # 
      XREF PROC DB$OUAC;           # UNLOAD ALL UNLOCKED OVCAPS # 
      XREF PROC DB$SWPO;           #SWAP OUT TASK TABLES# 
      XREF FUNC DB$SWO;            # SWAP OUT ONE TABLE                #
# 
* DC  NON-LOCAL VARIABLES 
* 
# 
      XREF ARRAY DB$RA0;
        BEGIN 
        ITEM ABSPTR  I(00,42,18);  # POINTER AT ABSOLUTE ADDRESS       #
        ITEM CALLADD I(00,12,18);  # ADDRESS OF CALL IN ENTRY WORD     #
        ITEM NEXTIDL I(00,00,60);  # POINTER TO NEXT IDLE BLOCK        #
        END 
      XREF ITEM CMM$ALF I;         # CMM ALLOCATE FIXED BLOCK AS ITEM  #
      XREF ITEM CMM$SBL I;         # CMM SMALL BLOCK LIMIT  (CMM.SBL)  #
      XREF ITEM CMM$SBM I;         # CMM SMALL BLOCK MAXIMUM SIZE      #
      XREF ITEM FDL$LDC I;         # LOAD CAPSULE ENTRY POINT AS ITEM  #
      XREF ITEM DB$MFRQ;           # SIZE OF THE CURRENT MEMORY REQUEST#
      XREF ITEM DB$MFWA I;         # ADDR OF CURRENT MAPPING CAPSULE   #
# 
 #
# 
*     LOCAL VARIABLES 
# 
      DEF DFTL #11#;               # TABLE LENGTH                      #
  
      ITEM ACLX;                   # ACL INDEX                         #
      ITEM AGE;                    # AGE OF PROCEDURE OR CAPSULE       #
      ITEM CALLNUM;                # OVERFLOW LEVEL - INPUT PARAMETER  #
      ITEM CFL;                    # CURRENT FIELD LENGTH              #
      ITEM CUTOFF;                 # AGE FOR RELEASING MEMORY BLOCKS   #
      ITEM INDEX;                  #LOOP INDEX# 
      ITEM INDEX1;                 #LOOP INDEX# 
      ITEM NOCMMSG C(40) = " CANNOT GET XXXXXX WORDS CM FOR XXXXXXX:";
      ITEM OLDSBL   I = 0;         # OLD SMALL BLOCK LIMIT             #
      ITEM REQSIZE;                #INPUT PARAMETER#
      ITEM SAVEDACL;               #CURRENT ACL POINTER#
      ITEM SAVEDAPL;               #CURRENT APL POINTER#
      ITEM SAVEDASL;               #CURRENT ASL POINTER#
      ITEM SAVEDRSB;               #CURRENT RSB POINTER#
      ITEM SAVEDTQT;               #CURRENT TQT ENTRY#
      SWITCH SEVERITY ,LEVEL1,LEVEL2,LEVEL3,LEVEL4,LEVEL5;
# 
*     EXTERNALLY DEFINED LOCAL VARIABLES
# 
      XDEF ITEM CMMIFL;            # INITIAL CDCS FIELD LENGTH         #
  
      XDEF ITEM CMMSBL = 0;        # SMALL BLOCK LIMIT FROM            #
                                   # CONTROL STATEMENT                 #
      XDEF ITEM CMMSBI = 0;        # SMALL BLOCK BOUNDARY INCREMENT    #
                                   # FROM CONTROL STATEMENT            #
  
      XDEF ARRAY SBITAB [0:DFTL] S(1);  # SMALL BLOCK INCREMENTS TABLE #
        BEGIN 
        ITEM BOUND  I(00,00,60)    # LOWEST BOUNDARY                   #
                  = [DFTL(0),0];   # PRESET THE ENTIRE ARRAY           #
        ITEM BCOUNT I(01,00,60);   # TIMES CROSSED                     #
        END 
 #
* DC  DESCRIPTION 
 #
  
  
#**********************************************************************#
#                                                                      #
#     I N T E R N A L   P R O C E D U R E   -   R E L E A S E .        #
#                                                                      #
#**********************************************************************#
  
      PROC RELEASE(SAVEPTR);
      BEGIN 
  
 #
*     RELEASE - 
*     THIS PROC SCANS A CHAIN OF SAVED BLOCKS AND RETURNS 
*     THEM TO CMM.
* 
*     PARAMETERS
# 
      ITEM SAVEPTR;          #POINTER TO SAVED BLOCK CHAIN# 
# 
*     LOCAL VARIABLES.
 #
      ITEM BLKADDR;          #SCRATCH - ADDRESS OF A BLOCK# 
  
  
  
      BLKADDR = SAVEPTR;
      FOR BLKADDR = BLKADDR WHILE BLKADDR NQ 0
      DO
        BEGIN 
        SAVEPTR = NEXTIDL[BLKADDR]; 
        DB$MFF(BLKADDR);     # RETURN THE BLOCK TO CMM                 #
        BLKADDR = SAVEPTR;
        END 
      RETURN; 
      END 
  
  
#**********************************************************************#
#                                                                      #
#     I N T E R N A L   P R O C E D U R E   -   R E T I R E .          #
#                                                                      #
#**********************************************************************#
  
      PROC RETIRE;
      BEGIN 
 #
*     RETIRE - UNLOAD DATABASE PROCEDURES AND MAPPER CAPSULES THAT HAVE 
*     NOT BEEN REFERENCED WITHIN "CUTOFF" CLOCK CYCLES. 
*     IF THE MAPPER CAPSULE OR THE DBP CAPSULE IS CURRENTLY 
*     IN EXECUTION, IT IS NOT UNLOADED. 
 #
                                   # IF THE CMM.ALF CALL IS FROM FDL   #
                                   # RETURN.                           #
      IF (CALLADD[LOC(CMM$ALF)] GR LOC(FDL$LDC) 
        AND CALLADD[LOC(CMM$ALF)] LS LOC(FDL$LDC) + 500)
      THEN
        BEGIN 
        RETURN; 
  
        END 
      SAVEDACL = P<ACL>;
      SAVEDAPL = P<APL>;
      SAVEDASL = P<ASL>;
      FOR INDEX = SALL STEP -1 UNTIL 0 DO #LOOP THRU SAL ENTRIES# 
        BEGIN 
        P<APL> = SADBPPTR[INDEX]; 
        IF P<APL> NQ 0             # THE DBP LIST IS LOADED.           #
        THEN
          BEGIN 
          FOR INDEX1 = APDBPSZ[0] STEP -1 UNTIL 1 DO #LOOP THRU APL#
            BEGIN 
            IF APEPADD[INDEX1] GR DFMAXDBPERR  #IS PROC LOADED# 
              AND APNUSERS[INDEX1] EQ 0        #IS PROC UNLOADABLE# 
              THEN                             #YES#
              BEGIN 
              AGE = B<42,18>TIMESTAMP - APDBPAGE[INDEX1]; 
              IF AGE LS 0 THEN
                AGE = AGE + 2**18;           #ALLOW FOR TIME WRAPAROUND#
              IF AGE GQ CUTOFF THEN          #IS AGE OVER CUTOFF# 
                BEGIN 
  
                CONTROL IFGR DFFLOP,0;
                  DB$FLOP("CMOH-R1"); 
                CONTROL ENDIF;
  
                DB$DBPU(APWORD0[0],LOC(APDBPNAM[INDEX1])); #YES,UNLOAD# 
                END 
              END 
            END  #INDEX1# 
          END 
        P<ASL> = SAASLPTR[INDEX]; 
        FOR INDEX1 = INDEX1 WHILE P<ASL> NQ 0 DO #LOOP THRU ASL ENTRIES#
          BEGIN 
          P<ACL> = ASACLLOC[0]; 
          FOR ACLX = ACNUMCAP[0] STEP -1 WHILE ACLX GR 0
            AND ASACLNCP[0] NQ 0 DO    #LOOP THRU EACH ACL# 
            BEGIN 
            IF ACCMLOC[ACLX] NQ 0        # IF CAPSULE IS LOADED        #
              AND ACCMLOC[ACLX] NQ DB$MFWA  # AND NOT ACTIVE           #
            THEN
              BEGIN 
              AGE = B<42,18>TIMESTAMP - ACAGECAP[ACLX]; 
              IF AGE LS 0 THEN
                AGE = AGE + 2**18;
              IF AGE GQ CUTOFF THEN           #IS AGE OVER CUTOFF#
                BEGIN                           #YES, UNLOAD IT#
  
                CONTROL IFGR DFFLOP,0;
                  DB$FLOP("CMOH-R2"); 
                CONTROL ENDIF;
  
                DB$MFF(ACCMLOC[ACLX]);
                ACCMLOC[ACLX] = 0;
                ASACLNCP[0] = ASACLNCP[0] - 1;
                END 
              END 
            END  #ACLX# 
          P<ASL> = ASNEXT[0]; 
          END  #INDEX1# 
        END  #INDEX#
      P<ACL> = SAVEDACL;
      P<APL> = SAVEDAPL;
      P<ASL> = SAVEDASL;
      END 
  
  
#**********************************************************************#
#                                                                      #
#     I N T E R N A L   P R O C E D U R E   -   R S B O U T .          #
#                                                                      #
#**********************************************************************#
  
      PROC RSBOUT;
      BEGIN 
 #
*     RSBOUT - SWAP OUT RSB'S AND CST'S 
* 
 #
  
      SAVEDASL = P<ASL>;
      SAVEDRSB = P<RSB>;
                                       # SWAP INACTIVE TASK TABLES     #
      P<TQT> = TQTCHAIN;
      FOR INDEX = INDEX WHILE P<TQT> NQ 0 
      DO
        BEGIN 
        IF TQRCB[0] EQ 0
          AND TQRSB[0] GR 0 
          AND P<TQT> NQ SAVEDTQT
          AND P<TQT> NQ TQTMTR
        THEN
          BEGIN 
          P<RSB> = TQRSB[0];
          IF RSFAGE GR 2
          THEN
            BEGIN 
            RSFAGE[0] = 0;
            DB$SWPO(FALSE); 
            END 
          ELSE
            BEGIN 
            RSFAGE[0] = RSFAGE[0] +1; 
            END 
          END 
        P<TQT> = TQNEXT[0]; 
        END 
                                       # SWAP ELIGIBLE CST TABLES      #
      FOR INDEX = SALL STEP -1 UNTIL 0
      DO
        BEGIN 
        P<ASL> = SAASLPTR[INDEX]; 
        FOR INDEX1 = INDEX1 WHILE P<ASL> NQ 0 
        DO
          BEGIN 
          IF ASNSWP[0] EQ ASNUSERS[0] 
            AND ASCSTLOC[0] GR 0
            AND RCFUNC[0] NQ DFINV
            AND RCFUNC[0] NQ DFVER
          THEN
            BEGIN 
            ASCSTLOC[0] = DB$SWO(ASCSTLOC[0],ASCSTSIZ[0]);
            END 
          P<ASL> = ASNEXT[0]; 
          END 
        END 
      P<ASL> = SAVEDASL;
      P<RSB> = SAVEDRSB;
      P<TQT> = SAVEDTQT;
      RETURN; 
      END 
  
  
  
  
  
  
  
#     B E G I N   D B $ C M O H   E X E C U T A B L E   C O D E .      #
  
  
 #
*     SELECT THE PROPER LEVEL OF CORRECTIVE ACTION, BASED ON THE VALUE
*     OF THE INPUT PARAMETER. 
*     RELEASE ANY IDLE ALT ENTRIES OR IDLE RCB ENTRIES. 
 #
      SAVEDTQT = P<TQT>;
      IF CALLNUM GQ 1 AND CALLNUM LQ 5 THEN 
        GOTO SEVERITY[CALLNUM]; 
      ELSE
        GOTO LEVEL5;
  
  
  
 #
* 
*     FOR CALLNUM = 1, RELEASE ALL PROCEDURES AND CAPSULES THAT HAVE NOT
*     BEEN ACCESSED IN DFRETIRE CLOCK CYCLES. 
*     SWAP OUT OLDEST RSB'S.
 #
  
LEVEL1: 
  
      CONTROL IFGR DFFLOP,0;
        DB$FLOP("CMOH-1");
      CONTROL ENDIF;
  
      IF OLDSBL NQ 0         # IF CMM.SBL WAS TEMPORARILY SET TO HIGH  #
      THEN                   # VALUE, SET IT BACK TO ITS OLD VALUE.    #
        BEGIN 
        CMM$SBL = OLDSBL; 
        OLDSBL = 0; 
        END 
                             # IF A SMALL BLOCK BOUNDARY INCREMENT IS  #
                             # SPECIFIED, ADJUST THE CMM.SBL IF IT IS  #
                             # OUT OF RANGE.                           #
      IF CMMSBI NQ 0
      THEN
        BEGIN 
                             # GET THE CURRENT FIELD LENGTH            #
        CFL = ABSPTR[-ABSPTR[O"65"]]; 
  
        IF CMM$SBL GR CFL 
        THEN                       # REFLECTS A DECREASING FIELD LENGTH#
          BEGIN 
          CMM$SBL = CFL - CMMSBI; 
          END 
        IF CMM$SBL LS CMMIFL
        THEN                       # RETAIN A MINIMUM SBL              #
          BEGIN 
          CMM$SBL = CMMIFL; 
          END 
        IF CMM$SBL GR CMMSBL
        THEN                       # LIMIT SBL TO THE MAXIMUM          #
          BEGIN 
          CMM$SBL = CMMSBL; 
          END 
        END 
  
      CUTOFF = DFRETIRE;
      RETIRE; 
      DB$OUEC;                         # UNLOAD EXPIRED CDCS OVCAPS # 
      RELEASE(IDLEALTP);               # RELEASE IDLE ALT ENTRIES      #
      RELEASE(IDLERCBP);               # RELEASE IDLE RCB ENTRIES      #
      RSBOUT;                          # SWAP OUT A GROUP OF RSB'S.    #
      RCBIC = 0;
      RETURN;                          #END OF LEVEL 1 PROCESSING#
  
  
  
 #
* 
*     FOR CALLNUM = 2, RELEASE ALL LOADED PROCEDURES AND CAPSULES,
*     REGARDLESS OF AGE.
*     SWAP OUT MORE RSB TABLES. 
 #
  
LEVEL2: 
  
      CONTROL IFGR DFFLOP,0;
        DB$FLOP("CMOH-2");
      CONTROL ENDIF;
  
      CUTOFF = 0; 
      RETIRE; 
      DB$OUAC;                         # UNLOAD ALL CDCS OVCAPS     # 
      RSBOUT;                          # SWAP OUT A GROUP OF RSB'S.    #
  
      RETURN;                          #END OF LEVEL 2# 
  
  
  
 #
* 
*     FOR CALLNUM = 3,
*     IF THE REQUEST IS FOR A SMALL BLOCK AND THE SMALL BLOCK LIMIT IS
*     BEING ADJUSTED DYNAMICALLY, ADVANCE THE SMALL BLOCK LIMIT.
*     SWAP OUT MORE RSB TABLES. 
 #
  
LEVEL3: 
  
      CONTROL IFGR DFFLOP,0;
        DB$FLOP("CMOH-3");
      CONTROL ENDIF;
  
      IF CMMSBI NQ 0
        AND REQSIZE LQ CMM$SBM
      THEN                         # ADVANCE THE SMALL BLOCK BOUNDARY  #
        BEGIN 
        CMM$SBL = CMM$SBL + CMMSBI;   # ADD INCREMENT TO CMM.SBL       #
        IF CMM$SBL GR CMMSBL
        THEN                       # DO NOT EXCEED THE MAXIMUM SBL     #
          BEGIN 
          CMM$SBL = CMMSBL; 
          END 
        INDEX = CMM$SBL - BOUND[0]; 
                                   # IF THE NEW BOUNDARY IS WITHIN THE #
                                   # RANGE WHERE BOUNDARY CROSSINGS    #
                                   # ARE BEING COUNTED, ADD ONE TO THE #
                                   # APPROPRIATE GROUP.                #
        IF INDEX GQ 0 
        THEN
          BEGIN 
          INDEX = INDEX / CMMSBI; 
                                   # IF CREATING A NEW GROUP, ADJUST   #
                                   # THE LOWER BOUND UPWARD.           #
                                   # MOVE EACH OF THE COUNTS DOWN TO   #
                                   # ITS NEW LOCATION IN THE ARRAY.    #
  
                                   # KEEP ONE ZERO WORD AS A LIST      #
                                   # TERMINATOR.                       #
          IF INDEX GQ DFTL -1 
          THEN
            BEGIN 
            BOUND[0] = BOUND[0] + CMMSBI; 
            FOR INDEX1 = 1 STEP 1 UNTIL DFTL -1 
            DO
              BEGIN 
              BCOUNT[INDEX1-1] = BCOUNT[INDEX1];
              END 
            INDEX = DFTL -2;
            END 
                                   # ADD ONE TO THE GROUP COUNT        #
          BCOUNT[INDEX] = BCOUNT[INDEX] +1; 
          END 
        END 
      RSBOUT;                          # SWAP OUT A GROUP OF RSB'S.    #
  
      RETURN;                          #END OF LEVEL 3# 
  
  
  
  
 #
* 
*     FOR CALLNUM = 4, ADVANCE CMM$SBL TO THE HIGHEST VALUE.
*     (CMM$SBL IS ANOTHER NAME FOR CMM.SBL) 
*     THIS IS A TEMPORARY RELAXATION OF THE SMALL BLOCK LIMIT.
*     THIS WILL AVOID ABORTING A USER OR EVEN CDCS
*     BECAUSE OF A SMALL BLOCK LIMIT. 
*     SWAP OUT THE LAST OF THE INACTIVE RSB TABLES. 
 #
  
LEVEL4: 
  
      CONTROL IFGR DFFLOP,0;
        DB$FLOP("CMOH-4");
      CONTROL ENDIF;
  
      IF REQSIZE LQ CMM$SBM        # IF ITS A SMALL BLOCK REQUEST      #
      THEN
        BEGIN 
        OLDSBL = CMM$SBL;          # SAVE THE CURRENT BOUNDARY         #
        CMM$SBL = O"377700";       # SET THE SBL TO THE HIGHEST VALUE  #
  
                                   # TWEAK TIMESTAMP SO THAT DB$CMOH   #
                                   # WILL BE CALLED AGAIN ON THE NEXT  #
                                   # DB$MTR EXECUTION.                 #
        TIMESTAMP = (TIMESTAMP LAN LNO (DFRETIRE-1)) + (DFRETIRE-1);
        END 
      RSBOUT;                          # SWAP OUT A GROUP OF RSB'S.    #
  
      RETURN;                          #END OF LEVEL 4# 
  
  
  
 #
* 
*     FOR CALLNUM = 5, ISSUE DIAGNOSTIC AND RETURN FOR CMM ABORT. 
 #
  
LEVEL5: 
  
      CONTROL IFGR DFFLOP,0;
        DB$FLOP("CMOH-5");
      CONTROL ENDIF;
  
      DB$MFRQ = REQSIZE;
      C<12,6>NOCMMSG = DB$COCB(REQSIZE,6);
      C<32,7>NOCMMSG = C<0,7>TQRUID;
      DB$MSG(NOCMMSG);
      RETURN;                          #END OF LEVEL 5# 
      END 
      TERM
