Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

Obsah / Utility / BUFFER / Alokace nové položky z pole bufferů

Zdrojový kód: INCLUDE\UTIL\BUFFER.INC, UTIL\BUFFER.ASM


Alokace nové položky z pole bufferů

K alokaci nové položky z pole bufferů slouží funkce BuffAlloc. Jako vstupní parametr je funkci předán ukazatel na záhlaví pole bufferů v registru EDX. Je-li nová položka úspěšně alokována, je její adresa navrácena v registru EAX a příznak CF je vynulován (tj. je podmínka NC). Pokud se položku nepodařilo alokovat (z důvodu nedostatku systémové paměti), je obsah registru EAX vynulován a příznak CF je nastavený (tj. je podmínka CY).


; -----------------------------------------------------------------------------
;                          Allocate buffer entry
; -----------------------------------------------------------------------------
; INPUT:	EDX = buffer array head
; OUTPUT:	EAX = new buffer entry (or EAX = NULL if CY)
;		CY = memory error (EAX = NULL)
; LOCKS:	BUFH_Lock, SysMemLock
; -----------------------------------------------------------------------------

; ------------- Push registers

BuffAlloc:	push	ebx		; push EBX
		pushf			; push flags
		cli			; disable interrupts

; ------------- Lock buffer array lock

		LOCK_Lock (edx+BUFH_Lock) ; lock buffer array lock

Na začátku funkce je uchován obsah registru EBX a obsah registru příznaků, je zakázáno přerušení a uzamknut zámek bufferu BUFH_Lock. Tím je zabráněno souběhu operací mezi více procesory nebo souběhu s obsluhou přerušení.


; ------------- Check if list of free entries is empty

		LISTTEST edx		; is list empty?
		jnz	BuffAlloc6	; list is not empty

Je proveden test seznamu volných alokačních položek. Je-li k dispozici nějaká volná alokační položka, přejde se k obsluze vyjmutí položky ze seznamu volných položek.


; ------------- Allocate new buffer block

		mov	eax,[edx+BUFH_BlockSize] ; EAX <- block size
		call	SysMemAlloc	; allocate system memory block
		jc	BuffAlloc9	; memory error (EAX = NULL)

; ------------- Push registers 2

		push	ecx		; push ECX
		push	esi		; push ESI

; ------------- Initialize head of the block (no entry used)

		and	dword [eax+BUFB_Used],byte 0 ; no entry used

; ------------- Initialize list of free entries

		mov	ecx,[edx+BUFH_Entries] ; ECX <- number of entries
		add	eax,byte BUFB_Data ; EAX <- first entry
		mov	esi,[edx+BUFH_EntrySize] ; EDI <- entry size
BuffAlloc4:	LISTLAST edx,eax,ebx	; add new entry into end of list
		add	eax,esi		; EAX <- next entry
		loop	BuffAlloc4	; link next entry

; ------------- Pop registers 2

		pop	esi		; pop ESI
		pop	ecx		; pop ECX

Není-li k dispozici žádná volná alokační položka, je nutné alokovat od systému nový alokační block. Z proměnné BUFH_BlockSize se do registru EAX načte velikost alokačního bloku a vyžádá se od systému přidělení takového bloku (SysMemAlloc). Při neúspěchu funkce předčasně skončí s příznakem chyby paměti (registr EAX v tom případě obsahuje 0).

Po úspěšné alokaci paměti se bude pokračovat začleněním nových alokačních položek do řetězce volných položek. Uchovají se registry ECX a ESI a vynuluje se čítač použitých položek BUFB_Used. Do registru ECX se připraví počet položek, které bude potřeba inicializovat (z proměnné BUFH_Entries), registr EAX se posune na začátek první alokované položky a do registru ESI se připraví velikost jedné položky (z proměnné BUFH_EntrySize). V cyklu se potom každá z položek připojí na konec seznamu volných položek pomocí makra LISTLAST. Registr EDX obsahuje záhlaví seznamu volných položek (protože záhlaví seznamu je umístěno na začátku popisovače pole bufferů), registr EAX obsahuje nově přidávanou položku a registr EBX je pracovní registr. Po přidání všech položek do seznamu jsou obnoveny obsahy registrů ECX a ESI.


; ------------- Get next entry from the list of free buffer entries

BuffAlloc6:	mov	eax,[edx+LIST_Next] ; EAX <- first entry in the list
		LISTDELPREV eax,edx,ebx	; delete list entry

; ------------- Increase number of used entries

		mov	ebx,[edx+BUFH_BlockMask] ; EBX <- block mask
		and	ebx,eax		; EBX <- block head
		inc	dword [ebx+BUFB_Used] ; increase used counter

; ------------- Release block from reserved block

		cmp	ebx,[edx+BUFH_Reserve] ; is it reserve block?
		jne	BuffAlloc8	; it is not reserve block
		and	dword [edx+BUFH_Reserve],byte 0 ; invalid block

Je-li k dispozici nějaká volná alokační položka, je ze seznamu volných položek uvolněna první položka pomocí makra LISTDELPREV. Registr EAX obsahuje ukazatel na první položku seznamu (která bude uvolněna), registr EDX obsahuje ukazatel na záhlaví seznamu volných položek (je shodný s ukazatelem na pole bufferů) a registr EBX je přechodný registr.

Po uvolnění alokační položky ze seznamu volných položek je pomocí masky BUFH_BlockMask odvozena z adresy položky (v registru EAX) adresa začátku alokačního bloku a inkrementován počet použitých položek BUFB_Used.

Jedná-li se o alokační blok, který byl uchován jako rezervní blok, je položka BUFH_Reserve vynulována, protože tento blok již nesmí být zrušen.


; ------------- OK: Unlock buffer array lock

BuffAlloc8:	LOCK_Unlock (edx+BUFH_Lock) ; unlock buffer array lock

; ------------- Pop registers and clear error flag

		popf			; pop flags
		clc			; clear error flag
		pop	ebx		; pop EBX
		ret

; ------------- ERROR: Unlock buffer array lock

BuffAlloc9:	LOCK_Unlock (edx+BUFH_Lock) ; unlock buffer array lock

; ------------- Pop registers and set error flag

		popf			; pop flags
		stc			; set error flag
		pop	ebx		; pop EBX
		ret

Při ukončení funkce je zámek BUFH_Lock opět odemknut, navrácením registru příznaků je případně opět povoleno přerušení, je navrácen obsah registru EBX. Protože se během navrácení registru příznaků neuchová nastavení příznaku CF, použijí se 2 varianty ukončení funkce - jedna s vynulovaným příznakem chyby a jedna s nastaveným příznakem.


Obsah / Utility / BUFFER / Alokace nové položky z pole bufferů