
;*************************************************************
;* 
;*	Terminate and Abort Specify Process Entry Points
;*
;*			(D.H - July 1981)
;*
;*************************************************************

;==============		==============
sysreset_entry:		; System Reset
;==============		==============
	sub dx,dx
	; jmp terminate_entry

;===============	===============================
terminate_entry:	; Terminate - DX=terminate code
;===============	===============================
; This entry point is used for a process to terminate itself.  The
; code from the label 'TERMINATE:' on, is also used by a process to be
; terminated when it comes back into context, as set up by
; abort specified process.

	mov bx,rlr
	call abt_chk
	cmp cx,0 ! jle term_err
terminate:  pushf ! cli
	    mov bx,(offset thrdrt)-p_thread
	    mov ax,rlr
nchld:	    mov bx,p_thread[bx]
	    cmp bx,0 ! je nochld
		cmp p_parent[bx],ax ! jne nchld
		    mov p_parent[bx],0 ! jmps nchld
nochld:	    mov bx,ax
	    test p_flag[bx],pf_ctlc ! jz term_r1
		and p_flag[bx],not pf_ctlc
		mov bx,p_parent[bx]
		cmp bx,0 ! je term_r1
		    or p_flag[bx],pf_childabort
term_r1:    popf
	    mov si,rlr ! call rlsmx
	    mov u_error_mode,0feh
	    mov cx,f_bdosterm ! call mpmif
	    mov dx,offset mxmemqpb ! mov cx,f_qread
	    call mpmif
	    mov bx,rlr
	    mov mxmemowner,bx
	    mov mxmemcount,1
 	    mov p_stat[bx],ps_term
	    jmp dsptch
term_err:
	jcxz term_err1
	    sub bx,bx ! mov cx,bx ! ret
term_err1:
	mov cx,e_pd_noterm		
	mov bx,0ffffh ! ret

; end of terminate entry point


;================
abort_spec_entry:		;Abort the specified process
;================
; Set up the specified PD for termination when it is next in context.
; If the running PD is the same as the PD to abort, we can just use
; the terminate entry point.  Otherwise we use the Abort Parameter Block
; to find it.  If it cannot be found, name and console must both match,
; return failure.  If the keep flag is on, return failure.
; If the conditional terminate byte is not 0FFH
; (low byte of passed parameter) - meaning conditional
; termination - and the system flag is on in the PD to be aborted, then fail.
; The PD is taken off the list it is attached to via its link field.
; Its u_dparam is set to the termination code,  its priority is made the
; best possible and the address of abort_code: is pushed on its UDA stack.
; Abort_code: is shared by the terminate entry point.
;
;	Input:	DX = address of APB in the caller's u_wrkseg
;	Output: BX = 0 if success, 0FFFFH if failure
;		CX = 0 "     "   , err code if failure
	 
	push ds ! mov ds,u_wrkseg
	mov si,dx ! mov bx,apb_pd[si]	; get PD adr to abort
	mov cx,apb_term[si]		; get termination/memfree code
	mov ah,apb_cns[si]		; console from APB
	pop ds

	push cx				; save termination code
	test bx,bx ! jz abt_findit	; got a PD ID, but not verified
	call find_pdthrd		; find it on thread
	    jcxz abt_err
	jmps abt_foundpd
abt_findit:
 	    add dx,offset apb_pdname	; get adr of named PD
	    mov bx,offset thrdrt - p_thread ; find it on thread
	    call findpdnc		; look for PD name and console match
	        jcxz abt_err
abt_foundpd:
	cmp bx,rlr		; BX has verified PD address to abort
	jnz abt_notus
	    pop dx		; put term code in dx
	    jmp terminate_entry	; we are the PD to abort
abt_notus:
	call abt_chk		; ok to abort this PD ?
	pop dx			; if error - balance stack
	cmp cx,0 ! jle term_err	; in terminate entry point

	push dx

	mov dl,p_stat[bx]	; call abort function based on status
	mov dh,0 ! mov di,dx
	pop dx ! push dx

	add di,di
	pushf ! cli	
	call cs:abort_tab[di]	; find via p_link and take PD of its list
	popf			; allow interrupts
	    jcxz abt_err	; couldn't find PD, if several processes  
				; are attempting an abort of the same
				; process, only one of the abort calls
				; will find it

	; PD is only on thread list - can't come back into context
	; until put on drl.  It is safe to fiddle with its priority 
	; and stack

	pop dx			; recall termination code
	mov p_prior[bx],abt_prior
	and p_flag[bx],not pf_ctlc
	push es		 	; set to low priority
	mov es,p_uda[bx]	; uda of PD being aborted
	mov si,(ulen-2)
	mov u_sp,si
	mov u_ss,es
	mov u_inint,false
	mov es:[si],offset terminate ; terminate code
	mov u_dparam,dx		; put in terminate code
	pop es			; restore calling PD's UDA
	call abt_putdrl		; PD will now terminate itself when next
				; in context
	xor cx,cx		; indicate sucess
	mov bx,cx
	jmp pdisp		; force abort to happen before we return 

