section DATA,DATA xref _SysBase section CODE include "exec/types.i" include "exec/ports.i" include "exec/tasks.i" include "exec/execbase.i" include "exec/ables.i" include "exec/memory.i" ; NOTE: LockAddr/UnLockAddr referenced elsewhere in ; this library ; MISC2.ASM xref _LVOPutMsg xdef _DoSyncMsg xdef _WaitMsg _DoSyncMsg: movem.l 4(sp),A0/A1 movem.l A2/A3/A6,-(sp) ; A0=port, A1=msg move.l _SysBase,A6 ; A6=execbase sub.w #MP_SIZE,sp ; initialize reply port move.b #NT_MSGPORT,LN_TYPE(sp) move.b #PA_SIGNAL,MP_FLAGS(sp) move.b #4,MP_SIGBIT(sp) ; EXEC semaphore signal move.l ThisTask(A6),MP_SIGTASK(sp) lea MP_MSGLIST(sp),A2 lea MP_MSGLIST+4(sp),A3 move.l A3,(A2) ; &tail -> head move.l #0,(A3) ; NULL -> tail move.l A2,8(A2) ; &head -> tailpred move.l sp,MN_REPLYPORT(A1) move.l A1,A2 ; save message jsr _LVOPutMsg(A6) ; send the message move.l A2,-(sp) bsr _WaitMsg addq.l #4,sp add.w #MP_SIZE,sp movem.l (sp)+,A2/A3/A6 rts xdef _CheckMsg _CheckMsg: move.l 4(sp),A0 moveq.l #0,D0 cmp.b #NT_MESSAGE,LN_TYPE(A0) ;NT_MESSAGE == not replied beq .lcm1 move.l A0,D0 .lcm1 rts xdef _CheckPort _CheckPort: move.l 4(sp),A0 moveq.l #0,D0 move.l MP_MSGLIST+LH_HEAD(A0),A0 tst.l (A0) ;list empty? beq .lcp1 move.l A0,D0 ;no, return first element .lcp1 rts xref _LVOWait xref _LVORemove xref _LVODisable xref _LVOEnable xdef _WaitMsg _WaitMsg: move.l 4(sp),A0 movem.l A2/A3/A6,-(sp) move.l A0,A2 ;A2 = message move.l MN_REPLYPORT(A0),A3 ;A3 = replyport move.l _SysBase,A6 ;A6 = execbase .wmloop cmp.b #NT_MESSAGE,LN_TYPE(A2) ;while msg not replied bne .wm1 move.b MP_SIGBIT(A3),D1 ;Wait on port signal moveq.l #0,D0 bset.l D1,D0 jsr _LVOWait(A6) bra .wmloop .wm1 jsr _LVODisable(A6) ;remove from port move.l A2,A1 ;A1 = message (A2) jsr _LVORemove(A6) jsr _LVOEnable(A6) move.l A2,D0 ;return message movem.l (sp)+,A2/A3/A6 rts ;WILDCMP(wild:D0, name:D1) ; ; Handles * and ? ; ;result: D0, 0 = no match, 1 = match ; ;auto: ; D2 bi ; A2 wildcard string ; A3 name string ; A4 back-array (of size MAXB * 2 * 4) MAXB EQU 8 xdef _WildCmp _WildCmp: movem.l 4(sp),D0/D1 movem.l D2/A2-A4,-(sp) move.l D0,A2 move.l D1,A3 sub.l #MAXB*2*8,sp move.l sp,A4 moveq.l #0,D2 .wcloop moveq.l #1,D0 move.b (A2),D1 bne .w1 tst.b (A3) beq .wcdone .w1 cmp.b #'*',D1 bne .w10 cmp.w #MAXB,D2 bne .w2 moveq.l #-1,D0 ; error bra .wcdone .w2 move.w D2,D0 ; back[bi][0] = w i.e. back+bi*8 asl.w #3,D0 ; back[bi][1] = n move.l A2,0(A4,D0.w) move.l A3,4(A4,D0.w) addq.w #1,D2 addq.l #1,A2 bra .wcloop .wgoback subq.w #1,D2 bmi .w5 move.w D2,D0 asl.w #3,D0 move.l 4(A4,D0.w),A0 tst.b (A0) beq .wgoback .w5 tst.w D2 bmi .wcret0 move.w D2,D0 asl.w #3,D0 move.l 0(A4,D0.w),A2 addq.l #1,A2 add.l #1,4(A4,D0.w) move.l 4(A4,D0.w),A3 addq.l #1,D2 bra .wcloop .w10 cmp.b #'?',D1 bne .w20 tst.b (A3) bne .wcbreak tst.w D2 bne .wgoback bra .wcret0 .w20 move.b (A3),D0 cmp.b #'A',D0 bcs .w21 cmp.b #'Z',D0 bhi .w21 or.b #$20,D0 .w21 move.b (A2),D1 cmp.b #'A',D1 bcs .w22 cmp.b #'Z',D1 bhi .w22 or.b #$20,D1 .w22 cmp.b D0,D1 beq .wcbreak tst.w D2 bne .wgoback bra .wcret0 .wcbreak tst.b (A2)+ bne .wcb1 subq.l #1,A2 .wcb1 tst.b (A3)+ bne .wcb2 subq.l #1,A3 .wcb2 bra .wcloop .wcret0 moveq.l #0,D0 .wcdone add.l #MAXB*2*8,sp movem.l (sp)+,D2/A2-A4 rts ; LOCKS ; ; { LOCKADDR STRUCTURE ; ulong Link; dynamic linking of blocked requests ; ubyte LockByte; bset to here ; ubyte Reserved; reserved for future use (flags?) ; EXTENSIONS FOR TASKLOCK ; uword Refs; reference count same-task has-locked ; ulong Task; task address ; } ; ; long var[3] = { 0, 0, 0 }; ; ; These routines work exactly like the lockaddr but maintain ; an additional reference count, allowing the same task to ; lock the same lock any number of times (the same number of ; unlocks are required to unlock the lock) ; ; Only one lock is available per structure ; ; TaskLock(&var[0]:A0) ; TaskUnlock(&var[0]:A0) _lTaskLock: move.l _SysBase,A1 ; task address used for ident move.l ThisTask(A1),A1 bset.b #0,4(A0) ; try to get lock fast beq .tl10 ; beq success cmp.l 8(A0),A1 ; failure, but is it the same task? beq .tl11 ; yes, success movem.l A0/A1,-(sp) ; failure, different task, block. moveq.l #0,D0 ; D0 = bit#, A0 = lock ptr bsr LA0 ; get lock the hard way movem.l (sp)+,A0/A1 .tl10 move.l A1,8(A0) ; success, store owner .tl11 add.w #1,6(A0) ; success, bump ref count rts ;;BREAKUP lockaddr.asm ; long var[2] = { 0, 0 }; ; ; These routines provide fast exclusive ; locks. Up to 8 independant locks may be used for ; each 4 byte address. ; ; LockAddr(&var[0]:A0) ; LockAddrB(bit:D0, &var[0]:A0) ; UnlockAddr(&var[0]:A0) ; UnlockAddrB(bit:D0, &var[0]:A0) ; TryLockAddr(&var[0]:A0) ; TryLockAddrB(bit:D0, &var[0]:A0) xref _LVOWait xref _LVOForbid xref _LVOPermit xdef _LockAddr xdef _LockAddrB xdef _TryLockAddr xdef _TryLockAddrB IFD LATTICE xdef @LockAddr xdef @LockAddrB xdef @TryLockAddr xdef @TryLockAddrB ENDC _TryLockAddrB: movem.l 4(sp),D0/A0 bra TLA0 _TryLockAddr: move.l 4(sp),A0 IFD LATTICE @TryLockAddr: ENDC moveq.l #0,D0 IFD LATTICE @TryLockAddrB: ENDC TLA0: bset.b D0,4(A0) ; attempt to gain lock bne .tla10 ; failure moveq.l #1,D0 rts ; success, return 1 .tla10 moveq.l #-1,D0 ; failure, return -1 rts _LockAddrB: movem.l 4(sp),D0/A0 ; bit: D0 lock: A0 bra LA0 _LockAddr: ; bit: 0 lock: A0 move.l 4(sp),A0 ; MAIN LOCK CODE IFD LATTICE @LockAddr: ENDC moveq.l #0,D0 IFD LATTICE @LockAddrB: ENDC LA0: bset.b D0,4(A0) ; attempt to gain lock bne .la10 ; failure rts ; success, done, rts (FAST) .la10 movem.l A2/A6,-(sp) ; failure (SLOW) (BLOCK) move.l _SysBase,A6 ; A6 = SYSBase FORBID bset.b D0,4(A0) ; try again after FORBID beq .la20 ; got it! ; Put linked list structure on stack move.w D0,-(sp) ; bit# 12(sp) move.l ThisTask(A6),-(sp) ; task# 8(sp) move.l A0,-(sp) ; &var 4(sp) move.l (A0),-(sp) ; Next (sp) move.l sp,(A0) ; (put at head of list) ; Loop Wait/re-attempt lock .la15 moveq.l #$10,D0 ; wait (semaphore signal) jsr _LVOWait(A6) move.w 12(sp),D0 ; try for lock move.l 4(sp),A0 bset.b D0,4(A0) bne .la15 ; loop until get it .la16 cmp.l (A0),sp ; unlink, find our node! beq .la18 move.l (A0),A0 bra .la16 .la18 move.l (sp),(A0) add.w #14,sp .la20 PERMIT movem.l (sp)+,A2/A6 rts ;;BREAKUP unlockaddr.asm ; TaskUnlock() works on an expanded lock (see TaskLock() above) ; while UnlockAddr[B] works on a basic lock. xdef _TaskUnlock _TaskUnlock: move.l 4(sp),A0 sub.w #1,6(A0) ; decrement reference count bne .tu10 ; non-zero, do not release lock yet moveq.l #0,D0 ; D0 = 0 (needed for ULW) move.l D0,8(A0) ; clear the owner field ; this repeats some of the unlock code bclr.b #0,4(A0) ; clear the lock move.l (A0),D1 ; Anybody waiting to get the lock? bne ULW ; yes, branch to unlock code .tu10 rts ; no, return immediately. xref _LVOSignal xref _LVOForbid xref _LVOPermit xdef _UnlockAddr xdef _UnlockAddrB IFD LATTICE xdef @UnlockAddr xdef @UnlockAddrB ENDC _UnlockAddrB: movem.l 4(sp),D0/A0 bra.s UL0 _UnlockAddr: move.l 4(sp),A0 IFD LATTICE @UnlockAddr: ENDC moveq.l #0,D0 IFD LATTICE @UnlockAddrB: ENDC UL0: bclr.b D0,4(A0) ; clear lock bit move.l (A0),D1 ; anybody waiting? beq .ulrts ; no, rts ULW: movem.l D2/A2/A6,-(sp) ; yes, wake 'm all up move.b D0,D2 ; D2 = bit# move.l _SysBase,A6 ; A6 = SYSBase FORBID move.l (A0),D1 ; get pointer again after FORBID beq .ul20 ; no, rts (close a window) .ul10 move.l D1,A2 ; A2 = node cmp.b 13(A2),D2 ; waiting on our bit #? bne .ul18 ; no move.l 8(A2),A1 ; yes, signal the node moveq.l #$10,D0 jsr _LVOSignal(A6) ; signal EVERYONE waiting .ul18 move.l (A2),D1 ; next bne .ul10 .ul20 PERMIT movem.l (sp)+,D2/A2/A6 .ulrts rts ; FindName2(list:D0, name:A0) ; ; Search the node list as in FindName(), but also ignore ; NULL ln_name entries, which FindName() does not do. This ; routine will also return NULL if given an uninitialized ; list header (completely zero'd). Finally, it will not ; bother to do a string compare if the two pointers are ; the same. xdef _FindName2 _FindName2: movem.l 4(sp),D0/A0 movem.l A2/A3,-(sp) move.l D0,A1 tst.l (A1) ; uninitialized list header beq .fn2fail .fn2loop move.l (A1),A1 ; get first/next node tst.l (A1) ; end of list? beq .fn2fail move.l LN_NAME(A1),D0 ; name beq .fn2loop ; NULL, skip cmp.l D0,A0 ; pointers are the same! beq .fn2succ ; don't bother w/cmp. move.l D0,A2 move.l A0,A3 .fn2l2 cmpm.b (A2)+,(A3)+ bne .fn2loop tst.b -1(A2) bne .fn2l2 .fn2succ move.l A1,D0 movem.l (sp)+,A2/A3 rts .fn2fail moveq.l #0,D0 movem.l (sp)+,A2/A3 rts END