; =============================================================================
;
; Litos - Buffer array
;
; =============================================================================
CODE_SECTION 32
; ------------- Macro - initialized buffer array head
; %1 = size of one buffer entry, %2 = size of buffer block (must be power of 2)
%macro BUFFER 2
LISTHEAD ; list of free buffer entries
SPINLOCK ; lock of buffer array
dd %1 ; size of one buffer entry (min. 8)
dd %2 ; size of buffer block (power of 2)
dd ~(%2-1) ; block mask (to get block head)
dd (%2-BUFBLOCK_size)/%1 ; number of entries per block
dd NULL ; reserved block (NULL=none)
%endmacro
; -----------------------------------------------------------------------------
; 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
%ifdef SMP
LOCK_Lock (edx+BUFH_Lock) ; lock buffer array lock
%endif
; ------------- Check if list of free entries is empty
LISTTEST edx ; is list empty?
jnz BuffAlloc6 ; list is not empty
; ------------- 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
lea eax,[eax+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
; ------------- 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
; ------------- OK: Unlock buffer array lock
BuffAlloc8:
%ifdef SMP
LOCK_Unlock (edx+BUFH_Lock) ; unlock buffer array lock
%endif
; ------------- Pop registers and clear error flag
popf ; pop flags
clc ; clear error flag
pop ebx ; pop EBX
ret
; ------------- ERROR: Unlock buffer array lock
BuffAlloc9:
%ifdef SMP
LOCK_Unlock (edx+BUFH_Lock) ; unlock buffer array lock
%endif
; ------------- Pop registers and set error flag
popf ; pop flags
stc ; set error flag
pop ebx ; pop EBX
ret
; -----------------------------------------------------------------------------
; Free buffer entry
; -----------------------------------------------------------------------------
; INPUT: EAX = buffer entry to free
; EDX = buffer array head
; OUTPUT: EAX = NULL
; LOCKS: BUFH_Lock, SysMemLock
; -----------------------------------------------------------------------------
; ------------- Push registers
BuffFree: push ebx ; push EBX
pushf ; push flags
cli ; disable interrupts
; ------------- Lock buffer array lock
%ifdef SMP
LOCK_Lock (edx+BUFH_Lock) ; lock buffer array lock
%endif
; ------------- Link entry into list of free buffer entries
LISTADD edx,eax,ebx ; add entry into list of free entries
; ------------- Decrease number of used entries in block head
and eax,[edx+BUFH_BlockMask] ; EAX <- block head
dec dword [eax+BUFB_Used] ; decrease used counter
jnz BuffFree8 ; block have not been freed
; ------------- Check if there is any reserved block
xchg eax,[edx+BUFH_Reserve] ; EAX <- reserved block
or eax,eax ; is reserved block valid?
jz BuffFree8 ; reserve block is not valid
; ------------- Push registers 2
push eax ; push EAX
push ecx ; push ECX
push esi ; push ESI
push esi ; push EDI
; ------------- Release list of free entries
mov ecx,[edx+BUFH_Entries] ; ECX <- number of entries
lea eax,[eax+BUFB_Data] ; EAX <- first entry
mov edi,[edx+BUFH_EntrySize] ; EDI <- entry size
BuffFree4: LISTDEL eax,ebx,esi ; delete entry
add eax,edi ; EAX <- next entry
loop BuffFree4 ; link next entry
; ------------- Pop registers 2
pop edi ; pop EDI
pop esi ; pop ESI
pop ecx ; pop ECX
pop eax ; pop EAX
; ------------- Deallocate old block
call SysMemFree ; deallocate old block
; ------------- Unlock buffer array lock
BuffFree8:
%ifdef SMP
LOCK_Unlock (edx+BUFH_Lock) ; unlock buffer array lock
%endif
; ------------- Pop registers
popf ; pop flags
pop ebx ; pop EBX
xor eax,eax ; EAX <- 0, invalid pointer
ret
|