;
; suballoc.s
;
; Handling of requests for small link blocks
;
;  1994-1998 Straylight
;

;----- Licensing note -------------------------------------------------------
;
; This file is part of Straylight's Dynamic Linking System (SDLS)
;
; SDLS is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2, or (at your option)
; any later version.
;
; SDLS is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with SDLS.  If not, write to the Free Software Foundation,
; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

;----- Standard header ------------------------------------------------------

		GET	libs:swis
		GET	libs:header

;----- External dependencies ------------------------------------------------

		GET	sh.wSpace
		GET	sh.linkblock

;----- Word to the wise -----------------------------------------------------
;
; The DLink manager requires lots of small blocks for linked lists and
; things.  To avoid mangling the RMA, we allocate very big blocks and then
; split them up into littler ones.  The format of the very big blocks is as
; follows:
;
;    +0  link to next one
;    +4  [data]
;
; The data blocks are allocated such that they are just big enough for the
; data -- the caller must specify the actual size of the block when freeing.
; Freed blocks are *not* returned to the OS.  There isn't much point -- it
; would take ages, and they're only going to be allocated again anyway.  All
; big blocks are returned to the OS when the module quits.

;----- Magic numbers --------------------------------------------------------

bigBlockSize	EQU	1024*lk_strSize+4	;Allocate 1024 small blocks
						;at a time

;----- Main code ------------------------------------------------------------

		AREA	|DLLM$$Code|,CODE,READONLY

		GBLL	debug
debug		SETL	{FALSE}

; --- sub_alloc ---
;
; On entry:	--
; On exit:	R0 == pointer to block allocated, or 0 if no memory
;

		EXPORT	sub_alloc
sub_alloc	ROUT

		STMFD	R13!,{R1-R4,R14}
		LDR	R0,sub__free		;Get the free list offset
		CMP	R0,#0			;Are there any free blocks?
		BEQ	%01sub_alloc		;No -- better allocate some

00sub_alloc	LDR	R2,[R0]			;Get next pointer from block
		STR	R2,sub__free		;This is now first free block
		LDMFD	R13!,{R1-R4,PC}^	;Restore registers and return

01sub_alloc	MOV	R0,#6			;Allocate some more from RMA
		LDR	R3,=bigBlockSize	;Allocate correct size
		SWI	XOS_Module		;Allocate the block
		LDMVSFD	R13!,{R1-R4,PC}		;Return on an error

		LDR	R4,sub__blocks		;Load the pointer
		STR	R4,[R2]			;Store in next ptr of new blk
		STR	R2,sub__blocks		;And link new block into list

		MOV	R0,#0			;Next free pointer start at 0
		SUB	R3,R3,#lk_strSize	;Offset to next field of sub
02sub_alloc	STR	R0,[R2,R3]		;Store in next field
		ADD	R0,R2,R3		;Point to that block
		SUBS	R3,R3,#lk_strSize	;Point to previous block
		BGT	%02sub_alloc		;If more to do, continue...
		B	%00sub_alloc		;Then allocate as normal

		LTORG

; --- sub_free ---
;
; On entry:	R0 == pointer to block
; On exit:	R0 corrupted

		EXPORT	sub_free
sub_free	ROUT

		STMFD	R13!,{R14}		;Preserve registers
		LDR	R14,sub__free		;Get current first block
		STR	R14,[R0]		;Store in newly freed block
		STR	R0,sub__free		;And insert new block in list
		LDMFD	R13!,{PC}^		;Oh, and return to caller

		LTORG

; --- sub_die ---
;
; On entry:	--
; On exit:	R0 corrupted

		EXPORT	sub_die
sub_die		ROUT

		STMFD	R13!,{R1-R3,R14}	;Preserve used registers
		MOV	R3,#0			;No errors yet
		LDR	R2,sub__blocks		;Point to list of blocks
		MOV	R0,#0			;Blank out bigblock pointer
		STR	R0,sub__blocks		;In case it fails a bit
		STR	R0,sub__free
00sub_die	CMP	R2,#0			;Are we at the end?
		BEQ	%01sub_die		;Yes -- leave the loop
		LDR	R1,[R2]			;Get next pointer right now
		MOV	R0,#7			;Free memory
		SWI	XOS_Module		;Free the block up
		MOVVS	R3,R0			;Remember the error, if any
		MOV	R2,R1			;Move on to next block
		B	%00sub_die		;And try again

01sub_die	MOVS	R0,R3			;Copy the error pointer back
		LDMFD	R13!,{R1-R3,R14}	;Restore the other registers
		ORRNES	PC,R14,#V_flag		;Set error indicator if reqd
		BICS	PC,R14,#V_flag		;Otherwise clear it

		LTORG

;----- That's all folks -----------------------------------------------------

		END