;	 Error exits for abort routines

abt_tab_err:			; if we can't find PD a status function,
	pop dx ! popf		; throw out return adr, restore flags.
abt_err:			; if error from above
	pop dx			; throw out termination code
	mov cx,e_no_pdname	; one kind of error returned
	mov bx,0ffffh
	ret

; The folowing are the abort handlers for a specific PD status.
; These labels are entered in the abort_tab(le) in the RTM data area. 
; Interrupts assumed off.
; For all of the following:
;	input:	BX = PD addr to be aborted
;		AH = cons
;	output: return if success
;		else a jump abort_tab_err:
;
; abort_specified process jump table
;
				; Status	
abort_tab	dw	abtrun	; 0  = ready list root
		dw	abtpol	; 1  = poll
		dw	abtdly	; 2  = delay
		dw	abtswp	; 3  = swap
		dw	abtrun	; 4  = term
		dw	abtrun	; 5  = sleep
		dw	abtdq	; 6  = dq
		dw	abtnq	; 7  = nq
		dw	abtflg	; 8  = flagwait
		dw	abtcns	; 9  = ciowait
abt_tablen	equ	offset $ - offset abort_tab

abtrun:			
;-------
; On ready list root or dispatcher ready list

	mov di,(offset rlr) - p_link
	call find_pd
	    jcxz abtr_drl
	jmps snip_it
abtr_drl:			; wasn't on rlr, try drl 
	mov di,(offset drl) - plink
	jmps abt_common

abtdq:
;------
; On a dq list

	xor al,al		; arg to find_pdq: to look on DQ lists
	jmps abtq_common

abtnq:
;-------
; On an nq list 

	mov al,0ffh		; to look on NQ lists

abtq_common:
	call find_pdq
	    jcxz abt_tab_err
	jmps snip_it		; BX,SI = PD;DI = last link
				; BP = adr of nq or dq root

abtpol:
;------
	mov di,offset plr - p_link
	jmps abt_common

abtflg:
;-------
	call fflgpd		; Find flag we are waiting on
	    jcxz abt_tab_err
	inc flg_ignore[di]
	mov flg_pd[di],flag_off
	ret

abtdly:
;------
	mov di,offset dlr - p_link
	call find_pd
	    jcxz abt_tab_err
	mov si,p_link[si]	; Fix wait field in next PD on dlr
	test si,si
	    jz ad_nofix		; Are there more PDs after the one
	mov dx,p_wait[si]	; being aborted on the DLR ?
	add dx,p_wait[bx]	; Add wait of aborting PD
	mov p_wait[si],dx	; New value in next PD on dlr
ad_nofix:
	jmps snip_it
	
abtswp:
;----
	mov di,offset slr - p_link
	jmps abt_common

abtcns:
;------
	mov al,p_cns[bx]	; Assume legal cns #
	call gccba
	lea di,(c_queue-p_link)[si]	; offset of root - p_link
	call findpd ! jcxz abtlst
	    jmps snipit
abtlst:	mov al,p_lst[bx]
	call gccba
	lea di,(c_queue-p_link)[si]
	jmps abt_common

gccba:		; get ccb address - AL=cio index
	xor ah,ah ! mov cx,ccblen
	mul cx			; figure offset for this console
	mov si,ax
	add si,ccb		; add base of ccb table
	ret

abtdrl:
;------
	mov di,(offset drl) - p_link
	;jmps abt_common

abt_common:
;----------
	call find_pd ! jcxz aterr1
	    jmps snip_it
aterr1:	jmp abt_tab_err

snip_it:
;-------
; Take PD out of linked list of PDs
;	input:	BX = PD being sniped out
;		DI = offset of previous PD or offset of root - p_link.

	mov dx,p_link[bx]	; DX = next link
	mov p_link[di],dx       
	ret

;
; End of abort_tab(le) functions
; 

