perm filename FS.FAI[S,NET] blob
sn#713574 filedate 1983-05-30 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00008 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 TITLE FS - Free Storage Management Routines
C00004 00003 SUBR FSGET,SIZE Get a block from Free Strorage
C00014 00004 SUBR FSGETZ,SIZE Get and zero a block from Free Strorage
C00015 00005 SUBR FSREL,ADDR Release Free Strorage block
C00022 00006 SUBR FSINIT Initialize Free Strorage
C00024 00007 SUBR CORFULL Print error message about core full
C00025 00008 Local Storage
C00026 ENDMK
C⊗;
TITLE FS - Free Storage Management Routines
COMMENT ⊗
These routines handle the management of free storage. These routines
do the allocation and release of free storage. In addition, it will
incorporate into its structure, buffers obtained by moving JOBFF.
CAUTION: Do not call these routines from user interrupt level unless
interlocks exist (BEGLOK and ENDLOK) and have been properly
initialized.
⊗;
SEARCH TVRHDR ;Macro definitions
.INSERT STRUC.FAI[S,NET] ;Node definitions
↓RET←1
↓TAC←2
IFNDEF TRIVIAL,< TRIVIAL←←3 > ;Minimum size for block
IFNDEF BEGLOK,< DEFINE BEGLOK(X)<>> ;Begin locked region
IFNDEF ENDLOK,< DEFINE ENDLOK(X)<>> ;End locked region
SUBR FSGET,SIZE ;Get a block from Free Strorage
COMMENT β
Calling sequence:
PUSH P,[SIZE] ;Size of block needed
PUSHJ P,FSGET
Returns:
Address of block
Description:
Searches free storage list for suitably large block and returns
it if it is available. Otherwise, it expands core to make it fit.
Calls:
FSINIT
Called by:
Many routines
Side effects:
Alters free storage list. Advances JOBFF if none available.
Destroys:
TAC
β;
THIS←RET ;Address of block being and later returned
SIZ←TAC+1 ;Size of block stored here for speed (also
;reused for other purposes
BEGLOK FSLOK↑ ;Enter interlocked region
PUSHP SIZ
MOVS SIZ,SIZE
TLNE SIZ,740000 ;Too big?
FATAL<Free storage request too big>
COMMENT ⊗ Free storage blocks are limited to a maximum of 37777
words in this implimentation of free storage system. This error
will also occur if a negative size is requested. ⊗;
SKIPN FSTAIL ;Has free storage been set up?
CALL FSINIT ; No, initialize
SKIPN THIS,ROVER ;Is there a free storage list?
JRST NOFS ; No, get it from the top
LOOP: CAMG SIZ,-1(THIS) ;Is this block big enough?
JRST GOTCHA ; Yes, use it!
FSNXT THIS,THIS ;Fetch next element of FS list
CAME THIS,ROVER ;Have all nodes been check?
JRST LOOP ; No, try next one
;No large enough block available, expand core to make one which
;fits
NOFS: MOVE TAC,JOBFF ;Get last known value of JOBFF
SUB TAC,OLDFF ;Has it moved?
JUMPE TAC,JBFFOK ; No, JOBFF is OK
JUMPL TAC,CORDWN ; Yes, but cored reduced. Trouble.
;A buffer has been allocated by someone by expanding JOBFF. Mark the
;space as being used.
;
;Core map at this point
; | |
; | free storage |
; _|__________________|
;FSTAIL --->_|__________________|
;OLDFF ---> | |
; | |
; | system buffer |
; _|__________________|
;JOBFF ---> | |
; | |
TRO TAC,(%FSUSE+%FSTMP) ;Make header for system buffer
MOVSM TAC,@FSTAIL ;Note: We are guaranteed that the
;last block in free storage is not
;avaiable, so we don't worry about
;%FSPRA
;(Even if it doesn't, it only prevents
; the new block from being merged
; from the top)
MOVSI TAC,(%FSUSE) ;Make new top marker
MOVE THIS,JOBFF ;Get pointer to old top of core
AOS JOBFF ;Allocate one word for top marker
;Note: We're about to expand core so
;that JOBFF pointing to NXM doesn't
;hurt, though slightly uncleanily.
MOVEM TAC,(THIS) ;Set marker
MOVEM THIS,FSTAIL ;New TAIL
;Allocate a block from the top of core
;
;Core map at this point
; | |
; | free storage |
; _|__________________|
;FSTAIL --->_|__________________|
;JOBFF ---> | |
; | |
; | |
JBFFOK: HLRZ THIS,SIZ ;Get size for block
ADD THIS,JOBFF ;New top of core
ADDI THIS,1 ;One more to account for marker
;for top of free storage
CAMLE THIS,JOBREL ;Expand core?
JRST[ XCT FSGCORE ;Yes, try to get more core
CALL CORFULL ;Print error message for core full
JRST JBFFOK ] ;Got core, now use it (or retry if
;it failed
;
;Core map at this point
; | |
; | free storage |
; _|__________________|
;FSTAIL --->_|__________________|
;JOBFF ---> | |
; | |
; | |
; | |
;THIS ---> | |
; | |
MOVEM THIS,JOBFF ;Set JOBFF to have block we want
MOVEM THIS,OLDFF ;Remember JOBFF we just made
MOVSI TAC,(%FSUSE) ;Make new top marker
MOVEM TAC,-1(THIS) ;Set top header
OR TAC,SIZ ;Make header word for new block
MOVEM TAC,@FSTAIL ;Just recycle old top marker
SUBI THIS,1 ;Get address of new top marker
EXCH THIS,FSTAIL ;Return old top block and set new
ADDI THIS,1 ;top marker
; | |
; | |
; | free storage |
; _|__________________|
;THIS ---> | |
; | new block |
; _|__________________|
;FSTAIL --->_|__________________|
;JOBFF ---> | |
; | |
; | |
JRST DONE
;JOBFF is lower than we lost saw it
CORDWN:
WARN<JOBFF lower than top of free storage. Data structures may be garbaged>
COMMENT ⊗ Someone unexpectedly moved the pointer the system uses to
make I/O buffers into the middle of the free storage area. If some
file was opened after that, it may have overwritten some of the
data structure. This is most certainly a bug and you may proceed
at your own risk.⊗;
MOVE TAC,OLDFF ;Fix it up for now by just restoring
MOVEM TAC,JOBFF ;JOBFF to its old value
;Found a block which is large enough
GOTCHA: MOVE TAC,-1(THIS) ;See how much of the block is used
SUB TAC,SIZ
CAML TAC,SWTRIV ;It is large enough to worry about?
JRST SPLIT ; Yes, split block into two parts
;Block is of appropriate size to use directly
FSFSZ SIZ,THIS ;Fetch size of block
ADD SIZ,THIS ;Point to next block
MOVSI TAC,(%FSPRA) ;and clear next block's mark that
ANDCAM TAC,(SIZ) ;that this one is free
MOVSI TAC,(%FSUSE) ;Now, we can mark this block as
IORB TAC,-1(THIS) ;in use and also fetch next pointer
FSPRV SIZ,THIS ;Fetch pointer to previous link in
;free block list
;RH SIZ: Next free block
;RH TAC: Previous free block
FSNXTM TAC,SIZ ;Unlink node to be allocated
FSPRVM SIZ,TAC
HRRZM SIZ,ROVER ;Set pointer to next free block
CAIN THIS,(TAC) ;Is this the last block?
SETZM ROVER ; Yes, no longer have a list
JRST DONE
;Block is too big to use directly, split it into two blocks
SPLIT: HLRZ SIZ,TAC ;Move into right half for arithmetic
SUBI SIZ,1 ;operations and account for header
FSFSZM SIZ,THIS ;Set new size of this block
ADDI THIS,1(SIZ) ;Point to new block
FSPSZM SIZ,THIS ;Set trailing size field for free
;block
;Core map at this point
; |__________________|
; | |
; | |
; | free storage |
; _|__________________|
;THIS ---> | |
; | new block |
; _|__________________|
MOVS SIZ,SIZE ;Fetch size of block wanted
TLO SIZ,(%FSPRA+%FSUSE) ;Mark in use and previous block as
;being available
MOVEM SIZ,-1(THIS) ;Set size field in this node
MOVE SIZ,SIZE ;Clear previous block available bit
ADD SIZ,THIS ;in the next block
MOVSI TAC,(%FSPRA)
ANDCAM TAC,(SIZ)
DONE: POPP SIZ ;Restore saved accumulator
ENDLOK FSLOK ;Leave locked region
SUB P,[XWD 2,2]
JRSTF @2(P)
SUBREND FSGET
SUBR FSGETZ,SIZE ;Get and zero a block from Free Strorage
COMMENT β
Calling sequence:
PUSH P,[SIZE] ;Size of block needed
PUSHJ P,FSGETZ
Returns:
Address of block
Description:
Same as FSGET except it zeros the block before returning it
Calls:
FSGET
Called by:
Many routines
Side effects:
(See FSGET)
Destroys:
TAC
β;
CALL FSGET,SIZE
SETZM (RET) ;Clear first word
MOVS TAC,RET ;Make IOWD to do rest
HRRI TAC,1(RET)
ADD RET,SIZE ;Point at last word
BLT TAC,-1(RET) ;Zero rest of block
SUB RET,SIZE ;Restore pointer to block
SUB P,[XWD 2,2]
JRSTF @2(P)
SUBREND FSGETZ
SUBR FSREL,ADDR ;Release Free Strorage block
COMMENT β
Calling sequence:
PUSH P,ADDR ;ADDR points to free storage block
PUSHJ P,FSREL
Returns:
Undefined
Description:
Returns block to free storage system. In detail, if the block
above is free, it is merged with this block. If block below it is
free and merges given block with it if so. Otherwise, the block is
added to the free storage list.
Calls:
Called by:
Many routines
Side effects:
Alters free storage list.
Destroys:
TAC
β;
prints/FSREL needs to check against top
/
THIS←RET ;Address of block being and later returned
SIZ←TAC+1 ;Size of block stored here for speed (also
;reused for other purposes
BEGLOK FSLOK ;Enter interlocked region
PUSHP SIZ ;Save an AC
MOVE THIS,ADDR
HLLZ SIZ,-1(THIS) ;Fetch size and flags
TLZ SIZ,(%FSUSE+%FSMRK+%FSTMP) ;Clear random crud
TLZN SIZ,(%FSPRA) ;Is previous block available?
JRST NOTBLW ; No, not below free
;Core map at this point
; | |
; | |
; | free block |
; _|__________________|
;THIS ---> | |
; | block to free |
; _|__________________|
; | |
; | ??? |
; | |
FSPSZ TAC,THIS ;Fetch size of previous block
MOVN TAC,TAC
ADDI THIS,-1(TAC) ;Point to previous block
ADD SIZ,[XWD 1,0] ;Account for header word
ADDB SIZ,-1(THIS) ;Update and fetch size
HLRZ TAC,SIZ ;Point to next block
ADDI TAC,1(THIS)
MOVEM SIZ,-2(TAC) ;Set block size
MOVSI SIZ,(%FSPRA) ;Set previous block available
ORB SIZ,-1(TAC) ;and also, fetch its size
TLNE SIZ,(%FSUSE) ;Is it in use?
JRST DONE ; Yes, we're done then
;New block and next block need to be merged
;Core map at this point
; _|__________________|
;THIS ---> | |
; | free block |
; _|__________________|
;TAC ---> | |
; | free block |
; | |
MOVEM THIS,ADDR ;Save pointer to lower block
FSPRV THIS,TAC ;Unlink upper block
FSNXT SIZ,TAC
CAMN TAC,ROVER ;Are we unlinking the head of list?
MOVEM SIZ,ROVER ; Yes, advance it to next
FSPRVM THIS,SIZ ;Previous block now sees next block
FSNXTM SIZ,THIS ;Next block now sees previous block
MOVE THIS,ADDR ;Get back pointer to lower block
HLLZ SIZ,-1(TAC) ;Get size of upper block
ADD SIZ,[1B17-%FSPRA] ;Account for header and flush bit
;saying previous block is available
ADDB SIZ,-1(THIS) ;Update size for lower block
HLRZ TAC,SIZ ;Point to next block
ADD TAC,THIS
MOVEM SIZ,-1(TAC) ;Set top size
JRST DONE ;Now, we're finished
;New block and next block need to be merged
;Core map at this point
; _|__________________|
;THIS ---> | |
; | block to free |
; _|__________________|
;TAC ---> | |
; | free block |
; | |
NOTBLW: HLRZ TAC,SIZ ;Check top
ADDI TAC,1(THIS)
MOVEM SIZ,-1(THIS) ;Set size (with tag bits cleared)
MOVEM SIZ,-2(TAC) ;Set size in top while convenient
HLLZ SIZ,-1(TAC) ;Fetch header for next block
TLNE SIZ,(%FSUSE) ;In use?
JRST MRKTOP ; Yes, mark
MOVEM THIS,ROVER ;Will be next block to consider allocating
ADD SIZ,[XWD 1,0] ;Account for header
ADDM SIZ,-1(THIS) ;Update lower size
FSPRV SIZ,TAC ;Fetch previous block in F.S. List
FSPRVM SIZ,THIS ;Copy into lower block
FSNXTM THIS,SIZ ;Make its next pointer see new block
FSNXT SIZ,TAC ;Fetch next block
FSNXTM SIZ,THIS ;Copy into lower block
FSPRVM THIS,SIZ ;Make previous pointer
FSFSZ SIZ,THIS ;Put in size pointer at end of block
ADDI THIS,1(SIZ)
FSPSZM SIZ,THIS ;Set size at top
JRST DONE
MRKTOP: MOVSI SIZ,(%FSPRA) ;Mark previous block available
ORM SIZ,-1(TAC)
SKIPE TAC,ROVER ;Get head of FS list
JRST ADDNOD ; Yes, there is a list
EMPTY: FSNXTM THIS,THIS ;Point to self if empty
FSPRVM THIS,THIS
MOVEM THIS,ROVER ;This node constitutes new freelist
JRST DONE
ADDNOD: FSPRV SIZ,TAC ;Fetch previous block in F.S. List
FSNXTM THIS,SIZ ;Make its next pointer see new block
FSPRVM SIZ,THIS ;Make new block point to previous
FSPRVM THIS,TAC ;Make previous pointer
FSNXTM TAC,THIS ;Make new block point to next
DONE: POPP SIZ ;Save an AC
ENDLOK FSLOK ;leave interlocked region
SUB P,[XWD 2,2]
JRSTF @2(P)
SUBREND FSREL
SUBR FSINIT ;Initialize Free Strorage
COMMENT β
Calling sequence:
PUSHJ P,FSINIT
Returns:
Undefined
Description:
Initializes Free Storage system. Remembers top of free storage
system.
CAUTION: Don't call this with interrupts enabled! (FSGET excepted)
Calls:
Called by:
Initialization, FSGET
Side effects:
Makes free storage list. Advances JOBFF
Destroys:
β;
SKIPA
JRST FSGCOK ;Starting at FSINIT+1 avoids changes to FSGCOR
MOVE RET,[CORE RET,] ;Yes, try to get more core
MOVEM RET,FSGCOR ;Instruction to execute to get more core
FSGCOK: MOVE RET,JOBFF ;Make pointer to top of core
MOVEM RET,FSBEG ;Remember beginning of F.S.
MOVEM RET,FSTAIL
SETZM ROVER ;Clear pointer to next block to examine.
MOVSI RET,(%FSUSE) ;Make a top marker
MOVEM RET,@JOBFF
AOS RET,JOBFF ;Allocate word for marker
MOVEM RET,OLDFF ;Remember what we saw for top of
;core
RETRY: CAMLE RET,JOBREL ;See if core needs to be expanded
JRST[ CORE RET,
CALL CORFULL ;Print core full message
MOVE RET,JOBFF
JRST RETRY ]
INCORE: MOVEI RET,TRIVIAL ;Set trivial block size
MOVSM RET,SWTRIV
POPJ P,
SUBREND FSINIT
;SUBR CORFULL ;Print error message about core full
COMMENT β
Calling sequence:
PUSHJ P,CORFULL
Returns:
Undefined
Description:
Prints error message for core full.
Calls:
Called by:
FSGET,FSINIT
Side effects:
Waits for response from user.
Destroys:
β;
CORFUL: WARN<No core left, will retry>
COMMENT ⊗There was no large enough block in free storage list and
attempt to get more core failed. The fact that you have run out
of core may be indicative of some problem with this program or
what you are asking it to do. ⊗;
POPJ P,
;SUBREND CORFULL
;Local Storage
INTERNAL FSGCOR
INTEGER FSBEG ;Beginning of free storage
INTEGER ROVER ;Pointer to next block to examine
INTEGER FSTAIL ;Pointer to top of free storage
INTEGER SWTRIV ;Swapped trivial block size (smallest
;sized block which will be alllocated)
INTEGER OLDFF ;Copy of JOBFF
INTEGER FSGCOR ;Instruction to execute to get more code
EXTERNAL JOBFF ;First Free location in top of core
END