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

;***************************************************************************
;
; Source File Name:     SMGCWAIT.ASM
;
; Subroutine Name:      DOSSMCHILDWAIT
;
; Descriptive Name:     Wait until one of the Session Manager's
;                       children terminate or wait until the
;                       specified command subtree terminates.
;
; Function:     Blocks on a start RAM semaphore. When the semaphore
;               is cleared, waits for any of the Session Manager's
;               children to terminate.  When a child terminates and
;               no descendants of the Session Manager's child are
;               running in the screen group, the screen group is freed
;               and made available for use.  If there are descendants
;               of the Session Manager's child executing in the screen
;               group when the Session Manager's child terminates, a
;               dedicated thread is spawned to wait for the entire
;               command subtree to terminate.
;
; Notes:
;       Dependencies:   This procedure is called through DOSCREATETHREAD.
;
;       Restrictions:   None
;
;  Change History:
;   @CJ3  02/27/90  PTR B711697 Only chk for Error_Wait_No_Children return
;                               from DosCWait to not wait for subtree to die.
;   @MHW  09/13/90  PTR B715818 removed MMIO support.
;   CJ26  05/12/91  PTR B722846 Free memory allocated for Cwait thread stack.
;   CJ41  01/11/92  PTR B732600 Set SGCB_Flags so ChildExit won't get called
;                               twice.
;
; Entry Point:
;       Linkage:  EXTRN DOSSMCHILDWAIT:FAR
;
; Inputs:
;       The following data is put on the stack prior to
;       DOSCREATETHREAD:
;
;       WORD    ActionCode      Wait for any child or subtree
;       WORD    ProcessID       Wait for any child or subtree
;       WORD    ResultCode      Child's return code
;
; Exit Normal:
;       None
;
; Exit Errors:
;       None
;
; Effects:      This is an infinite loop for the termination
;               monitoring thread. If it is a dedicated thread,
;               the thread terminates after the command subtree
;               dies.
;
; Internal References:
;          Routines:
;                       DOSSMNEWTHREADS
;                       DOSSMCHILDEXIT
;
; External References:
;          Routines:    DOSCWAIT
;                       DOSSEMREQUEST
;                       DOSSEMCLEAR
;                       DOSKILLPROCESS
;                       DOSEXIT
;
;***************************************************************************
ifdef I1
;
;   DOSSETPRTY (Time critical thread)
;   DOSSEMSET (Set terminate thread semaphore)
;   REPEAT
;      IF (Wait for any child)
;         DOSSEMREQUEST(Wait for start RAM semaphore to be cleared)
;      ENDIF
;
;      REPEAT
;         DOSCWAIT (Wait for child process (session) to die)
;
;         IF (ProcessID ne 0)
;            Save real child's return code and pid
;         ELSE
;            Get returned result code
;            and pid of terminated process
;         ENDIF
;
;         IF (No_Error) OR
;         IF (a child process died)
;            DOSSMGETASGCB (Get associated screen group queue)
;
;            IF (NOT Error_SMG_Session_Not_Found)
;               DOSCWAIT (Command subtree termination)
;               IF (NOT Error_SMG_No_Children)
;               IF (NOT Error_Child_Not_Complete)
;                  DOSSMNEWTHREADS (spawn dedicated thread)
;
;                  IF (No_Error)
;                     DOSKILLPROCESS (Kill command subtree)
;                  ELSE
;                     Save thread id and stack selector
;                  ENDIF
;
;               ENDIF
;               IF (No_error)
;                 DOSCHILDEXIT (Process session termination)
;               ENDIF
;            ENDIF
;
;            IF (Dedicate wait)
;              DOSENTERCRITSEC
;            ENDIF
;         ENDIF
;
;      UNTIL (Error) OR
;      UNTIL (Wait for specified command subtree)
;   UNTIL (Wait for specified command subtree)
;   DOSSEMCLEAR (Terminate thread semaphore)
;   DOSEXIT (Terminate dedicated thread)
;
;***************************************************************************
else

.386C
    Start_Here EQU 4                    ; Adjust stack frame for no Trace Data

    TermRamSem  EQU Start_Here          ; Thread terninate semaphore
    ActionCode  EQU Start_Here + 4      ; Cwait action code offset (was 8)
    ProcessID   EQU WORD PTR Start_Here + 6  ; Cwait processid offset (was 10)
    ResultCode  EQU Start_Here + 8      ; Child result code offset (was 12)

    EXTRN NewThreads       : WORD       ; Array new thread data
    EXTRN ThreadID         : WORD       ; Array of new thread ids
    EXTRN SGCB_QueueRamSem : DWORD
    EXTRN StartRamSem      : DWORD
    EXTRN SGCB_Array       : DWORD                                      ;CJ26

    EXTRN DOSSMCHILDEXIT  : NEAR        ; Free screen group
    EXTRN DOSSMNEWTHREADS : NEAR        ; Spawn dedicated wait thd
    EXTRN DOSSMGETSGCB    : FAR
    EXTRN DOSCWAIT        : FAR         ; Wait for child to terminate
    EXTRN DOSENTERCRITSEC : FAR         ; Crit sec for single subtree wait
    EXTRN DOSEXIT         : FAR         ; Exit if single subtree wait
    EXTRN DOSKILLPROCESS  : FAR         ; Kill subtree
    EXTRN DOSSEMCLEAR     : FAR         ; Clear semaphore ownership
    EXTRN DOSSEMSET       : FAR         ; Set Terminate semaphore
    EXTRN DOSSETPRTY      : FAR         ; Boost thread time crit zero
    EXTRN DOSSEMREQUEST   : FAR         ; Request semaphore ownership
