mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 09:24:19 +00:00
459 lines
13 KiB
Plaintext
459 lines
13 KiB
Plaintext
;*****************************************************
|
|
;*
|
|
;* Queue Routines
|
|
;*
|
|
;*****************************************************
|
|
|
|
; Each queue system entry point is mutually exclusive
|
|
; of the other queue system entry points.
|
|
; All the routines called in QUE2.RTM are
|
|
; subroutines of the entry points in QUE1.RTM and
|
|
; thus are called only when the process has ownership
|
|
; of the q system.
|
|
|
|
; If a process is already in the queue system another process
|
|
; will wait until the first process calls Q_UNSYNC.
|
|
; This allows us to keep interrupts on while using shared variables.
|
|
|
|
; To protect against terminating and potentially losing a QD,
|
|
; a message or neglecting to wake up a DQing or NQing
|
|
; process; a "no abort region" is entered whenever
|
|
; we obtain the queue system. In addition if we assign
|
|
; the queue system to a DQing or NQing process, the new owner
|
|
; of the q system is forced into a "no abort region". This
|
|
; makes the environment of the waking NQing or DQing process appear
|
|
; as if it never went to sleep.
|
|
|
|
; A note for the uninitiated: DQing is short for "Decoding from a Queue"
|
|
; or reading from a queue. NQing is short for "eNcoding to a Queue"
|
|
; or writing to a queue.
|
|
|
|
|
|
;=========== =======================
|
|
makeq_entry: ; Create a System Queue
|
|
;=========== =======================
|
|
; input : U_WRKSEG:DX = address of QD to create
|
|
; output: BX = 0 if okay , 0ffffh if error
|
|
; CX = error Code
|
|
|
|
call q_sync ;obtain q system, BX,DX preserved
|
|
|
|
call getqdaddr ;get QD and q buffer
|
|
jcxz qm_gotqd
|
|
jmp qm_err
|
|
qm_gotqd: ;DI->QD in SYSDAT
|
|
;make sure this queue doesn't
|
|
;already exist
|
|
qm_chk:
|
|
push es ;save UDA
|
|
mov es,sysdat
|
|
mov si,(offset qlr)-q_link
|
|
qm_nxt:
|
|
mov si,q_link[si] ;go down QLR to see if QD already
|
|
test si,si ! jz qm_go ;exists
|
|
push di ! push si ;save new QD and QLR ptr
|
|
mov cx,qnamsiz/2
|
|
add di,q_name ;ES:DI->QPB.NAME
|
|
add si,q_name ;DS:SI->QPB.NAME
|
|
repe cmpsw
|
|
pop si ! pop di ;restore QLR ptr and new QD
|
|
jne qm_nxt ;no match try next QD
|
|
|
|
pop es ;names match, restore UDA
|
|
call remqd ;QD pointed to by DS:DI
|
|
|
|
mov cx,e_q_inuse
|
|
jmps qm_err
|
|
|
|
qm_go: ;no match - alright to make this q
|
|
pop es ;ES=UDA
|
|
xor dx,dx ;initialize the QD
|
|
mov q_dq[di],dx
|
|
mov q_nq[di],dx
|
|
mov q_msgcnt[di],dx
|
|
mov q_msgout[di],dx
|
|
mov ax,qlr ;put QD on QLR
|
|
mov q_link[di],ax
|
|
mov qlr,di
|
|
xor bx,bx ;return success
|
|
jmps qm_ret
|
|
qm_err:
|
|
mov bx,0ffffh
|
|
qm_ret:
|
|
jmp q_unsync ;release q system; BX,CX preserved
|
|
|
|
;=========== ======================
|
|
openq_entry: ; Find an active Queue
|
|
;=========== ======================
|
|
; input: U_WRKSEG:DX = address of QPB
|
|
;
|
|
; output: sets QPB.QADDR to QD offset in SYSDAT
|
|
; BX = 0 if okay, 0ffffh if not
|
|
; CX = error Code
|
|
|
|
call q_sync ;obtain q system; BX,DX preserved
|
|
push es ;save UDA
|
|
mov es,u_wrkseg
|
|
mov si,(offset qlr)-q_link
|
|
mov di,dx ;ES:DI->QPB
|
|
qo_nqd:
|
|
mov si,q_link[si] ;go down QLR until QD name
|
|
test si,si ! jnz qo_cmp ;matches QPB name or end of QLR
|
|
pop es ;ES=UDA
|
|
mov cx,e_no_queue ;found end of QLR - can't open
|
|
jmps qo_err
|
|
qo_cmp:
|
|
push di ! push si ;compare names
|
|
mov cx,qnamsiz/2
|
|
add si,q_name ;DS:SI->QD.NAME
|
|
add di,qpb_name ;ES:DI->QPB.NAME
|
|
repe cmpsw
|
|
pop si ! pop di ;restore QD,QPB
|
|
jne qo_nqd ;try next QD if no match
|
|
|
|
test q_flags[si],qf_hide ;names match
|
|
jz noprot ;check for protection:
|
|
mov bx,rlr ;must be system process to
|
|
test p_flag[bx],pf_sys ;open q with QF_HIDE set
|
|
jnz noprot
|
|
pop es ;ES=UDA
|
|
mov cx,e_q_protected ;QF_HIDE and not SYS PD
|
|
jmps qo_err
|
|
noprot:
|
|
mov es:qpb_qaddr[di],si ;write the QD offset into
|
|
pop es ;ES=UDA
|
|
xor bx,bx ;the QPB_QADDR field
|
|
jmps qo_ret ;to open the q
|
|
|
|
qo_err: ;CX=error code
|
|
mov bx,0ffffh
|
|
qo_ret:
|
|
call q_unsync ;release q system; BX,CX preserved
|
|
ret
|
|
|
|
|
|
;============= =======================
|
|
deleteq_entry: ; Delete a System Queue
|
|
;============= =======================
|
|
; Takes QD off the QLR and place it in the QUL
|
|
; input: U_WRKSEG:DX = offset of QPB
|
|
; output: BX = 0 if ok, 0ffffh if error
|
|
; CX = error code
|
|
|
|
mov ax,es ;save UDA
|
|
mov es,u_wrkseg ;get QD address from user's
|
|
mov di,dx ;QPB
|
|
mov di,es:qpb_qaddr[di] ;DS:DI->QD (unverified)
|
|
mov es,ax ;ES=UDA
|
|
|
|
;Check for KEEP, SYS Flags
|
|
;DS:DI->QD
|
|
test q_flags[di],qf_keep
|
|
jnz qd_err1
|
|
test q_flags[di],qf_hide
|
|
jz qd_ok1
|
|
mov bx,rlr ;if hide flag then
|
|
test p_flag[bx],pf_sys ;SYS flag must be on in PD
|
|
jnz qd_ok1
|
|
|
|
qd_err1: mov cx,e_q_protected
|
|
mov bx,0ffffh
|
|
ret
|
|
qd_ok1:
|
|
push di ;DI->QD
|
|
call q_sync ;obtain q system; BX,DX preserved
|
|
pop di
|
|
mov ax,q_dq[di] ;if any process is NQing or
|
|
mov dx,q_nq[di] ;DQing we can't delete
|
|
or dx,ax ! mov cx,e_q_inuse
|
|
jnz qd_err2
|
|
|
|
mov bx,(offset qlr)-q_link
|
|
qd_nqd: ;look for QD on QLR
|
|
mov si,q_link[bx] ;DI=QD to delete
|
|
test si,si ! jz qd_noq
|
|
cmp si,di ! je qd_found
|
|
mov bx,si ! jmps qd_nqd ;try next queue
|
|
qd_found:
|
|
mov ax,q_link[di] ;found the queue, remove
|
|
mov q_link[bx],ax ;it from QLR
|
|
call remqd
|
|
xor bx,bx ;return success
|
|
jmps qd_ret
|
|
|
|
qd_noq:
|
|
mov cx,e_no_queue
|
|
qd_err2:
|
|
mov bx,0ffffh
|
|
qd_ret:
|
|
jmp q_unsync ;release q system
|
|
;ret ;BX,CX preserved
|
|
|
|
;=========== ============
|
|
readq_entry: ; Read Queue
|
|
;=========== ============
|
|
xor al,al ! jmps readq
|
|
|
|
;============
|
|
creadq_entry: ; Conditional Read Queue
|
|
;============
|
|
mov al,0ffh
|
|
; jmps readq
|
|
|
|
readq: ; Read message from queue
|
|
;----- -------------------------
|
|
; If no buffer is available the process
|
|
; making an unconditional READQ is placed into the DQ list.
|
|
;
|
|
; input: U_WRKSEG:DX = QPB
|
|
; AL = 0 if unconditional
|
|
; <> 0 if not
|
|
; output: BX = 0 if okay
|
|
; 0ffffh if error
|
|
; CX = Error Code
|
|
|
|
push ax ;save cond code
|
|
call q_sync ;get q system; BX,DX preserved
|
|
call queverify ;is the QPB valid ?
|
|
pop ax ;AL=cond code
|
|
mov si,dx ;U_WRKSEG:SI->QPB
|
|
jcxz qr_ver ;CX=0 QPB is ok
|
|
jmp qr_err ;CX=error code from
|
|
qr_ver: ;queverify
|
|
push es ;save UDA
|
|
mov es,u_wrkseg ;ES:SI->QPB
|
|
mov bx,es:qpb_qaddr[si] ;BX->QD
|
|
cmp q_msgcnt[bx],0 ;is there a msg to read ?
|
|
jne qr_readit
|
|
|
|
qr_wait:
|
|
pop es ;ES=UDA
|
|
test al,al ! jz qr_wait1 ;conditional read if AL <> 0
|
|
mov cx,e_q_empty
|
|
jmps qr_err
|
|
qr_wait1: ;ES=UDA
|
|
push bx ! push si ;QD, QPB
|
|
lea dx,q_dq[bx] ;DX=addr of DQ List
|
|
mov bl,ps_dq ;sleep status=DQ
|
|
call q_wait ;wait for a DQ
|
|
;we now own the q system
|
|
;and cannot be aborted
|
|
pop si ! pop bx ;QPB, QD
|
|
push es ;save UDA
|
|
mov es,u_wrkseg
|
|
qr_readit:
|
|
mov di,es:qpb_buffptr[si] ;ES:[DI]->user's queue buffer
|
|
mov cx,q_msglen[bx] ;ES=U_WRKSEG
|
|
test cx,cx ! jnz qr_lmsg ;check message length
|
|
xor ax,ax
|
|
test q_flags[bx],qf_mx ;msglen=0, check for MX q
|
|
jz qr_end
|
|
mov ax,rlr ;its a MX queue
|
|
mov q_buf[bx],ax ;BUF = PD addr of owner
|
|
xor ax,ax
|
|
jmps qr_end
|
|
qr_lmsg: ;msglen > 0
|
|
mov ax,q_msgout[bx] ! push ax ;MSGOUT is # of message to read
|
|
mul cx ! add ax,q_buf[bx] ;compute its start in buffer
|
|
mov si,ax
|
|
rep movsb ;move to QPB buffer
|
|
pop ax ! inc ax ;set MSGOUT to next message
|
|
cmp ax,q_nmsgs[bx] ;circular buffers, so
|
|
jne qr_end ;check for wrap around
|
|
xor ax,ax
|
|
qr_end:
|
|
pop es ;ES=UDA
|
|
mov q_msgout[bx],ax
|
|
dec q_msgcnt[bx]
|
|
lea dx,q_nq[bx]
|
|
call q_assign_sync ;give the queue system to
|
|
;first NQing process if any,
|
|
call q_unsync ;release q system if we still
|
|
;own it, exit no abort region
|
|
xor bx,bx ;indicate success
|
|
ret
|
|
|
|
qr_err:
|
|
call q_unsync ;release q system, exit no abort
|
|
;region, BX,CX preserved
|
|
mov bx,0ffffh ;indicate error
|
|
ret
|
|
|
|
;============ =============
|
|
writeq_entry: ; Write Queue
|
|
;============ =============
|
|
xor al,al ! jmps writeq
|
|
|
|
;============= =========================
|
|
cwriteq_entry: ; conditional Write Queue
|
|
;============= =========================
|
|
mov al,0ffh
|
|
;jmps writeq
|
|
|
|
writeq: ; Write message to queue
|
|
;------ ------------------------
|
|
; If no buffer is available when making an unconditional
|
|
; WRITEQ call, the calling process is placed into the NQ list.
|
|
;
|
|
; input: U_WRKSEG:DX = QPB
|
|
; AL = 0 if unconditional
|
|
; <> 0 if not
|
|
; output: BX = 0 if okay
|
|
; 0ffffh if error
|
|
; CX = Error Code
|
|
|
|
push ax ;save cond code
|
|
call q_sync ;get queue system
|
|
;BX,DX preserved
|
|
call queverify ;is the QPB valid ?
|
|
pop ax ;AL = cond code
|
|
mov di,dx ;U_WRKSEG:DI->QPB
|
|
jcxz qw_ver ;CX=0 QPB is ok
|
|
jmp qw_err ;CX=error code from
|
|
qw_ver: ;queverify
|
|
push es ;save UDA
|
|
mov es,u_wrkseg ;ES:DI->QPB
|
|
mov bx,es:qpb_qaddr[di] ;BX->QD
|
|
mov cx,q_msgcnt[bx]
|
|
cmp cx,q_nmsgs[bx] ;is there a buffer to write ?
|
|
jne qw_writeit
|
|
|
|
qw_wait:
|
|
pop es ;ES=UDA
|
|
test al,al ! jz qw_wait1 ;conditional read if AL <> 0
|
|
mov cx,e_q_full
|
|
jmps qw_err
|
|
qw_wait1: ;ES=UDA
|
|
push bx ! push di ;save QD, QPB
|
|
lea dx,q_nq[bx] ;DX=addr of NQ List
|
|
mov bl,ps_nq ;sleep status=NQ
|
|
call q_wait ;sleep on NQ List
|
|
;q system is assigned to us,
|
|
;we are in no abort region
|
|
;by DQing process that woke us
|
|
pop di ! pop bx ;QPB,QD
|
|
push es ;save UDA
|
|
mov es,u_wrkseg
|
|
qw_writeit:
|
|
mov si,es:qpb_buffptr[di] ;U_WRKSEG:[SI]->user's queue buffer
|
|
mov cx,q_msglen[bx] ;ES=U_WRKSEG
|
|
test cx,cx ! jnz qw_lmsg ;check message length
|
|
test q_flags[bx],qf_mx ;msglen=0, check for MX q
|
|
jz qw_end
|
|
xor ax,ax
|
|
mov q_buf[bx],ax ;its a MX queue
|
|
jmps qw_end ;BUF = 0
|
|
|
|
qw_lmsg: ;msglen > 0
|
|
mov ax,q_msgout[bx]
|
|
add ax,q_msgcnt[bx] ;AX = # of message to write
|
|
cmp ax,q_nmsgs[bx] ;check for wrap around
|
|
jb qw_move
|
|
sub ax,q_nmsgs[bx]
|
|
qw_move:
|
|
mul cx ! add ax,q_buf[bx] ;compute its start in buffer
|
|
mov di,ax ;DI offset of new msg in buffer
|
|
mov ax,ds ! mov dx,es
|
|
mov es,ax ! mov ds,dx ;ES=SYSDAT, DS=U_WRKSEG
|
|
rep movsb ;move to QPB buffer
|
|
mov ax,es ! mov ds,ax ;DS=SYSDAT
|
|
qw_end:
|
|
pop es ;ES=UDA
|
|
inc q_msgcnt[bx] ;one more message in the queue
|
|
lea dx,q_dq[bx] ;wake DQing process if any
|
|
call q_assign_sync
|
|
call q_unsync ;release q system if we still
|
|
xor bx,bx ;own it, exit no abort region
|
|
ret ;BX=0: success
|
|
|
|
qw_err:
|
|
call q_unsync ;release q system; exit no abort
|
|
;region BX,CX preserved
|
|
mov bx,0ffffh ;indicate error
|
|
ret
|
|
|
|
|
|
q_wait: ;wait on DQ or NQ list
|
|
;------
|
|
; entry: DX = list to wait on
|
|
; BL = sleep status
|
|
; calling process owns queue system through
|
|
; a call to q_sync
|
|
|
|
; Queue message or buffer space is not available.
|
|
; Give up queue system and sleep on DQ or NQ list, but
|
|
; do not allow any other process to read or write to a queue
|
|
; until we get on the sleep list.
|
|
|
|
|
|
pushf ! cli ;keep abort spec from running ...
|
|
push bx ! push dx ;save sleep status, list address
|
|
call q_unsync ;does not go to dispatcher, we can be
|
|
pop dx ! pop bx ;aborted once on sleep list
|
|
call sleep_entry ;go to dispatcher
|
|
popf ;come back after q_assign call
|
|
ret ;Q_ASSIGN: wakes us up when resource
|
|
;is ready
|
|
|
|
q_sync: ;obtain ownership of q system
|
|
;------
|
|
; entry: interrupts should be on
|
|
; ES=UDA
|
|
; exit: we own the queue system for make,open,read,write,delete
|
|
; queue operations, interrupts unchanged
|
|
; BX,DX preserved - usually entry parameters
|
|
|
|
push bx ! push dx
|
|
call no_abort_entry ;we cannot abort while in the queue system
|
|
mov bx,offset q_spb
|
|
call sync_entry
|
|
pop dx ! pop bx
|
|
ret
|
|
|
|
|
|
q_unsync: ;release the queue system
|
|
;-------- ;to other processes
|
|
; entry: interrupts can be or off
|
|
; exit: interrupts unchanged,
|
|
; have not gone to dispatcher,
|
|
; BX,CX preserved - usually return codes
|
|
|
|
push bx ! push cx
|
|
mov bx,offset q_spb
|
|
call unsync_entry ;wait for queue system
|
|
call ok_abort_entry ;allow calling PD to be terminated
|
|
pop cx ! pop bx
|
|
ret
|
|
|
|
|
|
q_assign_sync:
|
|
;-------------
|
|
; entry: DX = address of DQ or NQ list to give the queue
|
|
; exit: none
|
|
|
|
; Assign is used so a process is forced to read or write
|
|
; after DQing or NQing. Otherwise an awakening DQing or NQing
|
|
; process could be deleted, leaving a message or buffer space
|
|
; available with other processes still DQing or NQing.
|
|
; This message or buffer space would never be reclaimed.
|
|
; To prevent this situation, the waking DQing or NQing process
|
|
; is kept from aborting and assigned the QSPB. Note
|
|
; it is ok for a process to be aborted while it is on the NQ or
|
|
; DQ list before this routine is called.
|
|
|
|
pushf ! cli ;keep abort spec from terminating
|
|
mov bx,dx ;waking process
|
|
mov dx,[bx] ;first process on list
|
|
test dx,dx ;is there a process to wake?
|
|
jz qa_ret
|
|
push bx ;save list root
|
|
call no_abort_spec_entry ;can not abort while in queue
|
|
pop dx ;system
|
|
popf ;interrupts are ok now -
|
|
mov bx,offset q_spb ;present owner and next owner
|
|
jmp assign_sync_entry ;have TEMPKEEP on
|
|
|
|
qa_ret:
|
|
popf
|
|
ret
|