;************************************************************* ;* ;* 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