mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-10-16 23:24:32 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
770 lines
30 KiB
Plaintext
770 lines
30 KiB
Plaintext
;
|
|
; File: BTreeQueue.a
|
|
;
|
|
; Contains: This file separates Btree manager from HFS one layer above.
|
|
; Support async call for BTree Manager using its own cache buffers and
|
|
; param block queue.
|
|
;
|
|
; Written by: Kenny SC. Tung
|
|
;
|
|
; Copyright: © 1989-1991 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM1> 4/1/92 kc Changed the name prefex used to distinguish
|
|
; routines used by the external B-Tree manager
|
|
; from the versions used by the File System.
|
|
; Removed forRom conditional.
|
|
; ¥ Pre-SuperMario comments follow ¥
|
|
; <20> 9/13/91 JSM Cleanup header.
|
|
; <19> 6/12/91 LN Removed #includes for private interfaces from public interfaces.
|
|
; Changed #include 'HardwareEqu.a' to 'HardwarePrivateEqu.a'
|
|
; <18> 3/17/91 dnf ppd, #dnf-0013: Use the result code from ioResult(a0) instead of
|
|
; from d0 to be extra-clean on async calls.
|
|
; <17> 3/17/91 dnf dba, dty, #84977: use CallWithRegistersPreserved in dispatching;
|
|
; save D0 across calls to completion routines.
|
|
; <16> 12/18/90 KST With Bill B. Adding DoAlloc back.
|
|
; <15> 12/11/90 KST With Bill B. Change _Allocate. to _SetEOF because some foreign
|
|
; FS doesn't handle _Allocate call.
|
|
; <14> 9/10/90 KST Took out debugger labels.
|
|
; <13> 8/3/90 KST Adding FlushFile call in ExtDoAOCRWF.
|
|
; <12> 7/30/90 dnf Make some changes so BTree manager can work as a linked patch.
|
|
; <11> 7/18/90 KST btRsvAccess will not return error if the file has already been
|
|
; reserved, instead the request will be queued.
|
|
; <10> 7/11/90 gbm add END
|
|
; <9> 4/17/90 KST Adding btDebugSYS conditional in "ExtBTQueue".
|
|
; <8> 3/30/90 KST Save registers across ASYNC call.
|
|
; <7> 3/20/90 KST Fixing a bug in handling B*Tree request queue, removing <1.9>
|
|
; registers saving redundant code, and other documentation
|
|
; changes.
|
|
; <6> 3/13/90 KST documentation change and code cleanup.
|
|
; <5> 2/20/90 KST map node was written before "RelMap" was called, now we only
|
|
; mark it dirty and write it back in "ExtRelBlock" !
|
|
; <4> 2/4/90 DNF Add include of FileMgrPrivate.a
|
|
; <3> 1/22/90 KST Changed queue dispatcher to support access control. -- KST
|
|
; 1/16/90 KST added code to support AppleShare's access control.
|
|
; <1.9> 11/10/89 dnf Fix register trashing in ExtDoAOCRWF
|
|
; <1.8> 10/2/89 KST Code cleanup.
|
|
; <1.7> 9/25/89 KST Took out the Debugger call. BTFlush now will flush RamCAche.
|
|
; <1.6> 9/17/89 KST New buffer scheme. No more B*Tree cache buffers.
|
|
; <1.5> 9/8/89 KST Fixed a bug in ExtWriteBlock. We need to save the RefNum because
|
|
; the param is being reused.
|
|
; <1.4> 8/7/89 KST Code cleanup.
|
|
; 7/27/89 KST Use jump table for dispatching calls; Get rid of macro calls
|
|
; 7/27/89 KST Save async trap bit in BTVQflag of BTVar for all operations in
|
|
; ExtBTQueue (BTDispatch)
|
|
; <1.3> 7/13/89 KST Take out debug code for write error.
|
|
; <1.2> 7/6/89 KST Cleaned up the code.
|
|
; <1.1> 6/27/89 KST Fixed a bug in DoACORW routine that trashes A1.
|
|
; 6/27/89 KST Preserve A1 across ExtDoAOCRWF call.
|
|
; <1.0> 6/14/89 KST New file for the new implementation of BTreeMgr.
|
|
; 5/15/89 KST Check A6 stack overflow across ExtDoAOCRWF call.
|
|
; 4/24/89 KST New today.
|
|
;
|
|
|
|
|
|
LOAD 'StandardEqu.d'
|
|
INCLUDE 'BTreeEqu.a' ; BTManager
|
|
Include 'BTreePrivate.a'
|
|
Include 'FileMgrPrivate.a'
|
|
Include 'HardwarePrivateEqu.a'
|
|
|
|
IF (&TYPE('btDebug') = 'UNDEFINED') THEN
|
|
btDebug EQU 0
|
|
ENDIF
|
|
|
|
IF &trim(&type('btDebugSYS')) = 'UNDEFINED' THEN ; <16Apr90>
|
|
btDebugSYS EQU 0 ; <16Apr90>
|
|
ENDIF ; <16Apr90>
|
|
|
|
;__________________________________________________________________________
|
|
; Function: ExtBTQueue.
|
|
; All B*Tree requests branch to here to get queued and serviced in the
|
|
; order they enter the queue (but not necessarily serviced in FCFS because
|
|
; that file's access might have been reserved).
|
|
; Input: D0 = dispatch selector, A0 = ioParam, D1.W = trapword (A08E)
|
|
;__________________________________________________________________________
|
|
ExtBTQueue PROC EXPORT
|
|
export ExtBTDispatchRequest
|
|
IMPORT ExtIsBtree
|
|
|
|
MOVE.W #1,IOResult(A0) ; set IOResult to "in process"
|
|
MOVE.W D1,IOTrap(A0) ; save the trap number
|
|
MOVE.B D0,ioTrap+1(A0) ; Store trap index in low byte
|
|
MOVE.L (SP)+,IOCmdAddr(A0) ; save address to go to when ready
|
|
MOVE.W #btQType,IOType(A0) ; say its a Btree queueing element
|
|
BTST #btAsyncBit,D1 ; async bit on?
|
|
BNE BTAsync ; yes
|
|
;; else, it's a sync call:
|
|
CLR.L IOCompletion(A0) ; no completion routines for sync calls
|
|
MOVE.L A0,-(SP) ; save parameter block ptr
|
|
BSR.S BTAsync ; queue it up (and maybe call it)
|
|
MOVE.L (SP)+,A0 ; restore ioParam
|
|
|
|
WaitLoop MOVE.W IOResult(A0),D0 ; get the result code into D0
|
|
|
|
IF btDEBUG THEN ; debug ... see if we can continue ?
|
|
CMPI #btADAndWait,D0 ; waiting for a RelAccess call?
|
|
BNE.S @3 ; no, never mind
|
|
;; if it is, then we need a RelAccess call. How?
|
|
MOVE.L A0,-(SP) ; save parameter block ptr
|
|
BSR.S InstallVBL ; install a VBL task
|
|
MOVE.L (SP)+,A0 ; restore ioParam
|
|
MOVE.W #1,IOResult(A0) ; but do this only once
|
|
BRA.S WaitLoop
|
|
@3 TST D0
|
|
ENDIF ;...... end of debug
|
|
|
|
BGT.S WaitLoop ; done when result is zero or negative
|
|
|
|
EXT.L D0 ; ALWAYS return a long error code
|
|
RTS ; return to caller
|
|
|
|
IF btDEBUG THEN
|
|
DC.B $80, 'ExtBTQueue'
|
|
ALIGN
|
|
DC.W 0
|
|
|
|
InstallVBL ;; ask VBL to issue the release access BTcall
|
|
;; Test program issues a synchronous request and the access is denied.
|
|
|
|
MOVEQ #vblPhase+2,D0 ; 14 bytes
|
|
_NewPtr ,SYS ,Clear
|
|
BNE.S @nomem ; exit if no room
|
|
MOVE #vType,vblType(A0) ; VBL queue
|
|
MOVE.L @vblRelBT,vblAddr(A0) ; pointer to task (this will move the contents)
|
|
LEA @vblRelBT,A1
|
|
MOVE.L A1,vblAddr(A0) ; pointer to task (this will move the pointer)
|
|
MOVE #30,vblCount(A0) ; frequency count
|
|
_VInstall
|
|
|
|
@nomem RTS
|
|
|
|
@vblRelBT ;; this VBL task will release the file
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1 ; A1 = btVars
|
|
MOVEA.L btVParam(A1),A0 ; A0 = private Param
|
|
MOVEA.L btVQhead(A1),A1 ; A1 = current btioParam
|
|
MOVE ioRefNum(A1),ioRefNum(A0) ; release this file
|
|
MOVE.L ioBTRsrvUID(A1),D0 ; test program's UID
|
|
ADDQ #1,D0 ; it uses UID - 1
|
|
MOVE.L D0,ioBTRsrvUID(A0) ; use this ID to release
|
|
CLR.L ioCompletion(A0) ; no completion routine
|
|
_BTRelAccess ,Async ; call B*TreeMgr
|
|
RTS
|
|
|
|
ENDIF
|
|
|
|
|
|
BTAsync MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1 ; A1 is also the q header
|
|
MOVE SR,-(SP) ; only allow
|
|
ORI #HiIntMask,SR ; interrupt for debugging
|
|
_ENQUEUE ;
|
|
|
|
ToBTDispatch ; dispatch the next request (also called by ExtBTCmdDone)
|
|
; interrupt disabled. ; Is a request already executing?
|
|
BSET #btQBusyBit,btVQFlag(A1) ; A1=btVar, B*Tree busy?
|
|
BEQ.S BTDispatch ; if not, just call it
|
|
|
|
; The B*tree Manager is busy (and we've queued the request), so we're done for now.
|
|
; We'll get to it when ExtBTCmdDone is called.
|
|
MOVEQ #0,D0 ; no errors (yet)
|
|
MOVE.W (SP)+,SR ; re-enable interrupts and return
|
|
RTS
|
|
|
|
BTDispatch ;; A1 = ptr(BTvars)
|
|
MOVE (SP)+,SR ; re-enable interrupts
|
|
|
|
MOVEM.L D3-D7/A2-A6,-(SP) ; observe Pascal regsave conventions <17>
|
|
bsr.s ExtBTDispatchRequest
|
|
MOVEM.L (SP)+,D3-D7/A2-A6 ; restore registers <17>
|
|
rts
|
|
|
|
ExtBTDispatchRequest:
|
|
;; Added code to support AppleShare's access control: -- 12/14/89
|
|
;; We may not service the request in FCFS order. If the request we're servicing
|
|
;; is not in the front of the queue, then we move it to the front.
|
|
;; If we cannot service any of the requests, we clear the BUSY flag and leave.
|
|
|
|
LEA btVQHead(A1),A0 ; A1=btVar, A0=ioParam
|
|
@scanLoop MOVE.L qLink(A0),D0 ; Pick up the next element on the queue
|
|
BEQ @ad_ret ; If EQ, there are no requests pending
|
|
@loop2 MOVEA.L D0,A0 ; A0 -> BT Parameter block
|
|
|
|
;; Loop through the queue, looking for an element that can be started:
|
|
MOVEQ #0,D0
|
|
MOVE.B ioTrap+1(A0),D0 ; which operation
|
|
CMP.W #btRsrvAccessN,D0 ; reserveAccess will be queued now <17Jul90>
|
|
BEQ.S @controlled ; yes, this is RsrvAccess call <17Jul90>
|
|
CMP.W #btOpenN,D0 ; INIT, OPEN are free to go
|
|
BLE.S @moveQueue ; no access control
|
|
CMP.W #btDeleteN,D0
|
|
BHI.S @moveQueue ; no access control
|
|
@controlled
|
|
;; we are in the range of operations that will change the contents of B*Tree.
|
|
;; check if the file is locked by other process; if not then move the request
|
|
;; to the front if it isn't already at the front.
|
|
BSR btFileUid ; get this B*tree file's Uid in D1
|
|
BNE.S @moveQueue ; not btree error, but let B*TreeMgr handles it
|
|
TST.L D1 ; Check: B*-Tree access reserved?
|
|
BEQ.S @moveQueue ; If 0, it's a free-for-all
|
|
CMP.L ioBTRsrvUID(A0),D1 ; If not, is this call for the right user?
|
|
BEQ.S @moveQueue ; yes, we have the access
|
|
;; If we don't have the access permission and this is a SYNCHRONOUS call,
|
|
;; then we set a special value in ioResult.
|
|
BTST #btAsyncBit,ioTrap(A0) ; SYNC call?
|
|
BNE.S @scanLoop ; No, it's not - check next one in queue
|
|
MOVE #btADAndWait,IOResult(A0) ; access denied on a SYNC call, mark we're waiting
|
|
BRA.S @scanLoop
|
|
|
|
@moveQueue CMP.L btVQHead(A1),A0 ; is this head?
|
|
BEQ.S @doit ; yes
|
|
;; If not, then we need to move it to the front
|
|
MOVE SR,-(SP) ; only allow level 3
|
|
ORI #HiIntMask,SR ; interrupts for debugging
|
|
MOVE.L A1,-(SP) ; save btVars
|
|
LEA btVQHdr(A1),A1 ; A1 = theQueue, A0 = qEntry
|
|
_dequeue ; remove it from BT queue
|
|
MOVEA.L (SP),A1 ; A1 = btVars
|
|
MOVEA.L btVQHead(A1),A1 ; A1 = head
|
|
MOVE.L A1,qLink(A0) ; add it in the front
|
|
MOVEA.L (SP)+,A1 ; restore A1(btVars)
|
|
MOVE.L A0,btVQHead(A1) ; A0 = QHead
|
|
TST.L btVQTail(A1) ; tail = NULL?
|
|
BNE.S @1 ; no
|
|
MOVE.L A0,btVQTail(A1) ; A0 = QTail too
|
|
@1 MOVE.W (SP)+,SR ; re-enable interrupts
|
|
|
|
@doit ;;Really gonna execute it. Here, make sure A1=btVar.
|
|
MOVEA.L btVSTop(A1),A6 ; Set up A6 for use as stack pointer
|
|
;; Before servicing the call, save async bit in BTVars because B*Tree Manager
|
|
;; shares its private param block doing I/O, not user param.
|
|
BCLR #btAsyncBit,btVQFlag(A1) ; sync is default
|
|
BTST #btAsyncBit,ioTrap(A0) ; Async only?
|
|
BEQ.S @2 ; sync call
|
|
BSET #btAsyncBit,btVQFlag(A1) ; set async bit
|
|
@2 MOVEA.L IOCmdAddr(A0),A1 ; get address to call
|
|
JMP (A1) ; execute Btree command and return <17>
|
|
; (all commands finish by jumping to ExtBTCmdDone)
|
|
|
|
;; Access has been denied, clear busy flag and return,
|
|
;; (the request(s) will finally be serviced when a RelAccess call comes in).
|
|
@ad_ret BCLR #btQBusyBit,btVQFlag(A1) ; Btree not servicing
|
|
;; because this test and clear is not atomic, I need to do this:
|
|
MOVE.L qLink(A0),D0 ; A0 was tail
|
|
BEQ.S @qexit ; and it still is
|
|
BSET #btQBusyBit,btVQFlag(A1) ; is B*Tree busy?
|
|
BEQ @Loop2 ; no, go service the new request
|
|
@qexit RTS ; D0 = 0
|
|
|
|
;; _____________________________________________________________________
|
|
;; Function:verify if this file is B*Tree, if it is, get the UID in D1
|
|
;; Input: A0 = user param
|
|
;; Output: D0=0 if it's Btree; D1 = UID. All other registers preserved.
|
|
;; _____________________________________________________________________
|
|
btFileUid MOVEM.L D2/A1-A4,-(SP)
|
|
BSR ExtIsBtree ; BTree?
|
|
BNE.S @3 ; no, not btree
|
|
MOVE.L BTCRsrvUID(A4),D1 ; yes, get UID
|
|
|
|
IF btDebugSYS THEN ; if debugging <16Apr90>
|
|
MOVEQ #0,D1 ; .. system btree file <16Apr90>
|
|
ENDIF ; .. don't use UID <16Apr90>
|
|
|
|
@3 MOVEM.L (SP)+,D2/A1-A4
|
|
TST D0
|
|
RTS
|
|
IF btDEBUG THEN
|
|
DC.B $80, 'BTDispatch'
|
|
ALIGN
|
|
DC.W 0
|
|
ENDIF
|
|
ENDPROC
|
|
|
|
; _____________________________________________________________________________
|
|
; Function: ExtBTCmdDone. All BTcommands jump to here when finished
|
|
; ioCompletion routine is called for ASYNC call. The current request
|
|
; is removed from the queue, and the next one is serviced if there is one.
|
|
; Input: D0.W = error code
|
|
; _____________________________________________________________________________
|
|
ExtBTCmdDone PROC EXPORT
|
|
IMPORT ExtBTDispatchRequest, CallWithRegistersPreserved
|
|
|
|
IF btDebug THEN
|
|
BSR bufDebug ; debugging
|
|
ENDIF
|
|
|
|
EXT.L D0 ; Make a long of it
|
|
jsr btQerrorp ; get current ioParam in A0
|
|
MOVE SR,-(SP) ; save interrupt state
|
|
ORI #HiIntMask,SR ; only debug interrupts allowed
|
|
BCLR #btQBusyBit,btVQFlag(A1) ; clear Btree busy flag
|
|
|
|
; delete the current request from the queue and post any completion routines
|
|
MOVE.L QLink(A0),btVQHead(A1) ; get next request, if any
|
|
BNE.S bt_CallComp ; branch if queue not empty
|
|
CLR.L btVQTail(A1) ; clear tail ptr, too
|
|
bt_CallComp
|
|
MOVE (SP)+,SR ; restore interrupt state
|
|
MOVE.W D0,IOResult(A0) ; post error code
|
|
MOVE.L IOCompletion(A0),D1 ; is there a completion routine?
|
|
BEQ.S bt_DispNext ; skip if there's not
|
|
MOVE.L D1,A1 ; get the completion routine address
|
|
JSR (A1) ; call it with A0=param
|
|
|
|
bt_DispNext ;; check if there's anything else for us to do
|
|
MOVE SR,-(SP) ; save interrupt state
|
|
ORI #HiIntMask,SR ; only debug interrupts allowed
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1 ; get BT vars
|
|
TST.L btVQHead(A1) ; any req pending?
|
|
beq @noRequirements ; <dnf> change for linked patch
|
|
|
|
BSET #btQBusyBit,btVQFlag(A1) ; A1=btVar, B*Tree busy? <17>
|
|
bne.s @noRequirements ; if it was already busy, we can return asynchronously <17>
|
|
move.w (sp)+,sr ; restore interrupt state <17>
|
|
|
|
lea.l ExtBTDispatchRequest,a0 ; our dispatcherÕs entry point <17>
|
|
jmp CallWithRegistersPreserved ; call it <17>
|
|
|
|
@noRequirements:
|
|
MOVE.W (SP)+,SR ; re-enable interrupts and return
|
|
RTS
|
|
|
|
@doDispatch:
|
|
|
|
;; _______________________________________________________________
|
|
;; Function: get current ioParam in A0 and validate it
|
|
;; Output: A0=current request, A1=BTVar ptr
|
|
;; _______________________________________________________________
|
|
btQerrorp ;; if error just die
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1
|
|
MOVEA.L btVQHead(A1),A0 ; A0 = first ioParam
|
|
CMP #btQType,IOType(A0) ; it better be an Btree queue element
|
|
BNE.S @2 ; or else die
|
|
RTS
|
|
|
|
@2 MOVEQ #DSFSErr,D0
|
|
_SysError
|
|
|
|
IF btDebug THEN ; Debugging ........................
|
|
bufDebug MOVEM.L D0/D2/A3-A5,-(A7)
|
|
MOVEa.L FSVarsPtr,A5
|
|
MOVEA.L fsVars.btMgr(A5),A5
|
|
MOVEA.L btBufQHdr(A5),A5 ; A5 = ptr(buffer Qheader)
|
|
MOVEQ #0,D2 ; start from 0 <9/15/89>
|
|
LEA btQBStart(A5),A3 ; A3=first buffer <9/15/89>
|
|
|
|
@2 BTST #CBHinuse,btBHFlags(A3) ; buffer in use? <9/15/89>
|
|
BNE.S @4 ; yes, error <9/15/89>
|
|
|
|
ADDQ #1,D2 ; next index <9/15/89>
|
|
CMPI #btBufferN,D2 ; all done? <9/15/89>
|
|
BEQ.S @6 ; Yes, <9/15/89>
|
|
ADDA #$200,A3 ; next buffer <9/15/89>
|
|
ADDA #lenBTBH,A3 ; ... and skip header <9/15/89>
|
|
BRA.S @2 ; test next <9/15/89>
|
|
|
|
@4 _debugger ; this shouldn't happen <9/15/89>
|
|
; A3 buffer still in use <3/09/90>
|
|
@6 MOVEM.L (SP)+,D0/D2/A3-A5
|
|
ENDIF
|
|
|
|
RTS
|
|
IF btDEBUG THEN
|
|
DC.B $80, 'ExtBTCmdDone'
|
|
ALIGN
|
|
DC.W 0
|
|
ENDIF
|
|
ENDPROC ; ExtBTCmdDone
|
|
|
|
;; ___________________________________________________________________________
|
|
;; Function: This is the routine that handles async HFS calls
|
|
;; Input: D1 = option word (ALLOCATE/OPEN/CLOSE/READ/WRITE/Flush).
|
|
;; A0 = BT private param, assume A1 is free
|
|
;; Output: D0=error code
|
|
;; 28Jul89 KST Disable system cache for B*Tree when doing R/W
|
|
;; 24Aug89 KST Undo previous change, we depend on RamCache
|
|
;; 02Aug90 KST Adding flushfile call for BTFlush.
|
|
;; ___________________________________________________________________________
|
|
asyncRegs REG d2-d7/A2-A5
|
|
|
|
ExtDoAOCRWF PROC EXPORT
|
|
MOVEQ #paramErr,D0 ; preset error code
|
|
CMPI #DoMaxNum,D1 ; legal (0~5) ?
|
|
BHI.S syncRet ; bad
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1
|
|
|
|
IF btDebug THEN ;; debugging, check for stack overflow <6/12/89>
|
|
MOVE.L btVSTop(A1),D0 ; stack base
|
|
SUB.L A6,D0 ; how far does it go
|
|
CMPI.L #(btStkLen-24),D0 ; overflow? (reserve 24 bytes for AsyncOC)
|
|
BLO.S @1 ; no,
|
|
MOVEQ #dsStkNHeap,D0 ; stack overflow
|
|
_SysError ; bumb !
|
|
ENDIF
|
|
|
|
@1 LSL #2,D1 ; use jump table
|
|
BTST #btAsyncBit,btVQFlag(A1) ; Async call?
|
|
BNE.S AsyncOC ; yes
|
|
@2 ;; A0/A1 are saved by the system dispatcher
|
|
LEA syncTable,A1
|
|
JMP (A1,D1) ; service the call
|
|
|
|
syncTable
|
|
_Allocate ; put this back <18Dec90 #16>
|
|
BRA.S syncRet
|
|
_HOpen
|
|
BRA.S syncRet
|
|
_Close
|
|
BRA.S syncRet
|
|
_Read
|
|
BRA.S syncRet
|
|
_Write
|
|
BRA.S syncRet
|
|
_FlushFile
|
|
BRA.S syncRet
|
|
_SetEOF ; adding this <18Dec90 #16>
|
|
syncRet RTS
|
|
|
|
AsyncOC ;; A0 = BTParam to do async open/close...., D1 is the selector
|
|
;; A1 = ptr(BTVars)
|
|
MOVE.L (SP)+,-(A6) ; save return address
|
|
MOVEM.L asyncRegs,-(A6) ; save all regs across async
|
|
MOVE.L A6,btVSPtr(A1) ; save BT stack top
|
|
BCLR #btAsyncRetd,btVQFlag(A1) ; clear 'premature-return' flag
|
|
LEA btIOComp,A1 ; load btIOcomp routine
|
|
MOVE.L A1,IOCompletion(A0)
|
|
|
|
LEA asyncTable,A1
|
|
JMP (A1,D1) ; service the call
|
|
|
|
asyncTable
|
|
_Allocate ,Async ; put this back <18Dec90 #16>
|
|
BRA.S @4
|
|
_HOpen ,Async
|
|
BRA.S @4
|
|
_Close ,Async
|
|
BRA.S @4
|
|
_READ ,Async
|
|
BRA.S @4
|
|
_WRITE ,Async
|
|
BRA.S @4
|
|
_FlushFile ,Async
|
|
BRA.S @4
|
|
_SetEOF ,Async ; adding this <18Dec90 #16>
|
|
@4 BEQ.S @6 ; branch if no error
|
|
TST IOResult(A0) ; really error?
|
|
BLE.S btACont ; yes
|
|
@6 ; say we returned from B*Tree async call
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1
|
|
BSET #btAsyncRetd,btVQFlag(A1) ; set asyncReturn flag
|
|
BNE.S btACont1 ; if we already returned, do ioComp now
|
|
; do the completion routine not caused by interrupt
|
|
btAsyncRTS RTS ; else, return to App. We'll be back
|
|
|
|
|
|
btIOcomp ;; B*Tree ioCompletion routine
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1 ; say we're returning now
|
|
BSET #btAsyncRetd,btVQFlag(A1) ; set asyncReturn flag
|
|
BEQ.S btAsyncRTS ; if trap didn't really return ASYNC
|
|
; then RTS now, we'll be back (from @6)
|
|
;; SYNC case in an ASYNC call, it will eventually return to @6
|
|
btACont MOVEM.L D4-D7/A4-A6,-(SP) ; preserve non-interrupt registers
|
|
PEA btACont2 ; return to here to restore regs
|
|
btACont1
|
|
MOVEa.L FSVarsPtr,A1 ; restore B*TreeMgr stack
|
|
MOVEA.L fsVars.btMgr(A1),A1
|
|
MOVEa.L btVSPtr(A1),A6 ; A6 = BT stack
|
|
MOVEM.L (A6)+,asyncRegs ; restore regs across async
|
|
MOVE.L (A6)+,-(SP)
|
|
MOVE.W ioResult(a0),D0 ; any error? <18>
|
|
RTS ; return to B*tree manager
|
|
|
|
btACont2 MOVEM.L (SP)+,D4-D7/A4-A6 ; restore the non-int registers
|
|
RTS ;; we're done with it! (return to interrupt handler)
|
|
ENDPROC ;; exit ExtDoAOCRWF
|
|
|
|
;_________________________________________________________________________________
|
|
; Routine: ExtGetBlock
|
|
; Function: Gets a specified btree node (data fork of a B*Tree file).
|
|
; The desired block must be specified by file refnum;
|
|
; Unless GBnoRead option is specified, a FS read is performed.
|
|
; Input: D0.W - file refnum only
|
|
; A1.L - pointer to BTree cache queue header
|
|
; D1.B - option flags (default = read from disk if not found):
|
|
; GBRead - read from disk (forced read)
|
|
; GBnoRead - don't read from disk if not found
|
|
; GBexist - get existing cache block
|
|
; D2.L - btree node number
|
|
; Output: A0.L - addr(buffer) containing desired block
|
|
; D0.W - result code, 0 = ok, other = error
|
|
; 08Aug89 KSCT Need a inuse flag for the new buffer scheme.
|
|
; 15Aug89 KSCT Clear inuse flag if read error!
|
|
;_________________________________________________________________________________
|
|
ExtGetBlock PROC EXPORT ;
|
|
|
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
|
MOVEM.L D1-D6/A1-A5,-(A6) ; save regs
|
|
MOVE.B D1,D3 ; D3 = option flags
|
|
MOVEA.L A1,A3 ; A3 = ptr(Buf QHdr)
|
|
MOVE.W D0,D1 ; D1 = volume or file refnum?
|
|
BLT GBErrExit ; volume -> unsupported
|
|
|
|
MOVEA.L FCBSPtr,A1 ; A1 = ptr(FCB)
|
|
MOVEA.L FCBVPtr(A1,D1.W),A2 ; A2 = ptr(VCB)
|
|
MOVEA.L FCBBTCBptr(A1,D1),A4; A4 = ptr(BTCB)
|
|
MOVEQ #0,D6 ; D6.L=request count
|
|
MOVE.W btcNodeSize(A4),D6 ; D6=B*Tree nodesize
|
|
BNE.S @1 ; B*tree opened
|
|
;; BTOpen wants to read the header but we don't know the NodeSize, assume
|
|
;; Header Nodesize is a constant, or at least Header info is in the first 512 bytes.
|
|
MOVE.W #btHdrNSize,D6
|
|
|
|
;; new buffer scheme: not cache (can't get an existing block) <8/21/89>
|
|
@1 BTST #GBexist,D3 ; request for an existing block?
|
|
BEQ.S @2 ; no ->
|
|
|
|
IF btDebug THEN
|
|
_debugger ; should not happen
|
|
ENDIF
|
|
|
|
MOVEQ #Chnotfound,D0 ; result = 'not found'
|
|
BRA GBExit1 ; exit ->
|
|
|
|
@2 MOVE btQCIndex(A3),D0 ; current index
|
|
MOVE D0,D5 ; save current index for error recovery
|
|
MOVEA.L A3,A5 ; A3 = A5 = buffer QHdr
|
|
CMPI #(btBufferN-1),D0 ; need to wrap around?
|
|
BEQ.S @3 ; yes
|
|
ADDQ #1,btQCIndex(A3) ; else, bump the index
|
|
BRA.S @4
|
|
@3 CLR btQCIndex(A3) ; wrap around
|
|
@4 MOVE btQBSize(A3),D4 ; D4=INIT buffer size
|
|
;; In future release, we need to make sure that D4>=D6, err otherwise.
|
|
;; get the buffer based on the index in D0
|
|
LEA btQBStart(A3),A3 ; A3=first buffer
|
|
BRA.S @6
|
|
@5 ADDA D4,A3 ; next buffer
|
|
ADDA #lenBTBH,A3 ; ... and skip header
|
|
@6 DBRA D0,@5
|
|
|
|
;; A3=buffer header pointer, check if the buffer is inuse <9/8/89>
|
|
;; can't just use the next one sequentially <9/8/89>
|
|
BTST #CBHinuse,btBHFlags(A3) ; buffer in use? <9/8/89>
|
|
BEQ.S @8 ; No, OK => <9/8/89>
|
|
BSR gNextbuf ; Yes, get next one <9/11/89>
|
|
BNE.S @gbNoBuf ; no buffer <9/11/89>
|
|
;; convert block number into byte position, A3 = buffer header address to use.
|
|
@8 MOVEQ #0,D0
|
|
MOVE.B btcL2NSize(A4),D0 ; D0=shift bit count
|
|
LSL.L D0,D2 ; file block number x size = file position
|
|
;; assign buffer to new node, but keep status info <9/8/89>
|
|
BSET #CBHinuse,btBHFlags(A3) ; set in use <9/8/89>
|
|
|
|
MOVE D1,btBHRefNum(A3) ; save refnum
|
|
MOVE D6,btBHNSize(A3) ; save node size
|
|
MOVE.L D2,btBHFilePos(A3) ; save file position
|
|
LEA btBHData(A3),A3 ; A3=ptr(buffer)
|
|
BTST #GBnoRead,D3 ; no-read requested ?
|
|
BNE.S NoReadBlk ; ...yes, skip read ->
|
|
;; FileRead here: D0/A0 are free, (A1,D1)=FCB, A4=BTCB, D2=file pos,D6=nodesize
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1
|
|
MOVEA.L btVParam(A1),A0 ; A0 = BT Param
|
|
MOVE.W D1,ioRefNum(A0) ; file refnum
|
|
MOVE.L A3,IOBuffer(A0) ; buffer to read in
|
|
MOVE.W #fsFromStart,IOPosMode(A0) ; position mode(from BOF)
|
|
MOVE.L D6,IOByteCount(A0) ; r/w node size
|
|
MOVE.L D2,IOPosOffset(A0) ; ... gives position offset
|
|
MOVEQ #DoRead,D1 ; indicate this is READ
|
|
BSR ExtDoAOCRWF
|
|
BEQ.S NoReadBlk ; read OK =>
|
|
;; some read error, clean up and exit (clear flag). A3=ptr(buffer)
|
|
LEA -btBHData(A3),A1 ; A1=ptr(bufHdr) <9/15/89>
|
|
BCLR #CBHinuse,btBHFlags(A1) ; not in use <9/15/89>
|
|
@gbNoBuf MOVE D5,btQCIndex(A5) ; restore old index as nothing has happened
|
|
BRA.S GBExit1 ; D0=read error ->
|
|
|
|
NoReadBlk MOVEQ #0,D0 ; all OK
|
|
GBExit1 MOVEA.L A3,A0 ; return buffer address in A0 (even error in read)
|
|
MOVEM.L (A6)+,D1-D6/A1-A5
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set up condition codes
|
|
RTS ; exit ExtGetBlock
|
|
|
|
GBErrExit MOVEQ #paramErr,D0
|
|
BRA.S GBExit1
|
|
|
|
;_________________________________________________________________________________
|
|
; Routine: gNextbuf (internal function)
|
|
; Function: Current buffer is inuse, try next one. This function is SYNC.
|
|
; Input: D4.W=Btree private buffer size, D5.W=index of current buffer,
|
|
; A3=ptr(buffer inuse), A5=ptr(buffer QHdr)
|
|
; Output: if D0=0, then A3=new buffer ptr, everything else unchanged,
|
|
; btQCIndex(A5) updated to reflect the change.
|
|
; if D0<>0 (all inuse), everything unchanged, including A3.
|
|
;_________________________________________________________________________________
|
|
gNextbuf MOVE.L D2,-(SP)
|
|
MOVE D5,D2 ; D2=D5=index <9/11/89>
|
|
|
|
@gnbLoop ADDQ #1,D2 ; next index <9/11/89>
|
|
CMPI #btBufferN,D2 ; need to wrap around? <9/11/89>
|
|
BNE.S @1 ; No <9/11/89>
|
|
MOVEQ #0,D2 ; Yes, wrap around <9/11/89>
|
|
LEA btQBStart(A5),A3 ; A3=first buffer <9/11/89>
|
|
BRA.S @2 ; <9/11/89>
|
|
|
|
@1 ADDA D4,A3 ; A3 points to next buffer <9/11/89>
|
|
ADDA #lenBTBH,A3 ; ... and skip header <9/11/89>
|
|
|
|
@2 ;; we knew D5 is inuse, so don't bother testing it. A3 = ptr(D5 buffer)
|
|
CMP D2,D5 ; all done? <9/11/89>
|
|
BEQ.S @gnbNobuf ; yes, all inuse. punt-> <9/11/89>
|
|
|
|
BTST #CBHinuse,btBHFlags(A3) ; buffer in use? <9/11/89>
|
|
BNE.S @gnbLoop ; yes, try next one <9/11/89>
|
|
;; found the free buffer, D2 is the index, update the btQCIndex field
|
|
ADDQ #1,D2 ; next index <9/11/89>
|
|
CMPI #btBufferN,D2 ; need to wrap around? <9/11/89>
|
|
BNE.S @3 ; No <9/11/89>
|
|
MOVEQ #0,D2 ; Yes, wrap around <9/11/89>
|
|
@3 MOVE D2,btQCIndex(A5) ; and save it in qHeader <9/11/89>
|
|
MOVEQ #0,D0 ; perfect <9/11/89>
|
|
@gnbExit MOVE.L (SP)+,D2
|
|
TST D0
|
|
RTS
|
|
|
|
@gnbNobuf
|
|
IF btDebug THEN
|
|
_debugger ; this shouldn't happen <9/11/89>
|
|
ENDIF
|
|
MOVEQ #ChNoBuf,D0 ; result=all buffers in use <9/11/89>
|
|
BRA.S @gnbExit ; <9/11/89>
|
|
|
|
ENDPROC
|
|
|
|
|
|
;_________________________________________________________________________________
|
|
;
|
|
; Routine: ExtRelBlock (Release Block)
|
|
;
|
|
; Function: Releases use of a specified disk block; optionally marks block dirty,
|
|
; trashes block, and/or writes block to disk. Note: this routine may be
|
|
; called for an already released block to mark it dirty, trashed, or to
|
|
; write it.
|
|
;
|
|
; Input: D1.B - option flags:
|
|
; RBdirty - mark buffer dirty
|
|
; RBtrash - trash buffer contents (set empty)
|
|
; RBwrite - force write buffer to disk
|
|
; A0.L - addr(cache buffer) containing disk block
|
|
; A1.L - pointer to buffer header (not used)
|
|
; Output: D0.W - result code
|
|
; 0 = ok
|
|
; other = error (can only occur if RBwrite option specified)
|
|
;_________________________________________________________________________________
|
|
|
|
ExtRelBlock PROC EXPORT ;
|
|
IMPORT ExtWriteBlock ;
|
|
|
|
MOVE.L (SP)+,-(A6) ; save return address on A6 stack
|
|
MOVEM.L D1/A0/A4,-(A6) ; save registers
|
|
LEA -lenbtBH(A0),A4 ; A4 = ptr to CBH
|
|
BTST #CBHdirty,btBHFlags(A4) ; buffer dirty? <2/20/90>
|
|
BEQ.S @1 ; no <2/20/90>
|
|
CLR.B btBHFlags(A4) ; clear dirty/in-use <2/20/90>
|
|
BRA.S @4 ; write dirty mapnode <2/20/90>
|
|
|
|
@1 CLR.B btBHFlags(A4) ; clear in-use <9/8/89>
|
|
|
|
BTST #RBdirty,D1 ; buffer dirty?
|
|
BNE.S @4 ; Yes ->
|
|
@2 BTST #RBwrite,D1 ; force write requested ?
|
|
BEQ.S RBExit ; no ->
|
|
@4 JSR ExtWriteBlock ; write block to disk
|
|
BRA.S RBExit1 ; all done -> D0 set
|
|
RBExit
|
|
CLR.W D0 ; indicate no error
|
|
RBExit1
|
|
MOVEM.L (A6)+,D1/A0/A4 ; restore registers
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set up condition codes
|
|
RTS ; exit ExtRelBlock
|
|
ENDPROC
|
|
|
|
;_________________________________________________________________________________
|
|
; Function: write a B*Tree buffer to disk.
|
|
; Input: A4.L - buffer header to write
|
|
; Output: D0 = error code, set buffer not dirty!
|
|
; Modification History:
|
|
; 07Aug89 KSCT Get node size shift count from BTCB
|
|
; 08Sep89 KSCT Save the RefNum we are servicing because the param is reused.
|
|
;________________________________________________________________________________
|
|
ExtWriteBlock PROC EXPORT ;
|
|
IMPORT ExtDoAOCRWF
|
|
|
|
MOVE.L (SP)+,-(A6)
|
|
MOVEM.L D1/A1,-(A6) ; save regs over _write call
|
|
;; We don't do flush now, Do a filewrite here:
|
|
MOVEa.L FSVarsPtr,A1
|
|
MOVEA.L fsVars.btMgr(A1),A1
|
|
MOVEA.L btVParam(A1),A0 ; A0 = BT Param
|
|
IF BTDEBUG THEN
|
|
;; A0 is reused. stash info on stack. <9/8/89>
|
|
MOVE ioRefNum(A0),-(A6) ; save the RefNum we're servicing <9/8/89>
|
|
ENDIF
|
|
MOVE.W btBHRefnum(A4),D0 ; D0=refnum
|
|
MOVE.W D0,ioRefNum(A0) ; file refnum
|
|
LEA btBHdata(A4),A1
|
|
MOVE.L A1,IOBuffer(A0) ; buffer to write
|
|
MOVE.W #fsFromStart,IOPosMode(A0) ; position mode(from BOF)
|
|
MOVEQ #0,D0
|
|
MOVE.W btBHNSize(A4),D0 ; D0=node size
|
|
MOVE.L D0,IOByteCount(A0) ; r/w node size
|
|
MOVE.L btBHFilePos(A4),D0 ; file pos
|
|
MOVE.L D0,IOPosOffset(A0) ; ... gives position offset
|
|
MOVEQ #DoWrite,D1 ; indicate this is WRITE
|
|
BSR ExtDoAOCRWF ;
|
|
|
|
IF BTDEBUG THEN
|
|
MOVE (A6),D1 ; old refnum <9/8/89>
|
|
CMP ioRefNum(A0),D1 ; same refnum? <9/8/89>
|
|
BEQ.S @2 ; yes <9/8/89>
|
|
_debugger ; should not happen <9/8/89>
|
|
|
|
@2 MOVE (A6)+,ioRefNum(A0) ; restore RefNum <9/8/89>
|
|
ENDIF
|
|
|
|
MOVEM.L (A6)+,D1/A1 ; restore registers
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set up condition codes
|
|
RTS
|
|
ENDPROC ; ExtWriteBlock
|
|
|
|
|
|
;_________________________________________________________________________________
|
|
; Function: mark the block dirty
|
|
; Now we just write it but don't clear inuse flag <9/11/89>
|
|
; Input: A0=ptr(buffer)
|
|
; Output: D0 = 0 if no error
|
|
;_________________________________________________________________________________
|
|
ExtMarkBlock PROC EXPORT ;
|
|
; BSET #CBHdirty,CBHFlags-lenCBH(A0) ; mark it dirty
|
|
MOVE.L (SP)+,-(A6)
|
|
MOVE.L A4,-(A6)
|
|
LEA -lenbtBH(A0),A4 ; A4 = ptr to CBH
|
|
|
|
JSR ExtWriteBlock ;
|
|
MOVEa.L (A6)+,A4 ; restore registers
|
|
MOVE.L (A6)+,-(SP) ; put return address back on stack
|
|
TST.W D0 ; set up condition codes
|
|
RTS
|
|
ENDPROC
|
|
|
|
END |