home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
581a.lha
/
MemMan_v2.0
/
MemMan.asm
< prev
next >
Wrap
Assembly Source File
|
1991-12-04
|
9KB
|
301 lines
********************************************************************************
*
* MemMan
* Version 2.0
* Low-Memory manager
* Copyright (C) 1991 Bryan Ford
*
*
* This source code may be freely distributed as long as it is complete (see
* MemMan.doc for the required files), all of the files are unmodified, and no
* charge is made for such distribution other than a small fee to cover the
* cost of copying (no profit may be made through distribution of this
* program). You may modify this code for your own personal use, but you may
* not distribute modified versions. (Just send your improvements back to me
* - I'll incorporate them in the master, of course giving credit to you, and
* that way we won't have hundreds of different versions floating around.)
*
* You may use the object code derived from this (or your own modified version
* of this) source code in your own public domain, freeware, or shareware
* programs (programs that are distributed on similar terms to this source
* code), as long as you mention the use of MemMan and its author (me)
* somewhere in your documentation. You do not need to obtain any kind of
* license in this case.
*
* If you want to distribute MemMan (or any modified variation of it), in
* either source or object form, with a commercial package, you must obtain my
* written permission. (Don't worry, I'm not starving at this point - a
* license will be very cheap, most likely consisting simply of a copy of the
* program you're using it in.)
*
********************************************************************************
*
* Thanks to Michael Sinz of Commodore for his valuable suggestions for improving
* this code and making it more compatible with future versions of the OS.
*
* Also, special thanks to David Le Blanc for the library version and the test
* program.
*
********************************************************************************
*
* Assemble with A68k version >2.71.
*
include "exec/types.i"
include "exec/lists.i"
include "exec/ables.i"
include "exec/memory.i"
include "exec/libraries.i"
include "exec/semaphores.i"
include "exec/funcdef.i"
include "exec/exec_lib.i"
include "bry/macros.i"
include "bry/memman.i"
STRUCTURE MemManSem,SS_SIZE ; SignalSemaphore
UWORD mms_AppCount ; Number of apps using MemMan now
STRUCT mms_MMList,MLH_SIZE ; List we link MMNodes onto
LABEL mms_Code ; Copied MemMan library code
; Structure is continued farther down... (hehe)
code text
xdef MMInit,MMFinish,MMAddNode,MMRemNode
xdef _MMInit,_MMFinish,_MMAddNode,_MMRemNode
* This code is copied into the global MemManSem structure.
* The first six bytes are overwritten with a JMP instruction
* whenever MemMan is not in use.
* Immediately after that is the old AllocMem vector
* (last part of the JSR instruction).
* Yup, self-modifying code - isn't it beautiful? :-)
* This makes each AllocMem() call slightly faster and should be fine if we
* are very careful of caching (which we are). Since the only self-modifying
* code we use is in MEMF_PUBLIC memory, there should be no virtual or protected
* memory problems either.
codest:
push d0/d1 ; Save registers (4 bytes of code)
jsrinst:
jsr $12345678 ; Call regular AllocMem() (2 + 4 bytes)
tst.l d0
bz.s \failed
addq.l #8,sp ; Succeeded on the first try
rts
\failed:
push a2-a3
move.l codest-mms_Code+mms_MMList+LH_HEAD(pc),a2
move.l jsrinst+2(pc),a3
FORBID
\retry:
move.l LN_SUCC(a2),d1 ; Traverse the list forwards
bz.s \fin ; (kill HIGHEST priority nodes first)
move.l mmn_GetRidFunc(a2),a1 ; Call the GetRidFunc
move.l mmn_GetRidData(a2),a0
move.l d1,a2 ; Find next node BEFORE call
movem.l 8(sp),d0/d1
jsr (a1)
movem.l 8(sp),d0/d1 ; Try allocating again
jsr.l (a3)
tst.l d0
bz.s \retry
\fin:
push d0-d1/a0-a1 ; Some nasty apps rely on d1/a0/a1...
PERMIT
pop d0-d1/a0-a1/a2-a3
addq.l #8,sp ; Pop AllocMem args off stack
rts
semname:
dc.b "MemMan2",0
ds.w 0
codefin:
; Continuation of MemManSem structure (now that we know the code size)
STRUCT mms_Code_def2,(codefin-codest)
LABEL mms_SIZEOF
*** Initialize MemMan - patches AllocMem()
* Returns:
* d0 = Nonzero if successful, zero if failed
MMInit:
_MMInit:
apush
move.l 4,a6
lea semname(pc),a1 ; See if the semaphore already exists
jsr _LVOFindSemaphore(a6)
move.l d0,semaphore
bnz \oldsem
; There is the VERY slight chance we could get two MemMan semaphores
; at once. Who cares? Nothing terrible would happen anyway.
\newsem:
move.l #mms_SIZEOF,d0 ; Allocate the public memory block
move.l #MEMF_PUBLIC!MEMF_CLEAR,d1
jsr _LVOAllocMem(a6)
move.l d0,semaphore
bz \out
move.l d0,a5
lea mms_MMList(a5),a0 ; Initialize the data area
NEWLIST a0
move.w #1,mms_AppCount(a5)
lea mms_Code+(semname-codest)(a5),a0
move.l a0,LN_NAME(a5)
lea codest(pc),a0 ; Copy the public code
lea mms_Code(a5),a1
move.l #codefin-codest,d0
jsr _LVOCopyMem(a6)
FORBID ; No AllocMem()s in here please
move.l a6,a1 ; SetFunction AllocMem()
lea mms_Code(a5),a0
move.l a0,d0
movea.w #_LVOAllocMem,a0
jsr _LVOSetFunction(a6)
move.l d0,mms_Code+(jsrinst-codest)+2(a5) ; Set JSR vector
cmpi.w #36,LIB_VERSION(a6) ; Clear the cache after setting vector
blo.s \newsemcc
jsr _LVOCacheClearU(a6)
\newsemcc:
PERMIT
move.l a5,a1 ; Add to system semaphore list
move.l a5,a0 ; BUUUUUUUUUUUUUUUG in 1.3!!!
jsr _LVOAddSemaphore(a6)
bra \outok
\oldsem: ; Semaphore was already in memory
move.l d0,a5
move.l d0,a0
jsr _LVOObtainSemaphore(a6)
addq.w #1,mms_AppCount(a5)
cmp.w #$4ef9,mms_Code(a5) ; See if we have to reactivate the code
bne.s \codefine
FORBID ; No AllocMem()s while we change code
move.l codest(pc),mms_Code(a5) ; Restore first six bytes
move.w codest+4(pc),mms_Code+4(a5) ; No more or we'll trash the vector
cmpi.w #36,LIB_VERSION(a6) ; Clear the cache after changing code
blo.s \oldsemcc
jsr _LVOCacheClearU(a6)
\oldsemcc:
PERMIT
\codefine:
move.l a5,a0
jsr _LVOReleaseSemaphore(a6)
\outok:
lea mms_MMList(a5),a0
move.l a0,mmlist
moveq #1,d0
\out:
apop
rts
*** Uninstall our application from the memory manager
MMFinish:
_MMFinish:
apush
move.l 4,a6
move.l semaphore,d0 ; Never successfully initialized?
bz \out
move.l d0,a5
move.l a5,a0
jsr _LVOObtainSemaphore(a6)
subq.w #1,mms_AppCount(a5)
bnz.s \otherapps
FORBID ; No AllocMem()s while we change the code
move.w #$4ef9,mms_Code(a5) ; Quick bounce with a JMP instruction
move.l mms_Code+(jsrinst-codest)+2(a5),mms_Code+2(a5)
cmpi.w #36,LIB_VERSION(a6) ; Clear the cache after changing code
blo.s \cc
jsr _LVOCacheClearU(a6)
\cc:
PERMIT
\otherapps:
move.l a5,a0
jsr _LVOReleaseSemaphore(a6)
clr.l semaphore ; Safety
\out:
apop
rts
*** Add an MMNode (if it wasn't already on the MMList)
* a1 = Pointer to MMNode
MMAddNode:
_MMAddNode:
cmp.b #MMNT_LINKED,LN_TYPE(a1) ; Don't add a node twice
beq.s 9$
mb #MMNT_LINKED,LN_TYPE(a1) ; Mark it as added
push a6 ; Add it to the global list in prioritized order
move.l 4,a6
move.l mmlist,a0
FORBID
jsr _LVOEnqueue(a6)
PERMIT
pop a6
9$ rts
*** Remove an MMNode (only if it was on the MMList)
* a1 = Pointer to MMNode
MMRemNode:
_MMRemNode:
cmp.b #MMNT_LINKED,LN_TYPE(a1) ; Don't remove unless it was added
bne.s 9$
clr.b LN_TYPE(a1) ; Mark it as not added
push a6 ; Remove it from the public MMList
move.l 4,a6
FORBID
REMOVE
PERMIT
pop a6
9$ rts
bss __MERGED
semaphore ds.l 1 ; Pointer to public semaphore
mmlist ds.l 1 ; Points to mms_MMList in MemManSem
end