;       SCCSID = @(#)smrpanot.asm       6.6 92/06/02
PAGE 60,132                             ;
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;************************************************************************
;
; Source File Name:     SMRPANOT.ASM
;
; Subroutine Name:      PARENTNOTIFY
;
; Descriptive Name:     Notify Parent Session of Child Termination
;
; Function:     Notify the parent session via the termination queue
;               provided during a DOSSTARTSESSION request.
;
; Notes:
;       Dependencies:   None
;
;       Restrictions:   None
;
; Change History:
;  @@A6  02/19/90  PTR SL88090 - Ignore high byte of Session ID
;  @MHW  09/13/90  PTR B715824 - In-line performance (MMIO) hooks
;  @CJ20 01/15/91  PTR B718336 Fix trap D cause FS not setup when no parent.
;  @D1200 01/23/91 CJJ, DCR 1200.2 Call Dos32WriteQueue for Dos32StartSession.
;  @GDW   08/26/91 PTR B725436 Fix to allow semaphore loop on INTERUPT
;  CJ59  03/18/92  PTR B734620 Trap when checking for parent session.
;  CJ62  05/28/92  PTR B736341 Save CX in WriteTermQueue.
;
; Entry Point:
;       Linkage:  EXTRN PARENTNOTIFY:NEAR
;                       CALL    PARENTNOTIFY
; Inputs:
;       AX      Termtype   Termination or exec failure
;       CX      SessionID  Terminated session ID
;       DX      ChildRC    Child termination return code
;       DS      RDATA
;       FS:SI   Parent's SGCB
;       GS:DI   Dying SGCB
;
; Exit Normal:
;       AX      0 - Switched to parent
;               1 - No switch occured
;
; Exit Errors:
;       None
;
; Effects:      All other registers preserved.
;
; Internal References:
;          Data:        SESDATA - Commom segment with active session data
;                                 returned from DOSSMGETSTATUS (GETQSTATUS)
;                                 sessionid   - session ID number
;                                 sessiontype - independent/parent/child
;                                               session
;                       RDATA   - Common data segment
;                                 parentpidtbl  - parent pid table
;                                                 (SMRPATBL.INC)
;                                   parentpid   - parent process ID
;                                   parenttermq - termination queue handle
;                                   parentexit  - parent process in exitlist
;                                 statusindex table (See SMRQSTAT.ASM)
;          Routines:
;
; External References:
;          Routines:    DOSALLOCSEG
;                       DOSGIVESEG
;                       DOSFREESEG
;                       DOSWRITEQUEUE
;                       DOSCLOSEQUEUE
;                       DOSSMSGSET
;                       DOSSMSGSWITCH
;
;
;************************************************************************
ifdef I1
;
;   Get offset to child session data
;   Get offset to parent session data
;   Get offset to parent pid table entry
;
;   IF (Session has a parent)
;      IF (parentexit e 0) AND
;      IF (normal termination)
;         IF (parenttermq ne 0)
;            DOSWRITEQUEUE (Send parent termination notification)
;         ENDIF
;      ENDIF
;
;      IF (No_Error)
;         PARENTSWITCH (Switch to parent)
;      ENDIF
;
;      IF (Terminated child session is bound)
;         DOSSMGSET (Break parent-child bond)
;      ENDIF
;
;      IF (parent session is a debugger)
;         Get number of active sessions
;         DOSSMGETSGCB (Get sgcb of first child)
;         REPEAT
;             IF (session debugged e parent session) AND
;             IF (session id e terminating session)
;                DX = session found
;         LEAVE
;             ENDIF
;                DOSSMGETSGCB (Get sgcb of next relative)
;         UNTIL (We are back at parent sg)
;      ENDIF
;
;      IF (debug session not found)
;         IF (sessionrelative[ChildSes] = Parent) AND
;         IF (sessionchild[Parent] = ChildSes) OR
;         IF (Parentexit ne 0)
;            IF (Parenttermq ne 0)
;               DOSCLOSEQUEUE (Close termination notification queue)
;               parenttermq = 0
;            ENDIF
;            parentpid = 0
;         ENDIF
;      ENDIF
;   ELSE
;      Indicate no switch
;   ENDIF
;
;   IF (this session is a parent)
;      get pointer to pid table
;      IF (termination queue specified)
;         DOSCLOSEQUEUE (Close termination queue)
;         parenttermq = 0
;      ENDIF
;      parentpid = 0
;   ENDIF
;
;
;************************************************************************
else

.386C
    NotifyQLength EQU WORD PTR 8
    ChildSession EQU WORD PTR 0
    ChildReturnCode EQU WORD PTR 2
    SMPanSessionID EQU WORD PTR 6       ; Offset on stack for dead session
    TermQParm1 EQU WORD PTR 0           ; Child Session ID
    TermQParm2 EQU WORD PTR 2           ; Child Process ID
    TermQParm3 EQU WORD PTR 4           ; Parent Session ID
    TermQParm4 EQU WORD PTR 6           ; Parent Process ID

    EXTRN PM_Present         : BYTE
    EXTRN MaxFullScrnGrps    : WORD     ; Maximum # of FS Screen Groups
    EXTRN PopUpBlockSem      : BYTE     ; Popup semaphore
    EXTRN TopMost            : DWORD    ; @ of TopMost SGCB
    EXTRN SMRoutSem          : DWORD    ; Shell/application sync. sem
    EXTRN WinQueryExtIDFocus : DWORD    ; Get extended SGID for window focus
    EXTRN WinSetExtIDFocus   : DWORD    ; Set ext. SGID for window focus

    EXTRN GETBOUNDSESSION    : NEAR     ; Get session bound to parent
    EXTRN FOREGROUNDFAMILY   : NEAR     ; Check if session's family is foregrnd
    EXTRN DOSSMGETMEM        : FAR      ; Allocate termination queue seg
    EXTRN DOSCLOSEQUEUE      : FAR      ; Close termination queue
    EXTRN DOSSMFREEMEM       : FAR      ; Free termination queue sel.
    EXTRN DOSSMGETSGCB       : FAR
    EXTRN DOSGIVESEG         : FAR      ; Give parent access to term seg
    EXTRN DOSFSRAMSEMCLEAR   : FAR      ; Release semaphore ownership
    EXTRN DOSFSRAMSEMREQUEST : FAR      ; Synchronize Shell/App. calls
    EXTRN DOSSMSGSET         : FAR      ; Break parent child bond
    EXTRN DOSSMSGSWITCH      : FAR      ; Switch to the parent session
    EXTRN DOSWRITEQUEUE      : FAR      ; Send termination notification
    EXTRN DOSFREESEG         : FAR      ; Free selector to termq seg.
    EXTRN DOSALLOCSEG        : FAR      ; Free selector to termq seg.
    EXTRN DO32BITWRITEQ      : FAR      ; 32 bit thunk for DosWriteQ     @D1200

.xlist
    INCLUDE SMRPATBL.INC                ; Session parent pid table
    INCLUDE INFOSEG.INC                 ; needed by smmmpha.inc         ;MHW
    INCLUDE SMMMPHA.INC                 ; Performance hook macros       ;MHW
.xcref
    INCLUDE SMRSGCB.INC
    INCLUDE SMRRDATA.INC                ; Router data declarations
    INCLUDE STRUC.INC
    INCLUDE ERROR2.INC                  ; Error code equates            ;@GDW
.cref
.list

CODE SEGMENT WORD PUBLIC 'CODE' USE16
    ASSUME CS:CODE,DS:RDATA,SS:NOTHING,ES:NOTHING,FS:NOTHING,GS:NOTHING

    PUBLIC PARENTNOTIFY
    PUBLIC PARENTNOTIFY_POSTDT

PARENTNOTIFY PROC NEAR

    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

    MMPHPreParentNotify                 ; Performance Hook (810Ah)      ;MHW

;   ************************************
;   *  GS:DI --> Dying session's SGCB  *
;   *  FS:SI --> Parent's SGCB         *
;   ************************************

;   ************************************************
;   *  Parent's exit list hasn't been invoked yet  *
;   ************************************************
;@CJ20;; MOV  BX, FS
;@CJ20;; .IF  < nonzero BX > NEAR       ; If session has a parent       ;CJ10

    TEST GS:[DI].SGCB_FamilyType, Child ; Dieing SG has a parent        ;@CJ20
    .IF < nz >  NEAR                                                    ;@CJ20
      .IF  < FS:[SI].SGCB_ParentExit eq No > AND NEAR
      .IF  < zero AX > NEAR             ; Normal termination            ;CJ10

;       ***********************************************
;       *  Parent requested termination notification  *
;       ***********************************************
        CWDE                            ; Zero out EAX                  ;CJ10
        .IF  < FS:[SI].SGCB_ParentTermQ ne AX >                         ;CJ10
          PUSH AX                       ; Don't Specify SID             ;CJ10
          PUSH EAX                      ; Don't Specify PID             ;CJ10
;CJ10     PUSH 0                        ; Normal termination request
          CALL WRITETERMQUEUE
          SUB  AX,AX                    ;                               ;CJ10
        .ENDIF                          ; Parent wanted notification
;CJ10   POP  AX                         ; Restore notification flag
      .ENDIF                            ; Parent Exit List not been invoked yet

      .IF  < zero AX >                  ; Switch to parent if appropriate? ;CJ10
        CALL PARENTSWITCH               ; AX = 0 Means switch occurred
        MOV  DX, AX                     ; Screen switch made notification
      .ENDIF

;     ******************************************
;     *  If terminated child session is bound  *
;     *  to the parent, break the bond         *
;     ******************************************
      .IF  < <BYTE PTR FS:[SI].SGCB_Bound> eq CL >                         @@A6
        PUSH FS:[SI].SGCB_ID            ; Parent session ID
        PUSH FS:[SI].SGCB_Bound         ; Terminated child session
;CJ10   PUSH 0                          ; No change to select status
        PUSH DWORD PTR 2                ; Break parent child bond       ;CJ10
        CALL DOSSMSGSET
      .ENDIF

;     *******************************************************
;     *  If last child terminating or parent is terminating *
;     *******************************************************
      MOV  BX, FS:[SI].SGCB_ID          ; Parent session ID

;     *******************************************************
;     *  Check to see if this is the last child in a chain  *
;     *  of apps being debugged by the parent. If so, we    *
;     *  will close the parent's termination queue.         *
;     *******************************************************
      PUSH DX                           ; Save screen switched flag
      XOR  DX, DX                       ; Preset to no other child being debugged
      .IF  < FS:[SI].SGCB_ParentExit e Parent_Is_Debugger > ; Parent debugger?
        PUSH DI                         ; Save DI

        LEA  AX, Local_Var2             ; @ return @ of SGCB
        PUSH SS
        PUSH AX
        PUSH FS:[SI].SGCB_FirstChild    ; Get first child
        PUSH SGID_Lookup + 8000H        ; Look up SGID not PID and      ;CJ10
        CALL DOSSMGETSGCB               ;   don't serialize QueueRamSem


        .REPEAT
          LES  DI, Local_Var2             ; ES:[DI]-Dying Child's Relative SGCBS
          .IF  < ES:[DI].SGCB_DebuggerSID e BX > AND ; Parent is debugger
          .IF  < ES:[DI].SGCB_ID ne CX > ; This isn't the dying SG
            MOV  DX, Yes                ; Indicate another child being debugged
          .LEAVE                        ; Stop search
          .ENDIF

          LEA  AX, Local_Var2           ; @ return @ of SGCB
          PUSH SS
          PUSH AX
          PUSH ES:[DI].SGCB_Relative    ; Get next relative
          PUSH SGID_Lookup + 8000H      ; Look up SGID not PID and      ;CJ10
          CALL DOSSMGETSGCB             ;   don't serialize QueueRamSem

        .UNTIL < ES:[DI].SGCB_Relative eq BX > ; Until we're back at parent
        POP  DI                         ; Restore DI
      .ENDIF

      .IF  < zero DX >                  ; If we did not find            ;CJ10
;       ***************************************************
;       *  We can close the parent queue if our parent's  *
;       *  not a debugger or if it is a debugger but we   *
;       *  are the last child being debugged.             *
;       ***************************************************
        .IF  < GS:[DI].SGCB_Relative eq BX > AND    ; any sessions being debugged
        .IF  < <BYTE PTR FS:[SI].SGCB_FirstChild> eq CL > OR ; other than  @@A6
        .IF  < FS:[SI].SGCB_ParentExit ne No >      ; ourselves then proceed
          .IF  < FS:[SI].SGCB_ParentTermQ ne Null > ; to close the queue
            PUSH FS:[SI].SGCB_ParentTermQ
            CALL DOSCLOSEQUEUE
            MOV  FS:[SI].SGCB_ParentTermQ, Null
            AND  FS:[SI].SGCB_Flags, NOT API_32bit  ; Reset flag in SGCB @D1200
          .ENDIF
          MOV  FS:[SI].SGCB_ParentPID, Null
        .ENDIF
      .ENDIF                            ; No other child being debugged

      POP  DX                           ; Restore screen switch made flag
    .ELSE                               ; Session has no parent
      MOV  DX, 1                        ; Say no switch has taken place
    .ENDIF                              ; End test if session has a parent

;   ******************************************
;   *  If this session is a parent, close    *
;   *  the termination queue if it has one.  *
;   ******************************************
    TEST GS:[DI].SGCB_FamilyType, Parent ; If this is a parent
    .IF  < nz >
;     ************************************
;     *  Get pointer to pid table entry  *
;     ************************************
      .IF  < GS:[DI].SGCB_ParentTermQ ne 0 > ; If termination queue specified
        PUSH GS:[DI].SGCB_ParentTermQ   ; Close the termination que
        CALL DOSCLOSEQUEUE
        MOV  GS:[DI].SGCB_ParentTermQ, 0 ; 0 termination que name in pid table
        AND  GS:[DI].SGCB_Flags, NOT API_32bit ;Reset flag in SGCB       @D1200
      .ENDIF                            ; End check for termination queue
      MOV  GS:[DI].SGCB_ParentPID, 0    ; 0 entry in pid table
    .ENDIF                              ; End test to see if this is a parent

    MOV  AX_Reg[-Local_Bytes], DX       ; Return flag screen switch made or not

    POP  ES
    POP  DS
    POPA

    MMPHPostParentNotify                ; Performance Hook (818Ah)      ;MHW

    LEAVE
    PARENTNOTIFY_POSTDT LABEL FAR
    RET

PARENTNOTIFY ENDP
endif

PAGE
;**************************************************************************
;
; Subroutine Name: DOSSMPARENTSWITCH
;
; Descriptive Name: Switch to Parent Session on Child Termination
;
; Function: Locate the closest living parent and switch to it when a child
;           session dies.
;
; Notes:
;
; Entry Point:
;        Linkage: EXTRN  DOSSMPARENTSWITCH:FAR
;                        CALL   DOSSMPARENTSWITCH
; Inputs:
;       CX     SessionID  Terminated session ID
;
; Exit Normal:
;       AX     0 - Switched to parent
;
; Exit Errors:
;       AX    >0 - No switch occured
;
; Effects: All other registers preserved.
;
; Internal References:
;          Data:
;          Routines:
;
; External References:
;          Routines:
;
;**************************************************************************
ifdef I1
;
;   DOSFSRAMSEMREQUEST (No-Wait for popup semaphore)
;   IF (PopUp Not In Progress)
;      DOSFSRAMSEMREQUEST (Wait for SMG router semaphore)
;      DOSSMGETSGCB (Get sgcb of terminated session)
;      IF (No error)
;         DOSSMGETSGCB (Get sgcb of terminated session's parent)
;         IF (No error)
;            Switch to parent if appropriate
;            PARENTSWITCH (Switch to parent if appropriate
;         ELSE
;            Set RC = Error_SMG_Session_Not_Found
;         ENDIF
;      ELSE
;         Set RC = Error_SMG_Invalid_SGID
;      ENDIF
;
;
;
;      DOSFSRAMSEMCLEAR (Popup Switch Blocking semaphore)
;      DOSFSRAMSEMCLEAR (Release synchronization semaphore)
;   ELSE
;      RC = Error_SMG_Session_Not_Foregrnd
;   ENDIF
;
;**************************************************************************
else

    PUBLIC DOSSMPARENTSWITCH
    PUBLIC DOSSMPARENTSWITCH_POSTDT
DOSSMPARENTSWITCH PROC FAR


    ENTER Local_Bytes,0
    PUSHA
    PUSH DS
    PUSH ES
    PUSH FS
    PUSH GS

    MOV  AX, RDATA                      ; Router common data selector
    MOV  DS, AX

    MMPHPreDOSSMParentSwitch            ; Performance Hook (8016h)      ;MHW

;   *********************************
;   *  Sychronize Shell/Application *
;   *  Session Manager API calls    *
;   *********************************
    .repeat                                                             ;@GDW
      PUSH DS                           ; Popup semaphore
      PUSH OFFSET PopUpBlockSem
      PUSH DWORD PTR 0                  ; Don't wait                    ;CJ10
;     PUSH 0                            ;                               ;CJ10
      CALL DOSFSRAMSEMREQUEST
    .until  <ax ne ERROR_INTERRUPT>                                     ;@GDW

    .IF  < zero AX >                    ; If popup not in progress      ;CJ10
      .repeat                                                           ;@GDW
        PUSH DS                         ; SMG router RAM semaphore
        PUSH OFFSET SMRoutSem
        PUSH DWORD PTR -1                                               ;CJ10
;CJ10   PUSH -1
        CALL DOSFSRAMSEMREQUEST
      .until  <ax ne ERROR_INTERRUPT>                                   ;@GDW

      LEA  AX, Local_Var2               ; @ return @ of SGCB
      PUSH SS
      PUSH AX
      PUSH SS:[BP].SMPanSessionID       ; Terminated session ID
      PUSH SGID_Lookup + 8000H          ; Look up SGID not PID and      ;CJ10
      CALL DOSSMGETSGCB                 ;  don't serialize QueueRamSem

      .IF  < zero AX >                  ; Dying SGCB found              ;CJ10
        LGS  DI, Local_Var2             ; GS:[DI] --> Dying SGCB

        LEA  AX, Local_Var2             ; @ return @ of SGCB
        PUSH SS
        PUSH AX
        PUSH GS:[DI].SGCB_ParentSID     ; Dying session's Parent's ID
        PUSH SGID_Lookup + 8000H        ; Look up SGID not PID and      ;CJ10
        CALL DOSSMGETSGCB               ;   don't serialize QueueRamSem

        .IF  < zero AX >                ; Dying SGCB found              ;CJ10
          LGS  DI, Local_Var2           ; ES:[DI] --> First Child's SGCB
;         *********************************************
;         *  GS:DI --> Dying session's SGCB           *
;         *  FS:SI --> Dying session's parent's SGCB  *
;         *********************************************
          CALL PARENTSWITCH             ; Switch to parent if appropriate
        .ELSE                           ; Parent's SGCB not found
          MOV  AX, Error_SMG_Session_Not_Found
        .ENDIF                          ; Parent's SGCB search
      .ELSE                             ; Dying SGCB not found
        MOV  AX, Error_SMG_Invalid_SGID
      .ENDIF                            ; Dying SGCB search

;     *************************************
;     *  Preserve start return code and   *
;     *  clear synchronization semaphore  *
;     *************************************
      PUSH AX                           ; Save return code

      PUSH DS                           ; Clear synchronization semaphore
      PUSH OFFSET SMRoutSem
      CALL DOSFSRAMSEMCLEAR

      PUSH DS                           ; Clear popup semaphore
      PUSH OFFSET PopUpBlockSem
      CALL DOSFSRAMSEMCLEAR

      POP  AX                           ; Restore Session Manager return code
    .ELSE                               ; There is a pop up in progress
      MOV  AX, Error_SMG_Session_Not_Foregrnd ; Say no switch
    .ENDIF                              ; If popup sem. owned test

    MOV  AX_Reg[-Local_Bytes], AX       ; Put AX on stack for POPA

    POP  GS                             ; Restore registers
    POP  FS
    POP  ES
    POP  DS
    POPA

    MMPHPostDOSSMParentSwitch           ; Performance Hook (8096h)      ;MHW

    LEAVE
    DOSSMPARENTSWITCH_POSTDT LABEL FAR
    RET  2
DOSSMPARENTSWITCH ENDP
endif

PAGE
;**************************************************************************
;
; Subroutine Name:      PARENTSWITCH
;
; Descriptive Name: Switch to Parent Session on Child Termination
;
; Function: Locate the closest living parent and switch to it when a child
;           session dies.
;
; Notes:
;
; Entry Point:
;        Linkage: EXTRN  PARENTSWITCH:NEAR
;                        CALL   PARENTSWITCH
; Inputs:
;       CX     SessionID  Dying Session's ID
;       DS     RDATA
;       GS:DI  Dying session's session data
;       FS:SI  Dying session's parent's session data
;
; Exit Normal:
;       AX     0 - Switched to parent
;
; Exit Errors:
;       AX   <>0 - No switch occured
;
; Effects: All other registers preserved.
;
; Internal References:
;          Data:
;          Routines:
;
; External References:
;          Routines:
;
;**************************************************************************
ifdef I1
;
;   IF (Windowed Session e Foreground) AND
;   IF (PM is present)
;      WINQUERYEXTIDFOCUS(Who has focus)
;   ENDIF
;
;   IF (ChildSes is Foreground) OR
;   IF (ChildSes has Focus) AND
;   IF (PM is present) AND
;   IF (Dying Session has Focus) OR
;   IF (Parent has Focus) AND
;   IF (Full Screen Session)
;      REPEAT
;         Get parent/child session data
;         Get parent of parent/child session data
;         Get parent pid table data
;      UNTIL (A parent does not exist) OR
;      UNTIL (We find a live parent)
;      UNTIL (We find a debugger)
;
;      IF (We found a living parent)
;         BX = Parent session
;         REPEAT
;            GETBOUNDSESSION (Get bound child session)
;            IF (Boundsession = Terminating Session)
;               BX = Parent session
;               AX = Parent session
;            ENDIF
;         UNTIL <Error>
;
;         Get session data for session id in BX
;         IF (PM is present)
;            WINSETEXTIDFOCUS (Give parent focus)
;         ELSE
;            DOSSMSGSWITCH (We will do the switch)
;         ENDIF
;      ENDIF
;   ENDIF
;
;**************************************************************************
else

    PUBLIC PARENTSWITCH                 ; Make public so we have the symbol
    PUBLIC PARENTSWITCH_POSTDT
PARENTSWITCH PROC NEAR
    ASSUME CS:CODE,DS:RDATA,SS:NOTHING,ES:NOTHING,FS:NOTHING,GS:NOTHING

;  *******************************************
;  *  If child session is in the foreground  *
;  *  switch to the parent session.          *
;  *******************************************
    ENTER Local_Bytes,0

    PUSHA                               ; Save registers
    PUSH ES
    PUSH FS
    PUSH GS

    MMPHPreParentSwitch                 ; Performance Hook (810Bh)      ;MHW

;   ******************************************
;   *  CX     SessionID  Dying Session's ID  *
;   *  DS     RDATA                          *
;   *  GS:DI  Dying session's SGCB           *
;   *  FS:SI  Dying session's parent's SGCB  *
;   ******************************************
    LES  BX, TopMost                    ; ES:[BX] --> TopMost SG
    MOV  AX, ES:[BX].SGCB_ID            ; Save topmost SGid             ;CJ59

;CJ59.IF  < <BYTE PTR GS:[DI].SGCB_ID> eq Shell_SG > AND ; Shell is foreground

    .IF  < AL eq Shell_SG > AND         ; Shell is foreground           ;CJ59
    .IF  < PM_Present eq Yes >
      LEA  DX, Local_Var2               ; Place to store extend SGID
      PUSH SS
      PUSH DX
      CALL WINQUERYEXTIDFOCUS
      MOV  AX, Local_Var2               ; Get extended session id       ;CJ59
    .ENDIF

    MOV  DX, Error_SMG_Session_Not_Foregrnd        ; Preset RC to say no switch

;CJ59   .IF  <<BYTE PTR GS:[DI].SGCB_ID> eq CL > OR    NEAR     ; Child foreground?
;CJ59   .IF  <<BYTE PTR GS:[DI].SGCB_ID> eq Shell_SG > AND NEAR ; Child window focus
;CJ59   .IF  < PM_Present eq Yes > AND NEAR            ; PM present
;CJ59   .IF  < BL eq CL > OR  NEAR                     ; SG w/Focus = Dieing SG
;CJ59   .IF  < BX eq GS:[DI].SGCB_ParentSID > AND NEAR ; SG w/Focus = Parent
;CJ59   .IF  < BL b <BYTE PTR MaxFullScrnGrps> > NEAR  ; Parent is Full Screen

    .IF  < AL eq CL > OR    NEAR        ; Child foreground?                ;CJ59
    .IF  < <BYTE PTR ES:[BX].SGCB_ID> eq Shell_SG > AND NEAR ; Shell is 4grnd;C59
    .IF  < PM_Present eq Yes > AND NEAR            ; PM present            ;CJ59
    .IF  < AX eq GS:[DI].SGCB_ParentSID > AND NEAR ; SG w/Focus = Parent   ;CJ59
    .IF  < AL b <BYTE PTR MaxFullScrnGrps> > NEAR  ; Parent is Full Screen ;CJ59
;     ****************************************
;     *  Traverse the session data until we  *
;     *  find a parent who is not dieing.    *
;     ****************************************

;     ********************************************
;     *  GS:DI --> This session's SGCB           *
;     *  FS:SI --> This session's parent's SGCB  *
;     *  ES:BX --> TopMost Session's SGCB        *
;     ********************************************
      XOR  AX, AX                       ; Preset to No_Error
      .Repeat
;       ***********************
;       *  Get Parent's SGCB  *
;       ***********************
        MOV  AX, GS:[DI].SGCB_ParentSID ; Parent's SGID
        LEA  DI, Local_Var2             ; @ return @ of SGCB
        PUSH SS
        PUSH DI
        PUSH AX                         ; Parent's SGID
        PUSH SGID_Lookup + 8000H        ; Look up SGID not PID and      ;CJ10
        CALL DOSSMGETSGCB               ;   don't serialize QueueRamSem

      .Leave < nonzero AX >                                             ;CJ10
        LGS  DI, Local_Var2
      .Until < GS:[DI].SGCB_ParentExit ne Parent_In_ExitList >

      .IF  < zero AX >                  ; If found non dying parent     ;CJ10
;       **********************
;       *  Switch to parent  *
;       **********************
        MOV  BX, GS:[DI].SGCB_ID        ; Place parent session in BX
        .REPEAT                         ; Get bound session if any
          CALL GETBOUNDSESSION
;         *****************************
;         *  BX Session to switch to  *
;         *  FS:SI --> SGCB of BX     *
;         *****************************
          .IF  < BL eq CL >             ; Bond is with terminating child?
            MOV  BX, GS:[DI].SGCB_ID    ; Don't honor the bond
            MOV  AX, NOT No_Error       ; None zero to exit loop
          .ENDIF
        .UNTIL < nonzero AX >           ; Get bound session until no more ;CJ10

        .IF  < PM_Present e Yes >       ; If PM is here
          PUSH BX                       ; Set window focus
          PUSH DWORD PTR 0              ; Switch handle not needed here ;CJ10
;CJ10     PUSH 0                        ; Switch handle not needed here
          CALL WINSETEXTIDFOCUS

        .ELSE                           ; PM not here so we do switch
          PUSH 0                        ; Switch to specified session
          PUSH BX                       ; Parent session ID
          PUSH GS:[DI].SGCB_DebuggerSID ; Debugger's SID
          PUSH DWORD PTR 0              ; Reserved parameter            ;CJ10
;CJ10     PUSH 0
          CALL DOSSMSGSWITCH
        .ENDIF                          ; PM presence test for switch

        XOR  DX, DX                     ; Indicate switch has occured
      .ENDIF                            ; End loop exit cause test
    .ENDIF                              ; FOREGROUND check

    MOV  AX_Reg[-Local_Bytes], DX       ; Save return code on stack

    POP  GS                             ; Restore Registers
    POP  FS
    POP  ES
    POPA

    MMPHPostParentSwitch                ; Performance Hook (818Bh)      ;MHW

    LEAVE
    PARENTSWITCH_POSTDT LABEL FAR
    RET

PARENTSWITCH ENDP
endif

PAGE
;**************************************************************************
;
; Subroutine Name: WRITETERMQUEUE
;
; Descriptive Name: Write to termination queue
;
; Function: Offers separate entry point to allow other routines to write
;           to a parent's termination queue. This capability was added
;           for DCR93 and the new trace option for debuggers.
;
; Notes:
;
; Change History:
;      @@A6 - 02/19/90 - PTR SL88090 - Ignore high byte of Session ID
;
;
; Entry Point:
;        Linkage: EXTRN  WRITETERMQUEUE:NEAR
;                        PUSH WORD PSID   - Parent's SID or 0
;                        PUSH WORD PPID   - Parent's PID or 0
;                        PUSH WORD ACTION - 1 or 0
;                        CALL   WRITETERMQUEUE
; Inputs:
;                  DS -----> RDATA
;                  FS:SI --> Session's parent's SGCB
;                  CX -----> Terminating session or SID of started child
;                  DX -----> Child termination code or PID of started child
;                  Stack will have a ParentNotifyWriteTerm structure on it
;
; Exit Normal:
;       AX     0 - No error
;
; Exit Errors:
;              Any error for the subroutines called within
;
; Invocation:
;                     PUSH  Parent's SID
;                     PUSH  Parent's PID
;                     PUSH  0 or 1
;                     CALL  WRITETERMQUEUE
;
; Effects: All other registers preserved.
;
; Internal References:
;          Routines:
;
; External References:
;          Routines: DOSALLOCSEG
;                    DOSGIVESEG
;                    DOSFREESEG
;                    DOSWRITEQUEUE
;
;**************************************************************************
ifdef I1
;
;   DOSALLOCSEG (Allocate a terminate queue segment)
;   IF (No_Error)
;      DOSGIVESEG (Give the parent process access)
;      IF (No_Error)
;         DOSWRITEQUEUE (Send parent termination notification)
;      ENDIF
;      DOSFREESEG (Free selector for queue segment)
;   ENDIF
;
;************************************************************************
else

    PUBLIC WRITETERMQUEUE
    PUBLIC WRITETERMQUEUE_POSTDT
WRITETERMQUEUE PROC NEAR

;   ****************************************
;   *  Allocate termination queue segment  *
;   ****************************************
    ENTER Local_Bytes,0

    PUSH DS                             ; Save session data address
    PUSH CX                                                             ;CJ62
    PUSH DX                             ; Preserve DX
    PUSH BX

    MMPHPreWriteTermQueue               ; Performance Hook (810Ch)      ;MHW

    LEA  BX, Local_Var2
    PUSH NotifyQLength                  ; Termination queue segment size
    PUSH SS                             ; Return selector on the stack
    PUSH BX
    PUSH 1                              ; Share segment with parent process
    CALL DOSALLOCSEG
    MOV  BX, Local_Var2                 ; Terminate notification queue sel.

;  *************************************************************
;  *  Give parent process access to queue termination segment  *
;  *************************************************************
    .IF  < zero AX >                                                    ;CJ10

      MOV  DS, BX                       ; Addressability to notify segment
      PUSH DS                           ; Push on stack for FreeSeg call
      XOR  CH, CH                       ; Ignore Session Type              @@A6
      MOV  DS:TermQParm1, CX            ; CX is either the child session being
                                        ; terminated or is the SID of the
                                        ; child being started
      MOV  DS:TermQParm2, DX            ; DX is either the return code for
                                        ; the terminating child or is the
                                        ; PID of the started child
      MOV  DX, SS:[BP].ParentNotSID     ;
      XOR  DH, DH                       ; Ignore Session Type              @@A6
      MOV  DS:TermQParm3, DX            ; DX is 0 or the SID of the
                                        ; parent doing the startsession.
      MOV  DX, SS:[BP].ParentNotPID
      MOV  DS:TermQParm4, DX            ; DX is 0 or the PID of the
                                        ; parent doing the startsession
      LEA  BX, Local_Var2
      PUSH DS                           ; Segment to give to process
      PUSH FS:[SI].SGCB_ParentPID       ; Process ID to give seg.
      PUSH SS                           ; Return selector on the stack
      PUSH BX
      CALL DOSGIVESEG

      MOV  BX, Local_Var2               ; Pop process segment selector

;     *******************************************************************
;     *  Note:  In a full 32 bit release, we MUST check to see if the   *
;     *         queue is a 16 bit queue.  This can be done by setting   *
;     *         a flag if DosStartSession was used, as opposed to the   *
;     *         32 Bit DosStartSession.  If it is a 16 bit queue, then  *
;     *         we'll have to do a 16 bit write!.                       *
;     *******************************************************************
;     *********************************************
;     *  Write notification to termination queue  *
;     *********************************************
      .IF  < zero AX >                                                  ;CJ10
        TEST FS:[SI].SGCB_Flags, API_32bit ;Was Dos32StartSession calld ;@D1200
        .IF  < nonzero >                  ; If so, call 32 bit WriteQ   ;@D1200
          PUSH FS                                                       ;@D1200
          CALL DO32BITWRITEQ                                            ;@D1200
          POP  FS                                                       ;@D1200
        .ELSE                             ; Else call 16 bit WriteQ     ;@D1200
          PUSH FS:[SI].SGCB_ParentTermQ   ; Term. queue handle
          PUSH SS:[BP].ParentTermRequest  ; = 0 if termination.
                                          ; = 1 if debugger write to termq
          PUSH NotifyQLength              ; Length of data
          PUSH BX                         ; Data address
          PUSH DWORD PTR 0                                                ;CJ10
          CALL DOSWRITEQUEUE
        .ENDIF                                                          ;@D1200
      .ENDIF
      CALL DOSFREESEG                   ; Free selector to termq seg.
    .ENDIF                              ; Endif no error for DOSALLOCSEG

    POP  BX                             ; Restore BX
    POP  DX                             ; Restore DX
    POP  CX                             ; Restore session ID            ;CJ62
    POP  DS

    MMPHPostWriteTermQueue              ; Performance Hook (818Ch)      ;MHW

    LEAVE
    WRITETERMQUEUE_POSTDT LABEL FAR
    RET  ParentNotTermSize              ; Change from 2 to 6

WRITETERMQUEUE ENDP

CODE ENDS
endif
    END