abt_putdrl:
;-------
; Puts PD on DRL
;	Input:	BX = PD to insert

        pushf ! cli
	mov dx,drl
	mov p_link[bx],dx
	mov drl,bx
        popf ! ret

; Utility routines for abort entry point 

findpdnc:
;--------
; Find PD by name and console, via thread list.
;	input:	BX = offset of thread list root - p_thread
;		DX = adr of name in u_wrkseg
;		AH = console number	
;	output: BX = PD
;		CX = 0 failure

	pushf ! cli ! xor cx,cx
nxt_pdname:
	push ax ! call findpdname_entry ! pop ax
	jcxz fnc_found_one	; CX = 0 is success from findpdname
	    xor cx,cx ! popf
	    ret			; CX = 0 is failure from this routine
fnc_found_one:			; found PD w/ same name
	cmp p_cns[bx],ah	; chk for same console #
	    jnz nxt_pdname
	inc cx ! popf ! ret	; success

findpdq:
;-------
; find the queue list a PD is on
;	input:	BX = PD address
;		AL = ff if looking on NQ, 0 if on DQ lists
;	output:	DI = previous link,p_link[DI] = BX
;		SI = BX = PD address
;		CX = 0 if failure

	xor cx,cx
	mov di,(offset qlr) - q_link
	push di
fpdq_nxtq:			; DI is QD currently scanning
	pop di			; Recall QD adr
	mov di,q_link[di]	; Next QD adr
	test di,di		; End of queues ?
	    jz fpdq_no_pd
	test al,al		; DQ or NQ ?
	    jz fpdq_dq_lst
	lea di,(q_nq-p_link)[di]
	jmps fpdq_nxt_pd
fpdq_dq_lst:
	lea di,(q_dq-p_link)[di]	; root address of list to search
fpdq_nxt_pd:
	push di			; Save QD adr
	call find_pd
	jcxz fpdq_nxt_q		; PD not in this QD, try next QD
	pop dx			; Clean stack
fpdq_no_pd:			; find_pd returns non-zero CX if found
	ret

find_pdthrd:
; Find PD on thread list
;	input:	BX = PD address we want
;	output:	CX = 0 if not found

	pushf ! cli
	xor cx,cx
	mov di,offset thrdrt - p_thread
fp_next:
	mov di,p_thread[di]
	test di,di
	    jz fp_err
	cmp bx,di
	    jne fp_next
	inc cx
fp_err:
	popf ! ret


find_pd:
; Find PD on linked list of PDs.  Interrupts are assumed off
;	input:	BX = PD address
;		DI = offset of list root - p_link
;	output:	BX = SI = PD address
;		DI = Previous PD
;		CX = 0 if failure

        mov si,p_link[di]
        xor cx,cx
fpd_nxt_pd:
	test si,si		; SI could be zero to start
	    jz  fpd_not_found
	cmp si,bx		; Are addresses the same ?
	    jz fpd_found
fpd_nxt_lnk:
	mov di,si		; Save previous link
	mov si,p_link[si]
	jmps fpd_nxt_pd
fpd_found:
	inc cx
fpd_not_found:
	ret

fflgpd:
;-----
;	Find offset into flag table of flag waiting PD
;	input:	BX = PD
;	output:	DI = offset in RTM data of flag
;		CX = 0 if failure

	mov cl,nflags
	xor ch,ch
	mov di,flags
ffp_nxt_flg:
	cmp bx,flg_pd[di]	; assume legal flag
	jz ffp_pdfound
	    add di,flglen
	    loop ffp_nxt_flg
ffp_pdfound:
	    ret			; CX is 0 at end of loop instr
				; CX <> 0 if found
; end of abort specified process code

abt_chk:
;-------
; Check flags and termination code for abort,termination
;	Input:	BX = PD to possibly abort
;		DX = termination code
;	Output:	CX = 00000H if NOT ok to abort
;		     00001H IF OK TO ABORT
;		     0FFFFH IF tempkeep

	sub cx,cx ! mov ax,p_flag[bx]
	test ax,pf_keep ! jnz ac_n		;KEEP=ctlc off,no abort
	    test ax,pf_tempkeep ! jnz ac_tk	;TEMPKEEP=ctlc on,no abort
		test ax,pf_sys ! jz ac_y	;not SYS=abort
		    cmp dl,0ffh ! jne ac_n	;SYS and FF=abort,else no abort
ac_y:		inc cx ! ret
ac_tk:	    or p_flag[bx],pf_ctlc ! dec cx ! ret
ac_n:	and p_flag[bx],not pf_ctlc ! ret