.xlist
    INCLUDE SMRSGCB.INC
    INCLUDE SMRRDATA.INC
.xcref
    INCLUDE ERROR.INC
    INCLUDE ERROR2.INC
    INCLUDE STRUC.INC
.cref
.list

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

    PUBLIC DOSSMCHILDWAIT
DOSSMCHILDWAIT PROC FAR

    MOV  BP, SP                         ; Establish stack frame
    MOV  AX, RDATA                      ; Addressability to global data
    MOV  DS, AX

    MOV  BX, SS:[BP].ResultCode         ; Get child result code
    MOV  DX, SS:[BP].ProcesSID          ; PID to wait for
    MOV  CX, SS:[BP].ActionCode         ; Get cwait action code

;   PUSH 2                              ; Only this thread              ;CJ10
    PUSH DWORD PTR 20003H               ; Time critical, zero           ;CJ10
    PUSH DWORD PTR 0                                                    ;CJ10
;   PUSH 0                              ; Current thread only           ;CJ10
    CALL DOSSETPRTY

;   MOV  AX, BP                         ; Set terminate thread semaphore;CJ10
    LEA  AX, [BP].TermRamSem                                            ;CJ10
    PUSH SS
    PUSH AX
    CALL DOSSEMSET

;   **********************************
;   *  Block on start RAM semaphore  *
;   **********************************
    .REPEAT
      .IF  < zero DX >                  ; Wait for SMG children         ;CJ10
        PUSH DS                         ; Start RAM Semaphore
        PUSH OFFSET StartRamSem
        PUSH DWORD PTR -1               ; Wait for semaphore to clear   ;CJ10
;CJ10   PUSH -1
        CALL DOSSEMREQUEST
      .ENDIF

;     ***********************************
;     *  Wait for a child to terminate  *
;     ***********************************
      .REPEAT
        PUSH DX                         ; Save stack parameters
        PUSH CX
        PUSH BX

        PUSH AX                         ; Reserve stack space for PID
        MOV  SI, SP                     ; Save offset on stack
        PUSH AX                         ; Reserve stack space for resultcd
        PUSH AX
        MOV  DI, SP                     ; Save offset on stack

        PUSH CX                         ; Wait for child or child + desc.
        PUSH 0                          ; Wait until child terminates
        PUSH SS                         ; DOS child term. retcode
        PUSH DI
        PUSH SS                         ; Result code address
        PUSH SI
        PUSH DX                         ; Wait on any or one child
        CALL DOSCWAIT

        .IF  < nonzero DX >             ; Wait for command subtree      ;CJ10
          ADD  SP, 6                    ; Keep real childs rc and pid
        .ELSE
          POP  BX                       ; Get result code from child
          POP  BX
          POP  DX                       ; Get pid of process terminated
        .ENDIF

;       *****************************************
;       *  Block other Session Manager threads  *
;       *  from accessing the queue segment     *
;       *****************************************
        .IF  < zero AX > OR near             ; Child proc died?         ;CJ10
        .IF  < SS:[BP].ProcessID ne 0 > near ; Dedicated wait

;         ***************************************************************
;         *  Get screen group queue associated with terminated process  *
;         ***************************************************************
          CALL DOSSMGETASGCB            ; ES:DI --> SGCB, DX = SGID

;         **********************************************************
;         *  Determine if all processes in screen group have died  *
;         **********************************************************
          .IF  < AX ne Error_SMG_Session_Not_Found >
            PUSH AX                     ; Stack space for CWAIT data
            MOV  SI, SP
            PUSH AX
            PUSH AX
            MOV  CX, SP
;CJ10       PUSH 1                      ; Indicate subtree cwait
            PUSH DWORD PTR 10001H       ; No wait option                ;CJ10
            PUSH SS                     ; Duumy data address
            PUSH CX
            PUSH SS                     ; Dummy data address
            PUSH SI
            PUSH ES:[DI].SGCB_PID       ; Process id
            CALL DOSCWAIT
            ADD  SP, 6

;           ******************************************
;           *  If all processes not dead, spawn      *
;           *  dedicated thread to wait for subtree  *
;           ******************************************
            .IF  < AX ne Error_Wait_No_Children >                       ;@CJ3
