📄 shmalloc.asm
字号:
; SHMALLOC.ASM
;
; This TSR sets up a dynamic shared memory system.
;
; This TSR checks to make sure there isn't a copy already active in
; memory. When removing itself from memory, it makes sure there are
; no other interrupts chained into INT 2Fh before doing the remove.
;
;
;
; The following segments must appear in this order and before the
; Standard Library includes.
ResidentSeg segment para public 'Resident'
ResidentSeg ends
SharedMemory segment para public 'Shared'
SharedMemory ends
EndResident segment para public 'EndRes'
EndResident ends
.xlist
.286
include stdlib.a
includelib stdlib.lib
.list
; Resident segment that holds the TSR code:
ResidentSeg segment para public 'Resident'
assume cs:ResidentSeg, ds:nothing
NULL equ 0
; Data structure for an allocated data region.
;
; Key- user supplied ID to associate this region with a particular set
; of processes.
;
; Next- Points at the next allocated block.
; Prev- Points at the previous allocated block.
; Size- Size (in bytes) of allocated block, not including header structure.
Region struct
key word ?
next word ?
prev word ?
blksize word ?
Region ends
Startmem equ Region ptr [0]
AllocatedList word 0 ;Points at chain of alloc'd blocks.
FreeList word 0 ;Points at chain of free blocks.
; Int 2Fh ID number for this TSR:
MyTSRID byte 0
byte 0 ;Padding so we can print it.
; PSP is the psp address for this program.
PSP word 0
OldInt2F dword ?
; MyInt2F- Provides int 2Fh (multiplex interrupt) support for this
; TSR. The multiplex interrupt recognizes the following
; subfunctions (passed in AL):
;
; 00h- Verify presence. Returns 0FFh in AL and a pointer
; to an ID string in es:di if the
; TSR ID (in AH) matches this
; particular TSR.
;
; 01h- Remove. Removes the TSR from memory.
; Returns 0 in AL if successful,
; 1 in AL if failure.
;
; 11h- shmalloc CX contains the size of the block
; to allocate.
; DX contains the key for this block.
; Returns a pointer to block in ES:DI
; and size of allocated block in CX.
; Returns an error code in AX. Zero
; is no error, one is "key already
; exists," two is "insufficient
; memory for request."
;
; 12h- shmfree DX contains the key for this block.
; This call frees the specified block
; from memory.
;
; 13h- shminit Initializes the shared memory system
; freeing all blocks currently in
; use.
;
; 14h- shmattach DX contains the key for a block.
; Search for that block and return
; its address in ES:DI. AX contains
; zero if successful, three if it
; cannot locate a block with the
; specified key.
MyInt2F proc far
assume ds:nothing
cmp ah, MyTSRID ;Match our TSR identifier?
je YepItsOurs
jmp OldInt2F
; Okay, we know this is our ID, now check for a verify, remove, or
; return segment call.
YepItsOurs: cmp al, 0 ;Verify Call
jne TryRmv
mov al, 0ffh ;Return success.
lesi IDString
iret ;Return back to caller.
IDString byte "Dynamic Shared Memory TSR",0
TryRmv: cmp al, 1 ;Remove call.
jne Tryshmalloc
; See if we can remove this TSR:
push es
mov ax, 0
mov es, ax
cmp word ptr es:[2Fh*4], offset MyInt2F
jne TRDone
cmp word ptr es:[2Fh*4 + 2], seg MyInt2F
je CanRemove ;Branch if we can.
TRDone: mov ax, 1 ;Return failure for now.
pop es
iret
; Okay, they want to remove this guy *and* we can remove it from memory.
; Take care of all that here.
assume ds:ResidentSeg
CanRemove: push ds
pusha
cli ;Turn off the interrupts while
mov ax, 0 ; we mess with the interrupt
mov es, ax ; vectors.
mov ax, cs
mov ds, ax
mov ax, word ptr OldInt2F
mov es:[2Fh*4], ax
mov ax, word ptr OldInt2F+2
mov es:[2Fh*4 + 2], ax
; Okay, one last thing before we quit- Let's give the memory allocated
; to this TSR back to DOS.
mov ds, PSP
mov es, ds:[2Ch] ;Ptr to environment block.
mov ah, 49h ;DOS release memory call.
int 21h
mov ax, ds ;Release program code space.
mov es, ax
mov ah, 49h
int 21h
popa
pop ds
pop es
mov ax, 0 ;Return Success.
iret
; Stick BadKey here so that it is close to its associated branch (from below).
;
; If come here, we've discovered an allocated block with the
; specified key. Return an error code (AX=1) and the size of that
; allocated block (in CX).
BadKey: mov cx, [bx].Region.BlkSize
mov ax, 1 ;Already allocated error.
pop bx
pop ds
iret
; See if this is a shmalloc call.
; If so, on entry -
; DX contains the key.
; CX contains the number of bytes to allocate.
;
; On exit:
;
; ES:DI points at the allocated block (if successful).
; CX contains the actual size of the allocated block (>=CX on entry).
; AX contains error code, 0 if no error.
Tryshmalloc: cmp al, 11h ;shmalloc function code.
jne Tryshmfree
; First, search through the allocated list to see if a block with the
; current key number already exists. DX contains the requested key.
assume ds:SharedMemory
assume bx:ptr Region
assume di:ptr Region
push ds
push bx
mov bx, SharedMemory
mov ds, bx
mov bx, ResidentSeg:AllocatedList
test bx, bx ;Anything on this list?
je SrchFreeList
SearchLoop: cmp dx, [bx].Key ;Key exist already?
je BadKey
mov bx, [bx].Next ;Get next region.
test bx, bx ;NULL?, if not, try another
jne SearchLoop ; entry in the list.
; If an allocated block with the specified key does not already exist,
; then try to allocate one from the free memory list.
SrchFreeList: mov bx, ResidentSeg:FreeList
test bx, bx ;Empty free list?
je OutaMemory
FirstFitLp: cmp cx, [bx].BlkSize ;Is this block big enough?
jbe GotBlock
mov bx, [bx].Next ;If not, on to the next one.
test bx, bx ;Anything on this list?
jne FirstFitLp
; If we drop down here, we were unable to find a block that was large
; enough to satisfy the request. Return an appropriate error
OutaMemory: mov cx, 0 ;Nothing available.
mov ax, 2 ;Insufficient memory error.
pop bx
pop ds
iret
; If we find a large enough block, we've got to carve the new block
; out of it and return the rest of the storage to the free list. If the
; free block is at least 32 bytes larger than the requested size, we will
; do this. If the free block is less than 32 bytes larger, we will simply
; give this free block to the requesting process. The reason for the
; 32 bytes is simple: We need eight bytes for the new block's header
; (the free block already has one) and it doesn't make sense to fragment
; blocks to sizes below 24 bytes. That would only increase processing time
; when processes free up blocks by requiring more work coalescing blocks.
GotBlock: mov ax, [bx].BlkSize ;Compute difference in size.
sub ax, cx
cmp ax, 32 ;At least 32 bytes left?
jbe GrabWholeBlk ;If not, take this block.
; Okay, the free block is larger than the requested size by more than 32
; bytes. Carve the new block from the end of the free block (that way
; we do not have to change the free block's pointers, only the size.
mov di, bx
add di, [bx].BlkSize ;Scoot to end, minus 8
sub di, cx ;Point at new block.
sub [bx].BlkSize, cx ;Remove alloc'd block and
sub [bx].BlkSize, 8 ; room for header.
mov [di].BlkSize, cx ;Save size of block.
mov [di].Key, dx ;Save key.
; Link the new block into the list of allocated blocks.
mov bx, ResidentSeg:AllocatedList
mov [di].Next, bx
mov [di].Prev, NULL ;NULL previous pointer.
test bx, bx ;See if it was an empty list.
je NoPrev
mov [bx].Prev, di ;Set prev ptr for old guy.
NoPrev: mov ResidentSeg:AllocatedList, di
RmvDone: add di, 8 ;Point at actual data area.
mov ax, ds ;Return ptr in es:di.
mov es, ax
mov ax, 0 ;Return success.
pop bx
pop ds
iret
; If the current free block is larger than the request, but not by more
; that 32 bytes, just give the whole block to the user.
GrabWholeBlk: mov di, bx
mov cx, [bx].BlkSize ;Return actual size.
cmp [bx].Prev, NULL ;First guy in list?
je Rmv1st
cmp [bx].Next, NULL ;Last guy in list?
je RmvLast
; Okay, this record is sandwiched between two other in the free list.
; Cut it out from among the two.
mov ax, [bx].Next ;Save the ptr to the next
mov bx, [bx].Prev ; item in the prev item's
mov [bx].Next, ax ; next field.
mov ax, bx ;Save the ptr to the prev
mov bx, [di].Next ; item in the next item's
mov [bx].Prev, bx ; prev field.
jmp RmvDone
; The block we want to remove is at the beginning of the free list.
; It could also be the only item on the free list!
Rmv1st: mov ax, [bx].Next
mov FreeList, ax ;Remove from free list.
jmp RmvDone
; If the block we want to remove is at the end of the list, handle that
; down here.
RmvLast: mov bx, [bx].Prev
mov [bx].Next, NULL
jmp RmvDone
assume ds:nothing, bx:nothing, di:nothing
; This code handles the SHMFREE function.
; On entry, DX contains the key for the block to free. We need to
; search through the allocated block list and find the block with that
; key. If we do not find such a block, this code returns without doing
; anything. If we find the block, we need to add its memory to the
; free pool. However, we cannot simply insert this block on the front
; of the free list (as we did for the allocated blocks). It might
; turn out that this block we're freeing is adjacent to one or two
; other free blocks. This code has to coalesce such blocks into
; a single free block.
Tryshmfree: cmp al, 12h
jne Tryshminit
; First, search the allocated block list to see if we can find the
; block to remove. If we don't find it in the list anywhere, just return.
assume ds:SharedMemory
assume bx:ptr Region
assume di:ptr Region
push ds
push di
push bx
mov bx, SharedMemory
mov ds, bx
mov bx, ResidentSeg:AllocatedList
test bx, bx ;Empty allocated list?
je FreeDone
SrchList: cmp dx, [bx].Key ;Search for key in DX.
je FoundIt
mov bx, [bx].Next
test bx, bx ;At end of list?
jne SrchList
FreeDone: pop bx
pop di ;Nothing allocated, just
pop ds ; return to caller.
iret
; Okay, we found the block the user wants to delete. Remove it from
; the allocated list. There are three cases to consider:
; (1) it is at the front of the allocated list, (2) it is at the end of
; the allocated list, and (3) it is in the middle of the allocated list.
FoundIt: cmp [bx].Prev, NULL ;1st item in list?
je Free1st
cmp [bx].Next, NULL ;Last item in list?
je FreeLast
; Okay, we're removing an allocated item from the middle of the allocated
; list.
mov di, [bx].Next ;[next].prev := [cur].prev
mov ax, [bx].Prev
mov [di].Prev, ax
xchg ax, di
mov [di].Next, ax ;[prev].next := [cur].next
jmp AddFree
; Handle the case where we are removing the first item from the allocation
; list. It is possible that this is the only item on the list (i.e., it
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -