;       SCCSID = @(#)sswlock.asm	6.2 91/08/28
         page 60,132
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************


;*********************** START OF SPECIFICATIONS ***********************/
;                                                                      */
;  SUBROUTINE NAME:  DOSSCRLOCK                                        */
;                                                                      */
;  DESCRIPTIVE NAME:  Lock screen for process update                   */
;                                                                      */
;  FUNCTION:  Issued by a process to request screen switcher           */
;             allocation of screen until the process issues a          */
;             DOSSCRUNLOCK or a timeout has been reached. The process  */
;             is free to update screen uninterrupted for the           */
;             duration. The process sets a waitflag for the call       */
;             specifying whether the thread will wait for the          */
;             screen availability or an immediate return from Screen   */
;             Switcher is needed. If there is a switch pending, then   */
;             a process requesting a screen lock will be treated as    */
;             if it were in background mode.                           */
;                                                                      */
;  NOTES:  Executes on Level 3                                         */
;                                                                      */
;  ENTRY POINT:  DosScrLock                                            */
;                                                                      */
;  INPUT:  Stack:                                                      */
;                  Waitflag (0 = immediate return                      */
;                            1 = wait on screen)                       */
;                  Address of status byte                              */
;                                                                      */
;  EXIT-NORMAL:  AX = 0                                                */
;                                                                      */
;  EXIT-ERROR:   AX = 1 for invalid waitflag setting                   */
;                                                                      */
;  EFFECTS:  Contents of AX destroyed by return code                   */
;            Status byte updated (0 = lock successful                  */
;                                 1 = lock unsuccessful)               */
;                                                                      */
;  INTERNAL REFERENCES:                                                */
;    ROUTINES: SSCBUpdate, SSOpenSySem                                 */
;                                                                      */
;  EXTERNAL REFERENCES:                                                */
;    ROUTINES:  DosGetInfoSeg, DosSemWait, DosCloseSem, DosSemRequest, */
;               DosSemSet, DosSemClear                                 */
;                                                                      */
;       Change History:                                                */
;                                                                      */
;       @TL6 - 03/01/90 - DCR 704 - Merge SMG/SSW instance data into   */
;                         OS2CHAR                                      */
;      @GDW   08/26/91    PTR B725436 Fix to allow semaphore loop on   */
;                         INTERUPT                                     */
;                                                                      */
;************************ END OF SPECIFICATIONS ************************/

; Check waitflag for validity (passed in by calling application)
; IF <waitflag is greater than 1> (0,1 are valid)
;  AX = error_vio_wait_flag
; ELSEIF <VIOHandle ne 0>
;  AX = error_vio_invalid_handle
; ELSE
;  Request synch semaphore (savelocksem)
;  IF <this is first screen lock call for screen group>
;   Set up exitlist routine
;   Get current sg#
;   Get current pid#
;   Store these numbers in instanced data (allows us to check if first call)
;   Get pointer to screen group control block
;   Store the pointer in instanced data
;  ENDIF
;  IF <there is no screen lock currently in effect> AND
;  IF <kbdowner eq 0>
;   IF <the screen group is in background>
;    IF <waitflag is 0>  indicating immediate return
;     Set lockstatus to 1 indicating failure to obtain lock
;     AX = no_error
;    ELSE
;     Open and set the lockneeded semaphore
;     Clear the synch semaphore
;     Wait on the lockneeded semaphore (cleared on being made foreground)
;     Close the lockneeded semaphore (after being made foreground)
;     Request the synch semaphore
;    ENDIF
;   ENDIF
;   IF <the screen group is in foreground>
;    Set lockstatus to 0 indicating success in obtaining screen lock
;    AX = no_error
;   ENDIF
;  ELSE
;   AX = error_vio_lock
;  ENDIF
;   Clear synch semaphore
; ENDIF

         EXTRN   SSGETSGCB:NEAR
         EXTRN   SSOPENSYSEM:NEAR
         EXTRN   DOSGETINFOSEG:FAR
         EXTRN   DOSSEMWAIT:FAR
         EXTRN   DOSOPENSEM:FAR
         EXTRN   DOSCLOSESEM:FAR
         EXTRN   DOSEXITLIST:FAR
         EXTRN   DOSSEMREQUEST:FAR
         EXTRN   DOSSEMSET:FAR
         EXTRN   DOSSEMCLEAR:FAR
         EXTRN   DOSCLEANUP:FAR
         EXTRN   screenlocksgid:WORD
         EXTRN   savelockowner:word
         EXTRN   savelocksem:byte
         EXTRN   savelockflag:word
         EXTRN   lockneededname:byte
         EXTRN   DOSFSRAMSEMREQUEST:FAR
         EXTRN   DOSFSRAMSEMCLEAR:FAR
         EXTRN   SMG_INSTANCE:DWORD                                     ;@TL6

                .xlist
         INCLUDE INFOSEG.INC
         INCLUDE SSWLOCK.INC            ; Screen lock stack frame
         INCLUDE OS2INST.INC            ; SMG/SSW instance data equates ;@TL6
         INCLUDE SSWINC.INC
                .list

.386p

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

         PUBLIC  DOSSCRLOCK
DOSSCRLOCK      PROC    FAR

         PUSH    BP                     ; Save BP
         SUB     SP,8                   ; Reserve 4 words on stack      ;@TL6
;@TL6    PUSH    AX
;@TL6    PUSH    AX
;@TL6    PUSH    AX
         MOV     BP,SP                  ; Establish stack
                                        ;frame address
         PUSH    BX
;@TL6    PUSH    CX
         PUSH    SI
         PUSH    DI
         PUSH    DX
         PUSH    DS
         PUSH    ES

         .IF <SS:[BP].lockwaitflag a 1>  ; Valid wait flag?
            MOV     AX,error_vio_wait_flag  ; invalid wait
                                        ;option
         .ELSEIF <SS:[BP].lockviohandle ne 0> near   ; ES7/8/87
            MOV     AX,error_vio_invalid_handle  ; ES7/8/87
         .ELSE near

;@TL6          MOV     AX,INDATASG      ; Get
                                        ;addressability to
                                        ;instanced data
;@TL6          MOV     ES,AX
               MOV     AX,STDATASG      ; and to global
                                        ;data seg
               MOV     DS,AX
               LES     SI,DS:SMG_INSTANCE  ; Get access to instance data;@TL6
;@TL6          XOR     AX,AX

               .repeat                                                  ;@GDW
                 PUSH    DS                  ; Wait indefinitely for
                 PUSH    OFFSET savelocksem  ; the global ram sem
                 PUSH    DWORD PTR TIMEOUT                              ;CJ10
;CJ10            PUSH    TIMEOUT
                 CALL    DOSFSRAMSEMREQUEST
               .until  <ax ne ERROR_INTERRUPT>                          ;@GDW

            .IF <zero AX> near                                          ;@TL6
               MOV     savelockflag,10
;---------------------------------------------------------------------------
;  EXECUTE THE FOLLOWING CODE IF THIS IS THE FIRST SCREEN LOCK CALL FROM PID
;---------------------------------------------------------------------------
               .IF <ES:[SI].in_sgid e AX> near  ; If this is first      ;@TL6
                                                ; time we're called
                  MOV     AX,CS                                         ;@TL6
                  OR      AX,1          ; Exitlist must be in Ring 3    ;@TL6
                  PUSH    0C001H        ; New Function code for DCR18 7/10/87
                  PUSH    AX                                            ;@TL6
                  PUSH    OFFSET doscleanup  ; Termination routine
                  CALL    DOSEXITLIST
                  .IF <zero AX>                                         ;@TL6
;@TL6                PUSH    AX         ; Stack space for
                                        ;global selector
;@TL6                MOV     CX,SP
;@TL6                PUSH    AX         ; Stack space for
                                        ;local selector
;@TL6                MOV     DX,SP
;@TL6                PUSH    SS         ; Address to return
                                        ;global selector
;@TL6                PUSH    CX
;@TL6                PUSH    SS         ; Address to return
                                        ;local selector
;@TL6                PUSH    DX
;@TL6                CALL    DOSGETINFOSEG  ; get screengroup #
;@TL6                POP     CX         ; Address to local
                                        ;information segment
;@TL6                POP     DX         ; Throw away global
                                        ;selector
;@TL6                .IF <zero AX> near
;@TL6                   MOV     ES:[SI].in_localsg,CX
                        MOV     AX,DS                                   ;@TL6
                        MOV     DS,localsg                              ;@TL6
                        MOV     BX,DS:LIS_CURSCRNGRP  ; Save sg# and    ;@TL6
                        MOV     DX,DS:LIS_CURPROCID                     ;@TL6
                        MOV     DS,AX                 ; process id# in  ;@TL6
                        MOV     ES:[SI].in_sgid,BX    ; instanced data  ;@TL6
                        MOV     ES:[SI].in_procid,DX                    ;@TL6
                        PUSH    SI         ; SSGETSGCB destroys SI      ;@TL6
                        CALL    SSGETSGCB  ; Get screen group
                        POP     SI         ; Restore instance data off. ;@TL6
                        MOV     ES:[SI].in_di_reg,DI  ; control block   ;@TL6
;@TL6                .ENDIF             ; pointer
                  .ENDIF
               .ENDIF
;---------------------------------------------------------------------------
; EXECUTE THE FOLLOWING REGARDLESS OF FIRST LOCK CALL FROM PID OR NOT
;---------------------------------------------------------------------------
               .IF <zero AX> near                                       ;@TL6
                  MOV     DI,ES:[SI].in_di_reg                          ;@TL6
;@TL6             MOV     DI,DX
                  .IF <[DI].sglockineffect e ax> near AND  ;ES7/15/87   ;@TL6
                  .IF <[DI].kbdowner e ax> near            ;ES7/15/87   ;@TL6
                     .IF <[DI].sgflags ae in_backgrnd> NEAR  ; background?
                        .IF <SS:[BP].lockwaitflag e ax>  ; immediate return?
                           PUSH    ES   ; Save registers
                           PUSH    DI
                           LES     DI,SS:[BP].lockstatus  ; Status addr.
                           MOV     ES:BYTE PTR [DI],1  ; failed
                           POP     DI   ; Restore registers
                           POP     ES
                        .ELSE  near     ; Wait for lock
                           PUSH    SI   ; Save instance data offset     ;@TL6
                           MOV     SI, OFFSET lockneededname  ; Open lock
                                        ;semaphore
                           CALL    SSOPENSYSEM
;@TL6                      POP     SI
;@TL6                      MOV     SS:[BP].lockneededlow,SI
;@TL6                      POP     SI
;@TL6                      MOV     SS:[BP].lockneededhigh,SI
                           POP     SI   ; Restore instance data offset
                           .IF <zero AX>  ; Set semaphore to            ;@TL6
                                        ;block on
                              MOV     AX,ES:[SI].in_procid              ;@TL6
;                             MOV     [DI].sglockineffect,AX  ; ES7/15/87
                              MOV     [DI].kbdowner,AX        ; ES7/15/87
;@TL6                         PUSH    WORD PTR SS:[BP].lockneededhigh
                              PUSH    DWORD PTR SS:[BP].lockneededlow   ;@TL6
                              CALL    DOSSEMSET
                              .IF <zero AX>                             ;@TL6
                                 PUSH    DS  ;
                                 PUSH    OFFSET savelocksem
                                 MOV     savelockflag,AX  ; Clear flag  ;@TL6
                                 CALL    DOSFSRAMSEMCLEAR
                                 .IF <zero AX>                          ;@TL6
;@TL6                               PUSH    WORD PTR SS:[BP].lockneededhigh
                                    PUSH    DWORD PTR SS:[BP].lockneededlow;@TL6
                                    PUSH    DWORD PTR TIMEOUT           ;CJ10
;CJ10                               PUSH    TIMEOUT
                                    CALL    DOSSEMWAIT

;---------------------------------------------------------------------------
;  WE CONTINUE EXECUTING AFTER SG HAS BEEN MADE FOREGROUND AND WE ARE
;  UNBLOCKED
;---------------------------------------------------------------------------

                                    .IF <zero AX>  ; Close System       ;@TL6
                                        ; semaphore
;@TL6                                  PUSH    WORD PTR SS:[BP].lockneededhigh
                                       PUSH    DWORD PTR SS:[BP].lockneededlow
                                       CALL    DOSCLOSESEM
                                       .IF <zero AX>  ; Close System    ;@TL6
;                                         MOV     savelockflag,10 ;ES7/15/87
                                          .repeat                       ;@GDW
                                            PUSH    DS
                                            PUSH    OFFSET savelocksem
                                            PUSH    DWORD PTR TIMEOUT   ;CJ10
;CJ10                                       PUSH    TIMEOUT
                                            CALL    DOSFSRAMSEMREQUEST
                                          .until  <ax ne ERROR_INTERRUPT> ;@GDW
                                       .ENDIF
                                    .ENDIF
                                 .ENDIF
                              .ENDIF
                           .ENDIF
                        .ENDIF
                     .ENDIF
                     .IF <zero AX> AND                                  ;@TL6
                     .IF <[DI].sgflags b in_backgrnd> NEAR  ; background?
                        MOV     BX,ES:[SI].in_procid  ; ownership?????? ;@TL6
                        MOV     savelockflag,10
                        MOV     [DI].kbdowner,AX       ; ES7/15/87
                        MOV     [DI].sglockineffect,BX
                        MOV     BX,ES:[SI].in_sgid                      ;@TL6
                        MOV     screenlocksgid,BX
                        LES     DI,SS:[BP].lockstatus  ; Status
                                        ;addr.
                        MOV     ES:BYTE PTR [DI],AL ; Success           ;@TL6
                     .ENDIF
                  .ELSE                 ; If this is a repeated lock
                     MOV    AX, error_vio_lock  ; and no unlock
                  .ENDIF
               .ENDIF
               PUSH   AX
               PUSH   DS
               PUSH   OFFSET savelocksem
               MOV    savelockflag,0
               CALL   DOSFSRAMSEMCLEAR
               POP    AX
            .ENDIF
         .ENDIF
         POP     ES
         POP     DS
         POP     DX
         POP     DI
         POP     SI
;@TL6    POP     CX
         POP     BX
;@TL6    POP     BP
;@TL6    POP     BP
;@TL6    POP     BP
         ADD     SP,8                   ; Balance stack                 ;@TL6
         POP     BP                     ; Restore old BP

         RET                            ; Return to caller

DOSSCRLOCK      ENDP

CODE    ENDS                                                            ;@TL6
         END
