Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 2.0 SOURCE/kern/abort.rtm
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

522 lines
13 KiB
Plaintext

;*************************************************************
;*
;* Terminate and Abort Specify Process Entry Points
;*
;*************************************************************
;============== ==============
sysreset_entry: ; System Reset
;============== ==============
xor dx,dx
mov cx,f_terminate
jmp osif
;=============== ===============================
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
jcxz terminate
jmp term_err
terminate: ;process terminated by abort
mov bx,rlr ;spec resumes execution here
cli ;interrupts off during stack switch
mov ss,p_uda[bx] ;reset the stack to top of UDA
mov sp,ulen
sti
mov p_prior[bx],abt_prior ;finish termination quickly
;abort spec can't force us
;to reenter terminate when
;we have best priority
mov bx,offset thrd_spb ;get ownership of thread
call sync_entry ;list before searching
xor dx,dx
mov bx,(offset thrdrt)-p_thread
mov ax,rlr
nxtchld:
mov bx,p_thread[bx] ;set all child process's p_parent
test bx,bx ! jz nochld ;field to 0
cmp p_parent[bx],ax
jne nxtchld
mov p_parent[bx],dx ;found a child, 0 its parent field
jmps nxtchld
nochld:
mov bx,offset thrd_spb
call unsync_entry
;set parent's child abort flag
mov bx,rlr ;if terminating process's
test p_flag[bx],pf_ctlc ;CTL_C flag is on, ie, we are
jz term_r1 ;terminating from an abort spec
and p_flag[bx],not pf_ctlc ;or control C
mov bx,p_parent[bx]
test bx,bx ! jz term_r1
or p_flag[bx],pf_childabort
term_r1:
mov u_error_mode,0feh ;call BDOS termination
mov cx,f_bdosterm
call osif
mov bx,offset q_spb
call sync_entry
call rlsmx ;release all MXqueues
mov bx,offset q_spb
call unsync_entry
mov bx,offset mem_spb ;get ownership of MEM
call sync_entry
mov mem_cnt,1 ;keep MEM from freeing
;the MEM_SPB
mov bx,offset thrd_spb ;get the MEM sync BEFORE
call sync_entry ;the THRD sync to avoid
;deadlock
mov cx,f_freeall ;free all memory except
call osif ;load stack and UDA
mov bx,rlr ;dispatcher does rest of
mov p_stat[bx],ps_term ;termination
jmp dsptch
term_err:
;--------
; entry: CX=1 then can't terminate because KEEP or SYS flag
; CX=0ffffh TEMPKEEP on, CTLC turned on
; called from TERMINATE_ENTRY and ABORT_SPEC_ENTRY
; after call to ABT_CHK:
dec cx ! jz term_err1
;TEMPKEEP and CTLC flag on
xor bx,bx ! mov cx,bx ;and process will terminate
ret ;itself, or needs CTLC information
term_err1:
mov cx,e_pd_noterm ;couldn't term because of
mov bx,0ffffh ! ret ;SYS or KEEP flags,
;CTLC is off
;================
abort_spec_entry: ;Abort the specified process
;================
; entry: DX = address of APB in the caller's U_WRKSEG
; exit: BX = 0 if success, 0FFFFH if failure
; CX = 0 " " , error code if failure
; 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,
; the abort fails. If the TEMPKEEP flag is on, set the CTLC flag
; and return. If the KEEP flag is on and not the TEMPKEEP flag,
; then fail.
; If the terminate code in DL on entry, is not 0ffh
; and the SYS 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.
; The terminating PD's priority is set to ABT_PRIOR,
; and the address of TERMINATE: is put on top of its UDA stack.
; This forces the terminating process to run next (it has the
; best priority in the system) and for it to resume execution
; at TERMINATE: on returning from the dispatcher.
push dx
mov bx,offset thrd_spb ; get ownership of thread
call sync_entry ; while searching
pop si ; U_WRKSEG:SI->APB
push ds ! mov ds,u_wrkseg
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
push cx ; save return code
jmps abt_unsync
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
push cx ; save return code
abt_unsync:
push bx ; BX=PD if found
mov bx,offset thrd_spb
call unsync_entry
pop bx
pop cx ; CX=0 if no PD found
jcxz abt_err1
; successfully found PD
pop dx ; DX = terminate code
mov ax,rlr ; we are aborting ourselves
cmp ax,bx ; jump to TERMINATE_ENTRY
jne abt_notus
jmp terminate_entry
abt_notus:
mov indisp,true ; stop dispatching
;pushf ! cli ; do not let process or another
; process (NO_ABORT_SPEC) change the
or p_flag[bx],pf_ctlc ; flags while testing and acting on them.
call abt_chk ; ok to abort this PD ?
jcxz abt_ok
;popf ; can't abort it - return
call ok_disp
jmps term_err
; The interrupt window above may be lessened if the TERMINATE_ENTRY
; code is moved to the dispatcher and the status is set to PS_TERM.
; Turning interrupts back on, the aborting process could come
; back into context. Before turning on TEMPKEEP it would check
; its status, if it is PS_TERM, then it goes to the dispatcher
; to terminate.
abt_ok: ; this process will be aborted
mov dl,p_stat[bx] ; call abort function based on status
mov dh,0 ! mov di,dx
add di,di
call cs:abort_tab[di] ; find via p_link and take PD off its list
;popf
call ok_disp ; process can't come back into context
; so interrupts are ok
jcxz abt_err2 ; couldn't find PD on list by indicated
mov indisp,false ; by P_STAT
mov p_prior[bx],abt_prior
; set to low priority
push es ; save calling process' UDA
mov es,p_uda[bx] ; UDA of PD being aborted
mov si,(ulen-2) ; reset stack to top of UDA
mov u_sp,si
mov u_ss,es
mov es:[si],offset terminate
; TERMINATE: will be executed when
; terminating process comes back into
; context
xor ax,ax ; on exit from dispatcher interrupts
mov u_flag_sav,ax ; will be off
mov u_inint,false ; return into context with a RET and
; not an IRET
pop es ; ES=calling PD's UDA
call abt_putdrl
xor bx,bx ; indicate sucess
jmp pdisp ; force abort to happen before we return
; since terminating process has better
; priority
abt_err1:
pop dx ; throw out termination code
abt_err2:
mov cx,e_no_pdname ; set TERM_ERR for other returns
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:
; entry: BX = PD addr to be aborted
; AH = cons
; exit: CX=0 if error
; BX preserved
;
; abort_specified process jump table
;
; Status
abort_tab dw abtrun ; 0 = ready list root
dw abtslp ; 1 = poll
dw abtdly ; 2 = delay
dw abtslp ; 3 = swap
dw abttrm ; 4 = term
dw abtrun ; 5 = sleep
dw abtslp ; 6 = dq
dw abtslp ; 7 = nq
dw abtflg ; 8 = flagwait
dw abtslp ; 9 = ciowait
dw abtslp ; 10 = sync
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
abtslp:
;------
; On list indicated by u_dparam
; Note: a PD in the SY_NEXT field will not be found
; and cannot be terminated. Usually the PD has TEMPKEEP on
; so it never gets this far.
push es ! mov es,p_uda[bx]
mov di,u_dparam
pop es ! jmps abt_common
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
abttrm:
;------
mov indisp,false
call pdisp ; we are terminating already
xor cx,cx ; make sure termination completes
jmps abt_tab_err ; before returning error
abtflg:
;------
xor cx,cx
mov di,u_dparam ; flag PD field asleep on
cmp bx,[di] ; if interrupts are allowed
jne aflg_err ; in this code, check DRL
inc flg_ignore[di] ; and RLR if not in flags
mov flg_pd[di],flag_off
inc cx
aflg_err:
ret
abt_common:
;----------
call find_pd ! jcxz abt_tab_err
;jmps snip_it
snip_it:
;-------
; Take PD out of linked list of PDs
; entry: 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 ; CX<>0
abt_tab_err:
;-----------
ret ; CX = 0
;
; End of abort_tab(le) functions
;
abt_putdrl:
;-------
; Puts PD on DRL
; entry: BX = PD to insert
; exit: BX preserved
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.
; entry: BX = offset of thread list root - p_thread
; DX = adr of name in u_wrkseg
; AH = console number
; ownership of thread sync
; exit: BX = PD
; CX = 0 failure
xor cx,cx
nxt_pdname:
push ax ; save console number
call findpdname_entry
pop ax
jcxz fnc_found_one ; CX = 0 is success from findpdname
xor cx,cx
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 ! ret ; success
find_pdthrd:
;-----------
; Find PD on thread list
; entry: BX = PD address we want
; ownership of thread sync
; exit: CX = 0 if not found
; BX prserved
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:
ret
find_pd:
;-------
; Find PD through link field, interrupts assumed off
; entry: BX = PD address
; DI = offset of list root - p_link
; exit: 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
; entry: BX = PD
; exit: DI = offset in RTM data of flag
; CX = 0 if failure
; BX preserved
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
ok_disp:
;-------
mov indisp,false
cmp drl,0
jz od_ret
call pdisp
od_ret:
ret
abt_chk:
;-------
; Check different PD flags for terminate or abort
; CTLC flag is on if called from ABORT_SPEC
; entry: BX = PD to possibly abort
; DL = termination code
; interrupts off if called from ABORT_SPEC
; exit: CX = 00000H if ok to abort
; 00001H IF NOT OK TO ABORT
; 0FFFFH IF TEMPKEEP
; BX = PD as on entry
; interrupts unchanged
xor cx,cx
mov ax,p_flag[bx] ;AX = PD flags
;test TEMPKEEP first
;for signaling KEEP process
;to terminate i.e., the TMP
;while in the CLI
test ax,pf_tempkeep ! jz ac_keep
or ax,pf_ctlc ;signal control C
dec cx ;temp keep return
jmps ac_ret
ac_keep:
test ax,pf_keep ! jnz ac_no
;not KEEP, test SYS
inc dl ! jz ac_ok ;if DL = 0ffh -> ok to terminate
test ax,pf_sys ! jz ac_ok ;DL<>0ffh & not sys-> ok to terminate
ac_no:
and ax,not pf_ctlc ;turn off ctlc
inc cx ;CX=1, can't terminate
ac_ret:
mov p_flag[bx],ax ;new flags if no termination
ac_ok:
ret
rlsmx:
;-----
; Release all MX queues owned by the terminating process
; called only from TERMINATE_ENTRY
; entry: we own the Queue SYNC
; exit: none
; To guard against queue deletes, and to make interrupt
; windows are smaller, we start over from the beginning of
; QLR after we write to an MXqueue that we own.
mov bx,rlr ;BX=running process
; pushf ! cli
mov si,(offset qlr)-q_link
rm_nxt:
mov si,q_link[si] ;SI=QD currently checking
test si,si ;end of list ?
jz rm_done
test q_flags[si],qf_mx ;is it an MX queue ?
jz rm_nxt
cmp bx,q_buf[si] ;do we own it ?
jne rm_nxt
; popf ;allow interrupts
push si ;put 2-word QPB on stack
xor ax,ax
push ax
mov dx,sp
mov cx,f_qwrite
push ds ;save DS
push ss ! pop ds ;DS=SS
call osif
pop ds ;restore DS
pop ax ! pop ax ;throw out 2-word QPB
jmps rlsmx ;start over from
;top of queue list
;a queue could have been
;deleted while we were writing
rm_done:
; popf
ret