;@CJ3****** .IF  < AX ne Error_Child_Not_Complete >
              PUSH DX                   ; Save SGID
              MOV  DX, ES:[DI].SGCB_PID ; Subtree ID
              MOV  CX, 1                ; Wait on subtree
              MOV  SI, OFFSET NewThreads
              CALL DOSSMNEWTHREADS
              POP  DX                   ; Restore SGID                  ;CJ26

;             ************************************************************
;             *  If thread create failed, kill all processes in subtree  *
;             ************************************************************
              .IF  < nonzero AX >       ; Thread created?               ;CJ10
                PUSH 0                  ; Kill proc and descend
                PUSH ES:[DI].SGCB_PID   ; Subtree ID
                CALL DOSKILLPROCESS
                MOV  AX, NOT No_Error

;             ************************************************************CJ26
;             *  Else store stack address for new thread in SGCB_Array.  *CJ26
;             ************************************************************CJ26
              .ELSE                     ; Thread created ok
                MOV  AX, DX             ; Get SGID                       ;CJ26
                XOR  AH, AH             ; Zero type byte                 ;CJ26
                SHL  AX, 3              ; x 8 for 4 WORDs                ;CJ26
                LFS  BX, SGCB_Array     ; FS:[SI] --> @ of SGCB Array    ;CJ26
                LFS  BX, FS:[BX]        ; FS:[SI] --> SGCB Array         ;CJ26
                INC  BX                 ; Point past reserved word       ;CJ26
                INC  BX                 ; (Use INC SI instead of ADD)    ;CJ26
                ADD  BX, AX             ; Add in offset to correct DWORD ;CJ26
                MOV  EAX, DWORD PTR DS:[SI+4]   ; Get stack address      ;CJ26
                MOV  FS:[BX].CWaitStackPtr, EAX ; Store in SGCB_Array    ;CJ26
                XOR  EAX, EAX                   ; Zero AX for check below;CJ26

;CJ26;;;;;;;;;; MOV  DX, DS:ThreadID    ; Save Thd
;CJ26;;;;;;;;;; MOV  ES:[DI].SGCB_CWaitThread, DX
;CJ26;;;;;;;;;; MOV  DX, DS:[SI+4]      ; Save stack
;CJ26;;;;;;;;;; MOV  ES:[DI].SGCB_CWaitStack, DX
              .ENDIF
            .ENDIF

;           ****************************************************************
;           *  Free the screen group                                       *
;           *                                                              *
;           *  Check if process died during DosStartSession because        *CJ41
;           *  ChildExit will already have been called for those sessions. *CJ41
;           ****************************************************************
            .IF  < nonzero AX >                                         ;CJ10
              TEST ES:[DI].SGCB_Flags, Start_Failed    ; Exec failure   ;CJ41
              .IF  <z>                                                  ;CJ41
                CALL DOSSMCHILDEXIT
              .ENDIF                                                    ;CJ41
            .ENDIF
          .ENDIF

;         ************************************************************
;         *  For single subtree wait threads, enter critical section *
;         *  prior to allowing a screen group start.                 *
;         ************************************************************
          .IF  < SS:[BP].ProcessID ne 0 >      ; Dedicated wait
            CALL DOSENTERCRITSEC
          .ENDIF

          XOR  AX, AX
        .ENDIF

        POP  BX                         ; Restore stack parameters
        POP  CX
        POP  DX
      .UNTIL < nonzero AX > OR          ; 0 should be replaced with no child rc
      .UNTIL < nonzero DX > NEAR        ; Wait on one sub-tree only?    ;CJ10

;    ***********************************************
;    *  No children, block on start RAM semaphore  *
;    *  until new screen group started.            *
;    ***********************************************
    .UNTIL < nonzero DX > NEAR          ; Exit if single subtree wait   ;CJ10

    MOV  AX, BP                         ; Clear terminate thread semaphore
    ADD  AX, TermRamSem
    PUSH SS
    PUSH AX
    CALL DOSSEMCLEAR

    PUSH DWORD PTR 0                                                    ;CJ10
;   PUSH 0                                                              ;CJ10
    CALL DOSEXIT

DOSSMCHILDWAIT ENDP

;***************************************************************************
;  DosSMGetASGCB
;
;  Input:  DX  PID
;          DS  RDATA
;
;  Output: FS:SI --> SGCB that belongs to the PID
;***************************************************************************

PUBLIC DOSSMGETASGCB
DOSSMGETASGCB   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

    LEA  DI, Local_Var2                 ; @ return @ of SGCB
    PUSH SS
    PUSH DI
    PUSH DX                             ; PID
    PUSH PID_Lookup                     ; Look up PID not SGID
    CALL DOSSMGETSGCB

    .IF  < zero AX >                                                    ;CJ10
      LES  DI, Local_Var2               ; ES:[DI] --> SGCB
      MOV  DX, ES:[DI].SGCB_ID
    .ENDIF

    LEAVE
    RET
DOSSMGETASGCB   ENDP

CODE ENDS
endif
    END
