COMPACT: { COMPACT makes use of the following externally- { defined routines: { RELEASE(M_NODE) - M_NODE is removed from the doubly- { linked list of m_nodes referencing memory and placed { on the available list. { GET_MNODE() - Fetches a new m_node from the available { list. { MOVE_MEMORY(SADDR,DADDR,LENGTH) - Moves LENGTH bytes from { address SADDR to DADDR. The routine handles the possibility { of overlapping regions. CURRENT_BASE:=0; CURRENT_LENGTH:=0; SAVED_MNODE:=0; DIRTY:=0; PARAS_FREED:=0; PREVIOUS_MNODE:=0; { Start with first m-node in list. { INUSE_LIST points to the head of the { doubly-linked list of m_nodes that { actually reference memory. CURRENT_MNODE:=INUSE_LIST; REPEAT IF high bit of CURRENT_MNODE's NEXT link is set THEN BEGIN { This block is in use. See if it's locked. IF high bit of CURRENT_MNODE's PREVIOUS link is set THEN BEGIN { This block is locked. See if DIRTY is { set. If so, the contents of CURRENT_BASE { and CURRENT_LENGTH must be written into { an m-node. IF DIRTY=1 THEN BEGIN IF SAVED_MNODE<>0 THEN RELEASE(SAVED_MNODE); NEW_MNODE:=GET_MNODE(); NEW_MNODE's BASE field := CURRENT_BASE; NEW_MNODE's LENGTH field := CURRENT_LENGTH; CURRENT_BASE:=0; CURRENT_LENGTH:=0; { NEW_MNODE must now be attached to the { list preceding CURRENT_MNODE. NEW_MNODE's NEXT link := CURRENT_MNODE; NEW_MNODE's PREVIOUS link := CURRENT_MNODE's PREVIOUS link; CURRENT_MNODE's PREVIOUS link := NEW_MNODE; TEMP_MNODE := NEW_MNODE's PREVIOUS link; IF TEMP_MNODE = 0 THEN { NEW_MNODE is the head of the list. INUSE_LIST := NEW_MNODE; ELSE TEMP_MNODE's NEXT link := NEW_MNODE; DIRTY:=0; END ELSE BEGIN { This block is not locked. { Do we need to move it? IF (CURRENT_BASE<>0) OR (CURRENT_LENGTH<>0) THEN BEGIN SOURCE:=CURRENT_MNODE's BASE field; DESTINATION:=CURRENT_BASE; LENGTH:=CURRENT_MNODE'S LENGTH field; MOVE_MEMORY(SOURCE, DESTINATION, LENGTH); CURRENT_MNODE'S base field := CURRENT_BASE; CURRENT_BASE:= CURRENT_BASE + LENGTH; DIRTY:=1; END END END ELSE BEGIN { This m-node references a free block. { If there is anything in CURRENT_BASE or { CURRENT_LENGTH, release the m-node saved { in SAVED_MNODE and CURRENT_MNODE becomes { the new SAVED_MNODE. IF (CURRENT_BASE<>0) OR (CURRENT_LENGTH<>0) THEN BEGIN RELEASE(SAVED_MNODE); CURRENT_MNODE's BASE field := CURRENT_BASE; CURRENT_LENGTH := CURRENT_LENGTH + CURRENT_MNODE's length field; CURRENT_MNODE's LENGTH field := CURRENT_LENGTH; IF CURRENT_LENGTH > PARAS_FREED THEN PARAS_FREED := CURRENT_LENGTH; END ELSE { If there's nothing in CURRENT_BASE or { CURRENT_LENGTH, then this is the first free { memory block of this partition. BEGIN CURRENT_LENGTH := CURRENT_MNODES's LENGTH field; IF CURRENT_LENGTH > PARAS_FREED THEN PARAS_FREED := CURRENT_LENGTH; CURRENT_BASE := CURRENT_MNODE's BASE field; END SAVED_MNODE := CURRENT_MNODE; DIRTY := 0; END PREVIOUS_MNODE := CURRENT_MNODE; CURRENT_MNODE := CURRENT_MNODE's NEXT field; { This is the end of the REPEAT loop. UNTIL (CURRENT_MNODE = 0); { Pick up any straggling free memory. IF DIRTY=1 THEN BEGIN RELEASE(SAVED_MNODE); CURRENT_MNODE:= GET_MNODE(); CURRENT_MNODE's BASE field := CURRENT_BASE; CURRENT_MNODE's LENGTH field := CURRENT_LENGTH; CURRENT_MNODE's NEXT field := 0; CURRENT_MNODE's PREVIOUS field := PREVIOUS_MNODE; PREVIOUS_MNODE's NEXT field := CURRENT_MNODE; END { Return the size in paragraphs of the largest { block freed. RETURN(PARAS_FREED);