home *** CD-ROM | disk | FTP | other *** search
- ********************************************************************************
- *
- * 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
-