;       SCCSID = @(#)smrpexit.asm       6.1 90/11/18
;       SCCSID @(#)smrpexit.asm 6.6 90/05/18
PAGE 60,132                             ;
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;************************************************************************
;
; Source File Name:     SMRPEXIT.ASM
;
; Subroutine Name:      PARENTEXITLIST
;
; Descriptive Name:     Parent application termination cleanup
;
; Function:     A parent process in a parent session has died.
;               Ensure that all the child sessions have been
;               terminated.
;
; Notes:
;       Dependencies:   None
;
;       Restrictions:   None
;
;       Change History:
;
;       @TL6 - 03/01/90 - DCR 704 - Merge SMG/SSW instance data into OS2CHAR
;       @JK1 - 05/03/94 - D 82819 - Cleanup parent PID if DOSSTOPSESSION fails.
;
; Entry Point:
;       Linkage:  via DOSEXITLIST
;
; Inputs:
;       None
;
; Exit Normal:
;       None
;
; Exit Errors:
;       None
;
; Effects:      All other registers preserved.
;
; Internal References:
;          Data:        RDATA - Common data segment
;                               parentpidtbl  - parent pid table (SMRPATBL.INC)
;                               parentpid  - process ID
;                               parentexit - parent process in exitlist
;          Routines:    DOSSTOPSESSION
;
; External References:
;          Data:        Local information segment (LIS_CurScrnGrp,
;                       LIST_CurProcID)
;          Routines:    DOSEXITLIST
;                       DOSSEMCLEAR
;                       DOSSEMWAIT
;                       DOSSUBFREE
;
;************************************************************************
ifdef I1
;
;   WHILE (RB is written or almost written)
;      Get address of request block from INSTANCE data
;      Set terminated_flag on in request block[x]
;      DOSSEMCLEAR (reqblocksem2[DI]) allow shell to proceed
;   ENDWHILE (RBs have not been updated)
;
;   WHILE (all reqblocks written to que have not been acted on)
;      Get address of request block from INSTANCE data
;      IF (reqqueuestatus[DI] e rqwritten)
;         REPEAT
;            DOSSEMWAIT (req_synchrosem[DI]) - wait for smgsgstr to allow
;                                              us to clear all semaphores
;         UNTIL (Not Error_Interrupt)
;      ENDIF
;
;      IF (reqqueuestatus[DI] ne rqalmostwritten)
;         DOSSUBFREE (Free request block)
;      ENDIF
;   ENDWHILE (RBs written to queue have not been acted on)
;
;   Get offset to session parent pid table entry
;   IF (parentpid = LIS_CurProcID)
;      parentexit = parent_is_dead  (Use OR function to avoid
;                   destroying information about debugger status)
;      DOSSTOPSESSION (Terminate all the parents children)
;      IF (ERROR_SMG_SESSION_NOT_PARENT) AND
;      IF (Parentpid = LIS_CurProcID)
;         parentpid = 0
;      ENDIF
;   ENDIF
;   DOSEXITLIST (parent exitlist is complete)
;
;************************************************************************
else

.386C
    EXTRN LocalSelector  : WORD         ; Selector to LDT
    EXTRN SMG_INSTANCE   : DWORD        ; SMG/SSW instance data @       ;@TL6

    EXTRN DOSSTOPSESSION : FAR          ; Ensure all children are dead
    EXTRN DOSEXITLIST    : FAR          ; Parent exit list proc complete
    EXTRN DOSSUBFREE     : FAR          ; Free allocated storage
    EXTRN DOSSEMCLEAR    : FAR
    EXTRN DOSSEMWAIT     : FAR
    EXTRN DOSSUBFREE     : FAR
    EXTRN DOSSMGETSGCB   : FAR
    EXTRN DOSSMFREEMEM   : FAR
.xlist
.xcref
    INCLUDE ERROR.INC                   ; Error code for ERROR_INTERRUPT
    INCLUDE ERROR2.INC                  ; Error code equates
    INCLUDE INFOSEG.INC                 ; Information segment definitions
    INCLUDE SMRREQB.INC                 ; Request block equates
    INCLUDE SMRRDATA.INC                ; Router data declarations
    INCLUDE SMRSGCB.INC
    INCLUDE STRUC.INC
    INCLUDE OS2INST.INC                 ; Instance data segment         ;@TL6
.cref
.list

CODE    SEGMENT WORD PUBLIC 'CODE' USE16                                ;@TL6
    ASSUME CS:CODE,DS:NOTHING,SS:NOTHING,ES:NOTHING                     ;@TL6

    PUBLIC PARENTEXITLIST
PARENTEXITLIST PROC FAR

    Local_Bytes EQU 4
    Local_Var1 EQU SS:[BP][-2]          ; Local variable on stack
    Local_Var2 EQU SS:[BP][-4]          ; Local variable on stack

    ENTER Local_Bytes,0

    PUSHA                               ; Save registers
    PUSH DS
    PUSH ES

    MOV  AX, RDATA                      ;                               ;@TL6
    MOV  DS, AX                         ;                               ;@TL6
    LDS  BX, DS:SMG_INSTANCE            ; Get access to INSTANCE data   ;@TL6
    XOR  DX, DX                         ; DX = # of ReqBlocks written to queue
    MOV  SI, BX                         ; Save instance data offset     ;@TL6

;   *****************************************************
;   * Look at all the request blocks, addresses stored  *
;   * in INSTANCE data, and set the terminated flag.    *
;   *****************************************************
    MOV  CX, [SI].Next_Slot             ; Get next available slot #     ;@TL6
    .WHILE <ncxz>                       ; Check all req blocks          ;@TL6
;@TL6 MOV  DI, CX                       ; Get Slot # into DI
;@TL6 SHL  DI, 2                        ; Convert to offset in INSTANCE data
      LES  DI, [SI].Slots               ; ES:[DI] --> Request Block     ;@TL6
      MOV  ES:[DI].ReqTermFlag, Yes     ; Indicate process died

;     *************************************************************
;     *  Clear reqblocksem2 just in case shell is waiting on it.  *
;     *************************************************************
      ADD  DI, OFFSET ReqBlockSem2
      PUSH ES
      PUSH DI                           ; Offset of Semaphore
      CALL DOSSEMCLEAR                  ; Allow shell to continue

      ADD  SI, 4                        ; Next slot pointer             ;@TL6
      DEC  CX                           ; Increment loop counter        ;@TL6
    .ENDWHILE                           ; Get next request block

;   **********************************************************************
;   * We have to wait for the shell to read all the request blocks that  *
;   * we've written to the queue before we can deallocate the memory.    *
;   * So, do a semwait on all the request blocks that have been written  *
;   * to the queue.  If a request block is marked 'almost written', we   *
;   * don't know if it was or if it wasn't, so we can't wait on it's     *
;   * semaphore, and therefore, can't deallocate its memory.             *
;   **********************************************************************
    MOV  CX, [BX].Next_Slot             ; Get next available slot #     ;@TL6
    .WHILE <ncxz>                       ; For all request blocks        ;@TL6
;     ******************************************************************
;     *  Get the address of the request block from the INSTANCE data.  *
;     ******************************************************************
;@TL6 MOV  DI, CX                       ; Get Slot # into DI
;@TL6 SHL  DI, 2                        ; Convert to offset in INSTANCE data
      LES  DI, [BX].Slots               ; ES:[DI] --> Request Block     ;@TL6

;     ****************************************************
;     * If request was written, wait on req_synchrosem.  *
;     ****************************************************
      .IF  < ES:[DI].ReqQueueStatus e RqWritten > ; If written to queue
;@TL6   MOV  SI, DI                     ; Start of request block
        LEA  SI, [DI].Req_SynchroSem    ; Offset from ES                ;@TL6
        .REPEAT                         ; Do until cleared correctly
          PUSH ES
          PUSH SI
          PUSH DWORD PTR -1                                             ;CJ10
;CJ10     PUSH -1
          CALL DOSSEMWAIT
        .UNTIL < AX ne Error_Interrupt > ; In case cleared by interrupt
      .ENDIF                            ; If written test

;     *******************************************************************
;     * Deallocate memory used for the request block.  If the status of *
;     * the request block is almostwritten, we cannot deallocate it,    *
;     * since we don't know if the shell read it or not, and we can't   *
;     * wait on its synchrosem since we're not sure if the shell will   *
;     * ever clear it.                                                  *
;     *******************************************************************
      .IF  < ES:[DI].ReqQueueStatus ne RqAlmostWritten >
        MOV  AX, ES:[DI].ReqLength      ; # of bytes in header
        ADD  AX, ES:[DI].ReqParms       ; # of bytes in rest of request bloc
        PUSH ES                         ; Selector of memory to free
        PUSH DI                         ; Offset of memory to free (Req. Blk
        CALL DOSSMFREEMEM               ; Free the request block
      .ENDIF

      ADD  BX, 4                        ; Next slot pointer             ;@TL6
      DEC  CX                           ; Next request block            ;@TL6
    .ENDWHILE                           ; Loop until CX = Next_Slot     ;@TL6

    MOV  AX, RDATA
    MOV  DS, AX                         ; Access to global data

    MOV  AX, LocalSelector              ; @ of LDT
    MOV  ES, AX
    MOV  BX, ES:LIS_CurScrnGrp          ; Current session #

;   **********************
;   *  Get Current SGCB  *
;   **********************
    LEA  SI, Local_Var2                 ; @ return @ of SGCB
    PUSH SS
    PUSH SI
    PUSH BX                             ; SGID
    PUSH SGID_Lookup                    ; Look up SGID not PID
    CALL DOSSMGETSGCB

    .IF  < zero AX >                    ; If SGCB still exists          ;@TL6
      LDS  SI, Local_Var2               ; FS:[SI] --> Parent's SGCB
      MOV  CX, [SI].SGCB_ParentPID      ; Get parent PID from SGCB

;     ***************************************************
;     *  Kill all children if this is a parent process  *
;     ***************************************************
      .IF  < CX eq ES:LIS_CurProcID >

;       ***********************************************************
;       *  OR a 1 into field to allow debugger bit to remain set  *
;       ***********************************************************
        OR   [SI].SGCB_ParentExit, Parent_In_ExitList ; Non-zero = parent is dead
        PUSH 1                          ; Stop all children
        PUSH BX                         ; Session Number
        CWDE                            ; Reserved Double Word     ;@TL6,CJ10
        PUSH EAX                        ;   of zeroes              ;@TL6,CJ10
        CALL DOSSTOPSESSION

;       ***********************************************
;       *  Clean up parent pid table for this entry.  *
;       ***********************************************
        .IF  < nonzero AX > AND                                         ;@JK1
        .IF  < CX eq ES:LIS_CurProcID >
          MOV  [SI].SGCB_ParentPID, 0
        .ENDIF
      .ENDIF
    .ENDIF                              ; SGCB existance test

    POP  ES                             ; Restore registers
    POP  DS
    POPA

;   ****************************************************
;   *  Notify DOSEXIT that PARENTEXITLIST is complete  *
;   ****************************************************
    MOV  AX,CS                                                          ;@TL6
    OR   AX,1                           ; Exitlist must be in Ring 3    ;@TL6
    PUSH 3                              ; Finished indicator
    PUSH AX                             ; Selector to program           ;@TL6
    PUSH OFFSET PARENTEXITLIST          ; Offset of program
    CALL DOSEXITLIST

    LEAVE
    RET

PARENTEXITLIST ENDP

CODE    ENDS                                                            ;@TL6
endif
    END
