;       SCCSID = @(#)sig.asm	6.10 92/03/11
TITLE   SIGNAL - signal handling for MSDOS
NAME    SIGNAL

SCCSID  equ     "@(#)sig.asm	6.10 92/03/11"

;-----------------------------------------------------------------------
;
;       CP/DOS signal handling
;               includes routines for
;                       signal sensitization, sending
;                       signal dispatch
;
;       Alan Whitney, Nov. 1983
;       Pete Stewart, Apr. 1986
;
;       Copyright (C) Microsoft Corporation, 1983, 1984, 1985, 1986
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;       User processes may indicate their desire to accept a signal
;       from other processes or from the system by using the
;       DOSSETSIGHANDLER system call.  If the process does not
;       do so, it will get the default system defined action for
;       that signal.
;
;       When DOSSETSIGHANDLER is called, it remembers the
;       parameters of the call in several per-process variables:
;
;               Sig_vec         Signal handler address array
;               Sig_???f        Bit vectors recording disposition
;                               of individual signals.
;
;       When a signal is sent, for each matching process, the
;       disposition of the signal is checked.  If the signal is
;       being handled, a bit is set in a vector of pending signals
;       (TCBSig_pend) and the signal argument is recorded (in Sig_arg).
;       If a signal will cause either handling of a signal or
;       termination of the process, a bit is set in the task status
;       (TCBForcedActions) and the process is restarted if it is in an
;       interruptable wait.  The process will notice the status bit
;       and take appropriate action when it is about to leave
;       the system.
;
;       MODIFICATION HISTORY
;
;       28-Apr-88       JSF     Made internal error in ResetSigFocus jump
;                               to right place. (1.1 PTM 2493)
;
;       13-Jun-89       SB      Chnaged old KMode Enter/Exit interface usage
;                               with new one.
;
;       26-May-94  Change Team  Defect 84891 - Save/Restore ECX when calling
;                               TKForceThread.  ECX seams to get corrupted
;                               inside SCHSetState (sched.asm) which is
;                               called by TKForceThread.
;       28-June-94      RAC     Roll over 84891 into R207 under defect
;                               87561.
;
;       18-Jan-95  Change Team  Defect 108449 - Added procedure SigResetAPTERM
;                               to clear the SIGAPTERM bit in the current thread.
;       02-Jun-95  Change Team  Defect 123335 - Ensured that DS is Flatcontex
;
;--------------------------------------------------------------------------

include basemaca.inc
include osmaca.inc
include dosseg.inc
include fnotask.inc
.xcref

INCL_ERRORS EQU 1               ; For bseerr.inc
include bseerr.inc
include mi.inc
include protmode.inc
include seldesc.inc
include proc.inc
include kmode.inc
include sysentry.inc
include ordinals.inc
include tkexport.inc
.cref
include sigdef.inc
include bsexcpt.inc
include ostypes.inc
include osconst.inc
include dossymc.inc
include except.inc
include infoseg.inc
include pgexport.inc
include vmowner.inc
include vmexport.inc
include selxport.inc
include curdir.inc
include dirent.inc
include find.inc
include screen.inc
include sem.inc
include tkptda.inc
include mmpha.inc
include sigxport.inc

.sall
        ModName         SIG, FNO_SIG_ASM
        CpuMode 386

        ReferGlobal     PendingSigArg,WORD
        ReferGlobal     PendingSignals,WORD
        ReferGlobal     SigFocus,WORD           ; Asynch keyb signal recipients
        ReferGlobal     SISData,BYTE

        ReferFlat       _flGlobalActions,dword
        ReferFlat       _pTCBCur,dword
        ReferFlat       _pPTDACur,dword
        ReferFlat       _R3CS,word
        ReferFlat       _pfnSigDispatch,dword

        EXTRNFAR        ExitCritSecUnHoldSig

        EXTRN           ScanTasks:near
        EXTRN           KSGKillProcess:near
        EXTRN           ProtMode:near
        EXTRN           RealMode:near

        EXTRN32         _TKForceThread
        EXTRN32         _TKDieSoonPTDA
        EXTRN32         KMPUSHCLIENTSTACK
        EXTRN32         KMQUERYCLIENTREGISTER
        EXTRN32         KMSETCLIENTREGISTER
        EXTRN32         _PGVerifyInfoSegs
        EXTRN32         _XCPTCheckExceptionHandler
        EXTRN32         _SIGGetMustComplete
        EXTRN32         _SIGSetMustCompleteFlag

.xall

        FARCODE HIGH3
HIGH3CODE SEGMENT

;***    DOSHOLDSIGNAL - Postpone/reenable signal processing
;
;       INVOKE  push    word ActionCode         (1 word)
;               call    DOSHOLDSIGNAL
;
;       RETURN  (ax) = return code
;                       0 - success
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

SysEntryBegin DOSHOLDSIGNAL,ORD_DOSHOLDSIGNAL,1,,inline,0

ArgVar  UserBP, WORD
ArgVar  UserCSIP, <size FarPtr32>
ArgVar  Action, WORD

        push    bp
        mov     bp,sp                   ; (BP) = argument/register pointer

        pushf                           ; save user's registers
        push    ebx
        push    ecx
        push    si
        push    ds

        mov     ax,Action               ; (AX) = action code
        mov     si,dx                   ; save DX
        mov     dl,1                    ; (DL) = don't allow thread to block

;***DT  preDOSHOLDSIGNAL - DosHoldSignal pre-invocation trace point
;
;    TRACE MINOR = <RAS_PRE_DOSHOLDSIGNAL>,
;          TP    = .preDOSHOLDSIGNAL,
;          TYPE  = (PRE,API),
;          GROUP = SIG,
;          DESC  = "(OS) DosHoldSignal Pre-Invocation",
;          REGS  = (AX),
;          FMT   = "Action = <FMT_WORD>"

Entry preDOSHOLDSIGNAL,,,nocheck
        MMPHPreDOSHoldSignal            ; Performance Hook (1801h)

        cld

;       NOTE: HoldSignal returns DS = FlatContext

        call    HoldSignal              ; Try to do the work (use minimal regs)
        mov     dx,si                   ; restore DX
        jc      short dhs3              ; Jump if error
        sub     ax,ax                   ; set good return code now

;       This code checks the global, process and thread force flags
;       and enter/exits kernel mode to do the rescheding or
;       force action, if any.

        ASSUME  DS:FLAT
dhs1:   mov     si,ss:[TKOPTDA.CurrTCB] ; (SS:SI) = current TCB pointer
        mov     ebx,[_flGlobalActions]          ; Any global force flags,
        or      ebx,ss:[TKOPTDA.ptda_ForcedActions]     ; process force flags,
        or      ebx,ss:[si].TCBForcedActions    ; or thread force flags?
        ASSUME  DS:NOTHING
        jnz     short dhs2              ; yes - Enter Kernel Mode

        pop     ds                      ; restore registers
        pop     si
        pop     ecx
        pop     ebx
        popf
        pop     bp

;***DT  post2DOSHOLDSIGNAL - DosHoldSignal post-invocation trace point 2
;
;    TRACE MINOR = <RAS_POST2_DOSHOLDSIGNAL>,
;          TP    = .post2DOSHOLDSIGNAL,
;          TYPE  = (POST,API),
;          GROUP = SIG,
;          DESC  = "(OS) DosHoldSignal Post-Invocation (2)",
;          REGS  = (AX),
;          FMT   = "Return code = <FMT_WORD>"

Entry post2DOSHOLDSIGNAL,,,nocheck
        MMPHPostDOSHoldSignal2          ; Performance Hook (18B8h & 1881h)

        RETFD   <?argbytes>

;       Must enter kernel mode.

dhs2:   pop     ds                      ; restore registers
        pop     si
        pop     ecx
        pop     ebx
        popf
        pop     bp

;       DS and ES are the user's segment registers so that Exit_Kmode
;       can validate these selectors on the way out.
;
;       Call KMode Enter/Exit interface

        KMEnterKmodeCallGate <?argwords*2>,noinline,PASCAL
        KMExitKmodeCallGate  <?argwords*2>,noinline,PASCAL

;       We have an error returned from the worker.
;       Check if it is the special "use SCI" error
;       code (NO_ERROR).

dhs3:   or      ax,ax                   ; Would have blocked
        .errnz  NO_ERROR
        jnz     short dhs1              ; jump to check resched and EXIT

;       We might have blocked, so we must enter kernel mode
;       thru SCI

        pop     ds                      ; restore registers
        pop     si
        pop     ecx
        pop     ebx
        popf
        pop     bp

        CallSCI
        ld_ax                           ; action code

        farcall w_HoldSignal, ORD_DOSHOLDSIGNAL                           ;@SEC

;***DT  postDOSHOLDSIGNAL - DosHoldSignal post-invocation trace point
;
;    TRACE MINOR = <RAS_POST_DOSHOLDSIGNAL>,
;          TP    = .postDOSHOLDSIGNAL,
;          TYPE  = (POST,API),
;          GROUP = SIG,
;          DESC  = "(OS) DosHoldSignal Post-Invocation",
;          <LOG_RETVAL>,
;          FMT   = "Return code = <FMT_RETVAL>"

        RASposttrace

EndEntry DOSHOLDSIGNAL


;***    w_HoldSignal - postpone/reenable signal handling
;***    HoldSignal - postpone/reenable signal handling
;
;       Postpones signal handling for the current process.
;       Reenables signal handling for the current process
;       and causes any postponed signals to be posted.
;
;       ENTER   AX = 0 reenable signal handling
;                  = 1 postpone signal handling
;               DL = block check flag (HoldSignal only)
;                       0 = allow thread to block
;                       1 = do not allow thread to block
;
;       EXIT    Carry set
;                   AX = ERROR_INVALID_FUNCTION
;                   AX = NO_ERROR
;                       Block check failed (HoldSignal only)
;                   DS = Flat Context
;               Carry clear
;                       No error
;
;       USES    BP, AX, BX, CX, DX, DS, ES, Flags
;
;       NOTES   For performance reasons, there are multiple subroutine
;               exits, to allow execution to fall through in the more
;               common cases.
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure w_HoldSignal,hybrid

        CpuMode 386
        xor     dl,dl                   ; Blocking allowed

Entry   HoldSignal,,local

;       PMONLY  TASKTIME
        TaskTime

;       Set up DS one time, here, so that it is always returned
;       NOTE: psig16 preserves DS

        FlatContext ds,bx

        dec     ax                      ; AX==1? (postpone handling?)
        jnz     short hsg3              ;  no, skip ahead
        inc     ss:[TKOPTDA.HoldSigCnt] ; Increment counter
        jz      hsg8                    ;  overflow: restore, return error
        cmp     ss:[TKOPTDA.HoldSigCnt],1   ; Counter already incremented before?
        ja      short hsg2              ;  yes

hsg1:   mov     ebx,ss:[TKOPTDA.ptda_pTCBHead]  ; EBX = Thread 1 TCB
        mov     ax,[ebx].TCBSig_pend    ; Get any pending signals
        and     ax,SIG_HOLDABLE         ; Get the holdable ones
        or      [ebx].TCBSig_holding,ax ; Remember the held signals
        and     [ebx].TCBSig_pend,NOT SIG_HOLDABLE
                                        ; No holdable signals pending
        jnz     short hsg2              ; Skip ahead if some signal pending

                                        ; Clear forced signal action
        and     [ebx].TCBForcedActions,NOT TK_FF_SIG
hsg2:   clc
        ret                             ; EXIT

        align   4                       ; DWORD align jump target
hsg3:   inc     ax                      ; AX==0? (re-enable handling?)
        jnz     short hsg9              ;  no, bad function code
        cmp     ss:[TKOPTDA.HoldSigCnt],1   ; Check 0, 1, or greater than 1
        ja      short hsg4              ;  greater than 1, go decrement it
        jb      short hsg9              ;  underflow (treat as bad func)

;       At this point, we must determine what held signals there are
;       and post ourself.  Note that if there are held signals and
;       DL = 1, we do nothing and return with carry set and AX = NO_ERROR.

        mov     ebx,ss:[TKOPTDA.ptda_pTCBHead]  ; EBX = Thread 1 TCB
        mov     cx,[ebx].TCBSig_holding
                                        ; Get bit vector
        or      cx,cx                   ; was anything held?
        jnz     short hsg5              ;  yes
hsg4:   dec     ss:[TKOPTDA.HoldSigCnt] ; since not, decrement counter
        clc                             ;  and return successfully
        ret                             ; EXIT

        align   4                       ; DWORD align jump target
hsg5:   xor     ax,ax                   ; Initialize counter/AX = NO_ERROR
        .errnz  NO_ERROR
        test    dl,1                    ; Blocking allowed?
        jnz     short hsg10             ;  no, exit with carry set

        mov     byte ptr ss:[TKOPTDA.HoldSigCnt],al
                                        ; Not holding any more
        and     [ebx].TCBSig_holding,NOT SIG_HOLDABLE ; Clear Holdable signals

        and     cx, SIG_HOLDABLE        ; Only post holdable signals

        push    ss                      ; ES = this process' PTDA for psig16
        pop     es                      ;    NOTE: psig16 preserves ES

hsg6:   inc     ax                      ; Increment counter
        shr     cx,1                    ; Shift lsb into carry
        jc      short hsg7
        jnz     short hsg6              ; if no signal in that position,
        clc                             ;  EXIT successful once bits exhausted
        ret

        align   4                       ; DWORD align jump target
hsg7:   SaveReg <ebx,ax,cx>             ; Save registers


;       Put arguments for psig on the stack

        mov     bx,ax                   ; Get signal argument
        shl     bx,1
        push    ss:[TKOPTDA.Sig_arg]-2[bx]  ; Push argument
        push    ax                      ; Push signal number
        SigBit                          ; CX = signal bit mask
        push    cx                      ; Push bit mask
        mov     bp,sp                   ; BP = argument frame pointer
        call    psig16                  ; Post the signal
        add     sp,6                    ; Clean the stack
        RestoreReg <cx,ax,ebx>          ; Restore registers
        jmp     short hsg6              ; Loop

hsg8:   dec     ss:[TKOPTDA.HoldSigCnt] ; we incremented in error

;       At this point, we know we have overflow or underflow
;       or an invalid function number.

hsg9:   mov     ax,ERROR_INVALID_FUNCTION

hsg10:  stc                             ; generic error return point
        ret

EndProc w_HoldSignal



;***    w_SendSignal - Send Signal to Process within Command Subtree
;
;       This routine searches a command subtree for a process which has
;       a signal handler installed for the specified signal number, but
;       no children have such a signal handler installed.  If such a
;       process is found, a signal of the specified number is sent to the
;       last such process found, otherwise an error reply is returned.
;
;       ENTRY   AL = Signal number (1 = SIGINTR, 2 = SIGBREAK)
;
;               CX = Csid (Command Subtree Id).
;
;       EXIT    CF clear - Successful call
;                  set - An error occurred
;
;               AX = error code if CF set
;
;                    ERROR_NO_SIGNAL_SENT - No process in command subtree
;                                           has a handler installed for the
;                                           specified signal
;
;                    ERROR_INVALID_PROCID - The specified command tree
;                                           does not exist
;
;                    ERROR_INVALID_FUNCTION - The specified signal number
;                                             is not SIGINTR or SIGBREAK
;                                             OR not direct descendent
;                                             (compatibility)
;
;                    ERROR_SIGNAL_REFUSED - The specified signal could not
;                                           be accepted by the target process
;
;
;       USES    AX,BX,CX,DX,DI,BP,DS,Flags
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure w_SendSignal,<near, faronly, far16>

;       First check that the signal number is either SIGINTR or SIGBREAK.  No
;       other signals are allowed by this user interface.

;       MMIOPH Performance Hook Removed
;       Maj/Min = 1862H, Data = cx, ax (CSID, sig number)

        cmp     al,SIGINTR                      ; Is signal SIGINTR ?
        je      short ssg1                      ; Jump if it is
        cmp     al,SIGBREAK                     ; Is signal SIGBREAK ?
        jne     short ssg2                      ; Jump if not, its invalid

;       Convert the signal number (SIGINTR or SIGBREAK) to a signal bit mask
;       setting.

ssg1:   SaveReg <ax>                            ; Save signal number
        mov     bx,cx                           ; Save Csid
        SigBit                                  ; CX = Signal Bit Mask

;       Search the specified command subtree for a leafmost process amongst
;       those having a handler installed for the specified signal (SIGINTR
;       or SIGBREAK).  To ensure that the process is leafmost, we return the
;       last Pid in the command subtree accessed that has a handler installed.
;       Note that this is guaranteed to be leafmost amongst such processes since
;       processing for a command subtree goes from top to bottom.

        mov     bp,cx                           ; BP = signal bit mask
        xor     dx,dx                           ; Assume no eligible Pid found
        mov     cx,bx                           ; CX = command subtree id
        mov     bx,TK_TG_CSUB or TK_SF_WORKER   ; Scan command subtree
                                                ; carry stops worker
        mov     di,offset DOSHIGH3CODE:FindSigProc ; DI = offset of worker
        call    ScanTasks                       ; Scan command subtree
        RestoreReg <ax>                         ; AX = signal number
        jc      short ssg3                      ; Jump if error

;       If the worker found that the supplied csid did not correspond
;       to a direct child of the caller, it will clear CX to indicate an
;       error. Note this makes any attempt to send a signal to oneself
;       fail. This method assumes that 0 is not a valid value for csid

;       Note that we return ERROR_INVALID_FUNCTION in this case, which
;       is dumb but unavoidable.  We should really return
;       ERROR_NOT_DIRECT_CHILD.  Unfortunately, 1.0-1.2 shipped with
;       the following lines:
;
;>      Temporary equates till error/message file updated.
;>
;>      ERROR_NOT_DIRECT_CHILD  equ     ERROR_INVALID_FUNCTION
;
;       Since we are now stuck with this, I have removed the code that
;       used to differentiate between the invalid function case and
;       the invalid PID case.                   Reichel 11/2/89

        or      cx,cx                           ; Csid direct child's?
        jz      short ssg2                      ; No, go to error exit

;       Check if a process having a handler installed was found.  If found,
;       the Pid of a process that is leafmost among those in the command
;       subtree that have a handler installed will have been returned in DX.
;       Post the signal to that process.

        or      dx,dx                           ; Leafmost Pid with handler ?
        jz      short ssg3                      ; Jump if there isn't one
        mov     bl,1                            ; Send to one process only
        xor     cx,cx                           ; Zero signal argument
        call    POST_SIGNAL                     ; Send signal to leafmost proc
        RETC                                    ; Return AX = error if CF set

;       Signal number not SIGINTR or SIGBREAK.  This error should now be
;       ERROR_INVALID_SIGNAL_NUMBER but it is retained as is for
;       compatibility with OS/2 v1.0.

ssg2:   mov     ax,ERROR_INVALID_FUNCTION       ; Signal number invalid
        jmp     short ssg4                      ; Return error

;       No process has a handler installed for the signal

ssg3:   mov     ax,ERROR_NO_SIGNAL_SENT         ; No signal could be sent

ssg4:   stc                                     ; Indicate error, AX=error
        RETC                                    ; Return AX=error if CF set

EndProc w_SendSignal

;**     FindSigProc - Find leafmost process with signal handler
;
;       Worker routine for call to ScanTasks from w_SendSignal.  This
;       routine returns the target Pid in DX if the target process has a
;       handler installed for the signal specified by the bit set in CX.
;       The 1st time it is called the worker checks to see if the
;       process whose PTDA is supplied is a direct child of the caller.
;       If the process is not a direct child, the worker indicates
;       an error by clearing cx and aborts scantasks by setting carry.
;       Subsequent calls to the worker come to a different entry point of the
;       worker because the offset of the worker, stored in di, is adjusted
;       on the first call.
;
;       ENTRY   ES = PTDA
;               BP = Signal bitmask
;
;       EXIT    Success - DX = PID of leafmost process with handler
;               Failure - CX = 0 (Parent task not caller)
;                         DX = 0 (No process has signal handler)
;
;       USES    AX, CX, DX

        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

;       Entry point for 1st process examined
;       Check caller is direct parent of process under examination

Procedure FindSigProc,,local
        mov     ax,es:[TKOPTDA.ptda_Ppid]       ; get pid of parent of task
        cmp     ax,ss:[TKOPTDA.ptda_Pid]        ; is it the caller?
        jne     short fsp3                      ; No, return error

;       Set up so that next entry to worker skips the above test

        mov     di,offset DOSHIGH3CODE:fsp1     ; 2nd entry point offset

fsp1:   test    es:[TKOPTDA.Sig_hndf],bp        ; Handler installed?
        jz      short fsp2                      ; Jump if no handler installed
        mov     dx,es:[TKOPTDA.ptda_Pid]     ; Remember Pid, forget previous
fsp2:   ret                                     ; Return to ScanTasks

;       Here if caller is not direct parent, clear cx to indicate error, and
;       set carry to abort scantasks

fsp3:   xor     cx,cx                           ;Clear cx for error
        stc                                     ;So scantasks will abort
        jmp     short fsp2

EndProc FindSigProc


;***    w_FlagProcess - Send a user-defined signal
;
;       Send a signal to the named process or set of processes.
;
;       ENTRY   AL = flag number
;               BL = disposition
;                       0 = command subtree
;                       1 = only that process
;               CX = signal argument (user specified)
;               DX = Process ID
;
;       EXIT    Carry set if
;                       Invalid signal number of dispositon
;                       No processes matched
;                       Some targeted process had error action
;               else carry clear
;
;       USES    AX, DX, Flags
;
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure w_FlagProcess,faronly

;       PMONLY
        cmp     al,SIGPFC - SIGPFA      ; Check for bad flag number
        ja      short fpr1              ; Jump if too high
        add     al,SIGPFA               ; Convert to signal number
        cmp     bl,1                    ; Check for bad disposition
        ja      short fpr2              ; Jump if bad
        call    POST_SIGNAL             ; Send signal corresponding to flag
        ret                             ; Normal exit

;  Some specific error codes not yet implemented in error.inc - IDB

fpr1:   mov     ax,ERROR_INVALID_FLAG_NUMBER
        jmp     short fpr3
fpr2:   mov     ax,ERROR_INVALID_FUNCTION
fpr3:   stc                             ; Error exit
        ret

EndProc w_FlagProcess


;**     w_SetSigHandler - Set up a handler for a signal.
;
;       This is the system call entry to set up a signal handler.
;
;       This call is illegal at ExitList time
;
;       ENTRY   AL = signal number
;               DX:CX = address of handler      (*** WARNING ***)
;                                               (may not be RPL stamped)
;                                               (do not load into segment register)
;               BL = signal disposition:
;                       SIG_DFL = default action
;                       SIG_IGN = ignore
;                       SIG_GET = catch
;                       SIG_ERR = error to be sent
;                       SIG_ACK = rearm signal (no return values)
;       EXIT    DX:AX = previous handler
;               CL = previous disposition
;       USES    AX, BX, CX, DX, DI, SI, DS, ES, Flags
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

Procedure w_SetSigHandler,faronly

;       PMONLY

;       MMIOPH Performance Hook Removed
;       Maj/Min = 1863H, Data = ax, bx (sig number, sig action)

        or      al,al                   ; check for valid signal number
        jz      short ssh30             ; jump if signal number 0
        cmp     al,NSIG
        jae     short ssh30             ; jump if signal number >= NSIG
        cmp     al,2                    ; signal number 2 invalid
        je      short ssh30             ; jump if signal number 2
        cmp     bl,SIG_ACK              ; check for valid action
        ja      short ssh40             ; jump if bad action specified

; Since signal handlers need Thread 1 to be alive and well, we do not
; allow them to be installed if Thread 1 of the process has died or has
; been marked to terminate.  Also we do not allow them if we are in
; Exit List processing.

        test    byte ptr ss:[TKOPTDA.ptda_ProcStatus],PS_XITLST+PS_XITTH1
        jnz     short ssh50             ; jump if exit list or no thread 1

        FlatContext ds,di,NOASSUME
        mov     edi,ss:[TKOPTDA.ptda_pTCBHead]
        test    ds:[edi].TCBForcedActions,TK_FF_EXIT; is thread 1 on way out ?
        jnz     short ssh50             ; jump if thread 1 dying

; See if this is a Presentation manager app trying to set a SIGINTR or
; SIGBREAK. This is not allowed.

        cmp     byte ptr ss:[TKOPTDA.ptda_ProcType],PT_PRESMGR
                                        ; Is it a winthorn app?
        jne     short ssh10             ; If not, OK, skip ahead
        cmp     al,SIGINTR              ; Is it SIGINTR handler?
        je      short ssh30             ; If it is, go to error exit
        cmp     al,SIGBREAK             ; Is it a SIGBREAK handler?
        je      short ssh30             ; If it is, go to error exit

; Make sure that the selector is ring 3 - IF we're setting a sig handler

ssh10:  cmp     bl,SIG_GET              ; are we setting a handler?
        jne     short ssh20             ; no, so don't check address

        SaveReg <dx>                    ; save selector to handler
        and     dx,SEL_LDTBIT or SEL_RPLMASK    ; (DX) = handler RPL
        cmp     dx,SEL_RPL3 or SEL_LDTBIT       ; is it ring 3 LDT?
        RestoreReg <dx>                 ; (DX) = selector to handler
        jne     short ssh60             ; error if not

ssh20:  call    SetSignal               ; set signal handler/disposition
        clc                             ; Normal exit
        jmp     short sshx

ssh30:  mov     ax,ERROR_INVALID_SIGNAL_NUMBER   ; Bad signal number
        jmp     short sshex

ssh40:  mov     ax,ERROR_INVALID_FUNCTION   ; Bad action parameter
        jmp     short sshex

ssh50:  mov     ax,ERROR_THREAD_1_INACTIVE  ; Thread 1 dead or dying
        jmp     short sshex

ssh60:  mov     ax,ERROR_INVALID_STARTING_RING  ; handler must be ring 3

sshex:  stc                                 ; Error Exit
sshx:   ret

EndProc w_SetSigHandler

;**     SetSignal - Set up a handler for a signal.
;
;       SetSignal is a service routine for w_SetSigHandler.  It
;       does all the hard work after the parameters have been checked.
;
;       ENTRY   AL = signal number
;               DX:CX = address of handler      (*** WARNING ***)
;                                               (may not be RPL stamped)
;                                               (do not load into segment register)
;               BL = signal disposition:
;                       SIG_DFL = default action
;                       SIG_IGN = ignore
;                       SIG_GET = catch
;                       SIG_ERR = error to be sent
;                       SIG_ACK = rearm signal (no return values)
;       EXIT    DX:AX = previous handler
;               CX = previous disposition
;       USES    All

Procedure SetSignal,<near,far16>,local

        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
;       PMONLY

        FlatContext ds,si
        mov     esi,ss:[TKOPTDA.ptda_pTCBHead]  ; ESI = Thread 1 TCB
        SaveReg <cx>
        SigBit                          ; CX = signal bit mask
        not     cx                      ; Clear bit to acknowledge signal
        and     [esi].TCBSig_cur,cx
        RestoreReg <cx>
        cmp     bl,SIG_ACK              ; if action = SIG_ACK, we're almost done

ifdef SECURITY                                                                  ;@SEC
        jne     short sets0                                               ;@SEC

        cmp     al,SIGTERM              ; SIGTERM ?                       ;@SEC
        jnz     sets6                   ;  jmp if no                      ;@SEC

        push    eax                     ;                                 ;@SEC
        mov     eax,_pPTDACur           ; EAX = _pPTDACur                 ;@SEC
        cmp     [eax].SigFTerm,-1       ; forced SIGTERM in effect ?      ;@SEC
        pop     eax                     ;                                 ;@SEC
        jnz     sets6                   ;  jmp if no                      ;@SEC

        pushad                          ; kill process on SIG_ACK if      ;@SEC
        SaveReg es                      ;  forced SIGTERM in effect       ;@SEC
        FlatContext es,ax               ;                                 ;@SEC
        CCALL32 _TKDieSoonPTDA, <[_pPTDACur], 0, TC_SIGNAL, 0>            ;@SEC
        RestoreReg es                   ;                                 ;@SEC
     assume es:nothing                  ;                                 ;@SEC
        popad                           ;                                 ;@SEC
        jmp     sets6                   ;                                 ;@SEC
sets0:                                                                    ;@SEC
else                                                                      ;@SEC
        je      sets6                                                     ;@SEC
endif                                                                     ;@SEC
        cmp     byte ptr ss:[TKOPTDA.ptda_ProcType],PT_DETACHED
                                        ; Is process detached?
        je      short sets1d            ;  yes, don't worry about focus
        cmp     byte ptr ss:[TKOPTDA.ptda_ProcType],PT_VIOWIN
                                        ; Is process VIO_windowable?
        je      short sets1d            ;  yes, don't worry about focus
        cmp     al,SIGINTR              ; SIGINTR?
        je      short sets1a            ;  yes, skip ahead
        cmp     al,SIGBREAK             ; SIGBREAK?
        jne     short sets1d            ;  no, skip this part

;       Handle Ctrl-C/Ctrl-Break focus:
;
;       1) Either we are becoming the focus, or
;       2) we used to be the focus, or
;       3) neither of the above.
;
;       Since ResetSigFocus only does the reset if the current
;       process is the focus, we handle all three cases.  Note
;       that SIG_ACK neither sets nor resets the focus.  Note
;       also that a process becomes the focus even in the cases
;       where an explicit handler is not being set (SIG_IGN and
;       SIG_ERR).

sets1a: DosContext ds
        mov     di,ss:[TKOPTDA.ptda_infoseg.LIS_CurScrnGrp]
                                        ; Get task's screen group
        cmp     bl,SIG_DFL              ; Restoring system default?
        je      short sets1c            ;  yes, go reset focus if we were focus
        shl     di,2                    ; Scale index
        .errnz  ((SIZE SigFoci) - (1 SHL 2)) ; Error if scale factor bad
        mov     si,sfi_sigintr          ; Assume SIGINTR
        cmp     al,SIGINTR              ; SIGINTR?
        je      short sets1b            ;  yes, skip ahead
        mov     si,sfi_sigbreak         ; Must be SIGBREAK
sets1b: add     di,si                   ; DI = proper structure element index
        mov     si,ss:[TKOPTDA.ptda_Pid]     ; SI = current process' PID
        mov     word ptr SigFocus[di],si ; Set this process to signal focus
        jmp     short sets1d

sets1c: cmp     ss:[TKOPTDA.SigFocusCnt],0 ; 32-bit handlers in use?
        jg      short sets1d            ; Yes! Don't reset focus
        call    ResetSigFocus           ; Reset focus if we were the focus

sets1d: FlatContext ds,si
        mov     esi,ss:[TKOPTDA.ptda_pTCBHead]  ; ESI = Thread 1 TCB
        xor     ah,ah                   ; extend signal number to a word
        SaveReg <bx,ax>                 ; Save signal disposition,number, and
        SaveReg <cx>                    ; handler offset
        SigBit                          ; compute signal bit mask
        test    bl,1                    ; ignore or error action?
        jz      short sets1e            ; no
        not     cx                      ; yes, reset possible pending signal
        and     [esi].TCBSig_pend,cx
        not     cx
                                        ; we recompute this later
        and     [esi].TCBForcedActions,NOT TK_FF_SIG

; WARNING - the following code makes assumptions about the layout of
;           the variables Sig_ignf, Sig_hndf and Sig_errf and the
;           values assigned to the manifests SIG_IGN, SIG_HND and SIG_ERR.
;           (This code is gross!)
;
;       (EAX) = loop count/previous action index, and
;               default action to be returned
;       (ESI) = pTCB

sets1e: mov     ah,SIG_ERR              ; setup loop count/prev action index
        mov     al,SIG_DFL              ; default action to be returned
        mov     bp,offset ss:[TKOPTDA.Sig_errf]     ; pointer to end of flags
sets2:  test    cx,ss:[bp]              ; is bit set in this flag?
        jz      short sets3             ; no, try next
        mov     al,ah                   ; save action
        not     cx                      ; reset bit in flag
        and     ss:[bp],cx
        not     cx
sets3:  cmp     bl,ah                   ; is this where we want to set bit?
        jnz     short sets4             ; no
        or      ss:[bp],cx              ; set flag
sets4:  sub     bp,2                    ; point to next flag
        dec     ah                      ; see if done
        jnz     short sets2

; At this point, a bit in Sig_hndf might have been reset, if the requested
; action was SIG_IGN, SIG_DFL, or SIG_ERR. But Sig_hndf is also used to
; indicate that a thread is "signals aware", so if SigFocusCnt
; > 0 (a 32-bit thread is signals aware) then the bit in Sig_hndf
; should remain set.

        cmp     ss:[TKOPTDA.SigFocusCnt],0      ; 32-bit focus?
        jz      short sets4a            ; No. Continue
        or      ss:[TKOPTDA.Sig_hndf],cx        ; Yes, restore hndf bit.

sets4a: mov     cx,ax                   ; Save previous disposition
        RestoreReg <ax,bx>              ; (AX) = handler offset
        movzx   ebx,bx                  ; (EBX) = signal number
        push    ss:[TKOPTDA.Sig_vec-4][ebx*4] ; save old handler address
        or      dx,dx                   ; new handler has null selector?
        jz      short sets5             ;  yes, don't install it
        mov     word ptr ss:[TKOPTDA.Sig_vec-2][ebx*4],dx ; install new hdlr
        mov     word ptr ss:[TKOPTDA.Sig_vec-4][ebx*4],ax

sets5:  pop     ax                      ; return old handler
        pop     dx
        RestoreReg <di>                 ; Restore signal disposition
        cmp     di,SIG_GET              ; Are we installing a handler?
        je      short sets6             ;   yes. Don't zero the vector.
        mov     ss:[TKOPTDA.Sig_vec-4][ebx*4],0 ; Zero handler vector

sets6:  mov     bx,[esi].TCBSig_cur     ; BX = bit mask of current signals
        not     bx                      ; BX = bit mask of signals not current
        test    [esi].TCBSig_pend,bx    ; Any dispatchable signals?
        jz      short sets7             ;  no, exit
        or      [esi].TCBForcedActions,TK_FF_SIG ; remember for later action

sets7:  ret

EndProc SetSignal

;***    ResetSigFocus - Reset SIGINTR or SIGBREAK signal focus ancestor
;
;       Given the PTDA of the current process, this function checks if this
;       process is the focus for the specified signal type (only SIGINTR or
;       SIGBREAK signals have a focus) within its screen group.  If the
;       current process is the focus, the Parent PTDA links are followed to
;       look for an ancestor process that belongs to the same screen group and
;       has a handler installed.  If there is such an ancestor, the first
;       eligible ancestor found inherits the focus, otherwise there is no
;       focus (Pid = 0).
;
;       ENTRY   SS = PTDA of current process
;
;               DS = DOSGROUP
;
;               AL = Signal number, SIGINTR or SIGBREAK
;
;       EXIT    NONE
;
;       USES    DS,ES,Flags
;
        ASSUME  DS:DOSGROUP,ES:NOTHING,SS:NOTHING

Procedure ResetSigFocus,<near,far16>,local

;       PMONLY

;
; Only full screen procedures have a focus.
;

        cmp     byte ptr ss:[TKOPTDA.ptda_ProcType],PT_FULLSCRN
        jne     rsf6

        SaveReg <ax,bx,cx,dx,esi>               ; Save caller's registers

;       Get bit flag for signal number

        SigBit                                  ; CX = signal bit flag

IFDEF   ALLSTRICT

        test    cx,SIGINTRF+SIGBREAKF           ; Valid signal number?
        jz      short rsfie7                    ; J if not, internal error

ENDIF

;       Return pointer to slot containing the Pid of the signal focus for
;       screen group of the current process.

        mov     bx,ss:[TKOPTDA.ptda_infoseg.LIS_CurScrnGrp]
                                                ; BX = current screen group
IFDEF   ALLSTRICT
        cmp     bx, NSCRN
        jge     short rsfie8
ENDIF

        shl     bx,2                            ; Scale the index
        .errnz  ((SIZE SigFoci) - (1 SHL 2))    ; Check scale factor
        .errnz  sfi_sigintr                     ; Must be first field in struc
        cmp     al,SIGINTR                      ; SIGINTR focus specified ?
        je      short rsf1                      ; Jump if SIGINTR specified
        add     bx,sfi_sigbreak                 ; Must be SIGBREAK focus
rsf1:   add     bx,offset DOSGROUP:SigFocus     ; Add base of array

;       Check if the current process is the focus for the specified signal
;       and do nothing if not.

        mov     ax,[bx]                         ; Get Pid of signal focus
        cmp     ax,ss:[TKOPTDA.ptda_Pid]        ; Is it the current process ?
        jne     short rsf5                      ; Jump if not, exit

;       Look for ancestor process in same screen group having a handler
;       installed for the specified signal.  We will find the most recent
;       ancestor.

        mov     dx,ss:[TKOPTDA.ptda_infoseg.LIS_CurScrnGrp]
                                                ; DX = current screen gp
        FlatContext es,esi                      ; ES = FLAT
        mov     esi,_pPTDACur                   ; ESI = current ptda

rsf2:   mov     esi,es:[esi].pPTDAParent        ; ESI = ancestor PTDA
        or      esi,esi                         ; Have we reached top of tree?
        jz      short rsf4                      ; Jump if we have
        mov     ax,es:[esi].Sig_hndf            ; AX = mask of handled signals
        or      ax,es:[esi].Sig_ignf            ; AX = handled and ignored
        or      ax,es:[esi].Sig_errf            ; AX = mask of all signals
        test    ax,cx                           ; Is specified signal handled ?
        jz      short rsf2                      ; Jump if not, keep looking
        cmp     dx,es:[esi].ptda_infoseg.LIS_CurScrnGrp
                                                ; Ancestor in same SG ?
        jnz     short rsf2                      ; Jump if not

;       The most recent ancestor of the current process in the same screen
;       group and having a handler for the specified signal has been found.
;       Reset the signal focus to the Pid of that ancestor.

        mov     ax,es:[esi].ptda_Pid            ; AX = Pid of new focus
rsf4:   mov     [bx],ax                         ; Set the new focus

        ASSUME  ES:NOTHING

;       Restore caller's registers and return

rsf5:   RestoreReg <esi,dx,cx,bx,ax>
rsf6:   ret                                     ; Nothing is returned

IFDEF   ALLSTRICT
rsfie7: InternalError <ResetSigFocus: Invalid signal number>

rsfie8: InternalError <ResetSigFocus: Invalid screengroup>
ENDIF

EndProc ResetSigFocus



;**     ResetSignals - reset signals to default behavior
;
;       This function resets signals to their default behavior.
;       In particular, if the current process was the focus in
;       its screen group for either SIGINTR or SIGBREAK, then
;       the focus is reset.
;
;       ENTRY   (SS) = PTDA
;               (DS) = DOSGROUP
;
;       EXIT    NONE
;
;       USES    ES, Flags

Procedure ResetSignals,far16
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:NOTHING

;       PMONLY
        SaveReg <ax,cx,di>
        SaveReg <ds>

        mov     cx,ss:[TKOPTDA.Sig_hndf]
                                        ; Get handled signals
        or      cx,ss:[TKOPTDA.Sig_ignf]
                                        ; ...and ignored signals
        or      cx,ss:[TKOPTDA.Sig_errf]
                                        ; ...and error signals
        test    cx,SIGINTRF             ; Is SIGINTR a "handled" signal?
        jz      short rs0               ;  no, check SIGBREAK
        mov     al,SIGINTR              ; AL = SIGINTR
        call    ResetSigFocus           ; Reset focus if we were it
rs0:    test    cx,SIGBREAKF            ; Is SIGBREAK a "handled" signal?
        jz      short rs1               ;  no, skip ahead
        mov     al,SIGBREAK             ; AL = SIGBREAK
        call    ResetSigFocus           ; Reset focus if we were it
rs1:    TaskContext ds,cx
        FlatContext es,cx
        mov     edi,ss:[TKOPTDA.ptda_pTCBHead]
        xor     ax,ax
        mov     ds:[TKOPTDA.Sig_hndf],ax
                                        ; Signals no longer handled
        mov     es:[edi].TCBSig_pend,ax ; Signals no longer pending
        mov     es:[edi].TCBSig_holding,ax      ; No signals being held
        mov     byte ptr ds:[TKOPTDA.HoldSigCnt],al
        mov     es:[edi].TCBSig_cur,ax  ; No signals current
                                        ; Clear TK_FF_SIG for thread one
        and     es:[edi].TCBForcedActions,NOT TK_FF_SIG
        TaskContext es                  ; Make ES:DI point to handler vector
        mov     di,offset ss:[TKOPTDA.Sig_vec]
        mov     cx,(NSIG*4)/2           ; Number of words in Sig_vec
        rep     stosw                   ; Clear the array
        RestoreReg <ds>
    ASSUME      DS:DOSGROUP
        RestoreReg <di,cx,ax>           ; Restore registers
        RETC

EndProc ResetSignals


;**     POST_SIGNAL
;
;       Send a signal to a process, process group or screen group
;
;       Note that we will not post a KILL signal on any thread which
;       is executing its ExitList.
;
;       Sending a signal to all members of a screen group using this
;       procedure will not send a signal to any detached processes within
;       the screen group. The procedure has been modified to do this so
;       that KSGKILLPROCESS will not kil detached processes in a screen
;       group. (PTM11 724). This assumes that only KSGKILLPROCESS calls
;       post_signal with a signal to send to the entire screen group.
;
;       Note: Be careful when modifying use of stack in this procedure.
;
;       ENTRY   (AL) = signal number
;               (BL) = disposition
;                       0 = command subtree
;                       1 = only that process
;                       2 = Process and ALL descendants
;                       3 = all processes in screen group
;               (CX) = signal argument (user specified)
;               (DX) = Process ID if BL = 0, 1, or 2
;                      Screen Group # if BL=3
;
;       EXIT    Carry set
;                   (AX) = ERROR_SIGNAL_PENDING
;                   (AX) = ERROR_SIGNAL_REFUSED
;                   (AX) = ERROR_INVALID_PROCID
;                   (AX) = ERROR_NOT_DESCENDANT
;                   (AX) = ERROR_ZOMBIE_PROCESS
;               Carry clear
;                   Signal sent
;
;       USES    AX, DX (used by ScanTasks), Flags

Procedure POST_SIGNAL,HYBRID
        ASSUME  DS:NOTHING,ES:NOTHING,SS:NOTHING

;       PMONLY  TASKTIME
        TaskTime
        SaveReg <bp,bx,di,si,es>
        SaveReg <bx,cx>         ; Save disposition at [BP+6], examined later
                                ; SS:[BP+4] will be signal argument for psig

;       If we are sending signal to entire screen group, set bit in error
;        flags to indicate this to psig. This will tell it not to signal
;        detached processes. Clear rest of error byte.

        mov     ah,80h          ; Assume signal to screen group
        cmp     bl,3            ; is DX screen group # ?
        je      short ps0       ;  yes,
        or      dx,dx           ; is PID valid?
        jz      short ps1       ;  no, return an error
        xor     ah,ah           ; set up error flag
ps0:    push    ax              ; SS:[BP+2] will point to error flag/signal #
        SigBit                  ; convert signal number to bit mask
        xchg    cx,dx           ; DX = sig mask; CX = PID, CSID or SGID
        push    dx              ; SS:[BP+0] will point to signal bit mask
        mov     bp,sp
        mov     di,offset cs:psig16
        xor     bh,bh
        cmp     bl,TK_TG_SCRN
        jb      short ps00
        or      bx,TK_SF_WORKER
ps00:   call    ScanTasks       ; iterate through all tasks.
        pop     cx              ; throw out signal bit mask
        pop     cx              ; get error flag/signal number back
        jc      short ps3       ;  branch if no process found ((AX) = error)
        test    ch,0fh          ; Error sending signal? (TEST clears carry)
        jz      short ps3       ;  no, exit with carry clear

;       The signal was refused or another signal was already pending

        test    ch,3            ; Busy or pending error ?
        jz      short ps3       ; No, exit with carry clear and zero set

;       Here if there is a pending or busy error. Find out which.

        mov     ax,ERROR_SIGNAL_PENDING ; Assume signal already pending
        test    ch,2            ; Signal pending ?
        jnz     short ps2       ; Yes, go to error exit

;       Here if signal was not pending.  Assume signal refused.

        mov     ax,ERROR_SIGNAL_REFUSED ; Signal refused
        jmp     short ps2

;       No such process i.d.

ps1:    mov     ax,ERROR_INVALID_PROCID
ps2:    stc                     ; set error return indication

ps3:    RestoreReg <cx,bx>      ; Pop signal argument and disposition
        RestoreReg <es,si,di,bx,bp>
        ret

EndProc POST_SIGNAL


;**     psig16 - Helper routine for POST_SIGNAL
;
;       This routine is called for each task matching the selection
;       criteria given POST_SIGNAL.  Depending on the particular
;       signal action in effect, the process will be notified of
;       the arrival of the signal, an error condition will be noted,
;       the signal will be ignored, or the process will be asked to
;       terminate. The caller can skip the signalling of detached
;       processes by setting bit 7 of the error flag on the stack.
;       Psig16 takes care of purely 16-bit components of posting a
;       signal. Psig actually posts the signal.
;
;       ENTRY   ES = pointer to PTDA
;                               -----------------
;                            +5 |    sig arg    |+4
;                               +---------------+
;                            +3 | err fl| sig # |+2
;                               +---------------+
;               SS:BP ========> | sig bit mask  |+0
;                               -----------------
;               SS:BP pointer to parameter area for signal
;
;       BP+3, error flag, has bit 7 set if psig must not signal detached
;        processes.
;
;       EXIT
;
;       Low nibble of BP+3 indicates errors, bit 0, signal refused,
;       bit 1 busy bit, bit 2 attempt to signal zombie process
;
;       USES    AX,BX,FLAGS
;       CALLED FROM     SIG:  POST_SIGNAL via ScanTasks

Procedure psig16,hybrid
    ASSUME      DS:NOTHING,ES:NOTHING,SS:NOTHING

;       PMONLY  TASKTIME
        TaskTime

        SaveReg <edi>

;       Check to see if we are not to signal detached processes, and
;       if the supplied process is detached. If so, exit.

        test    byte ptr [bp+3],80h     ;Ignore detached processes?
        jz      short psig0             ;No, skip
        cmp     byte ptr es:[TKOPTDA.ptda_ProcType],PT_DETACHED
                                        ;Process detached?
        je      psig2                   ;Yes, exit

psig0:

ifdef   MISCSTRICT
;       Check if the process is alive

        test    byte ptr es:[TKOPTDA.ptda_ProcStatus],PS_DYING
                                        ; Is the process dying?
        jz      short psig0a            ;  no, keep going
        Panic   "psig: signalling dying process"
psig0a:
endif
ifdef SECURITY                                                                     ;@SEC
        mov     al,[bp+2]                   ; al = signal #               ;@SEC
        cmp     al,SIGTERM                  ; SIGTERM ?                   ;@SEC
        jnz     short psig0c                ;  jmp if no                  ;@SEC
        mov     al,[bp+4]                   ; al = signal arg             ;@SEC
        cmp     al,-1                       ; arg = -1 ?                  ;@SEC
        jnz     short psig0c                ;  jmp if no                  ;@SEC
        cmp     es:[TKOPTDA.SigFTerm],0     ; forced SIGTERM in progress? ;@SEC
        jz      psig0b                      ;  jmp if no                  ;@SEC
        mov     eax,ERROR_SIGNAL_PENDING    ; set error                   ;@SEC
        jmp     psig4                       ; exit                        ;@SEC
psig0b: mov     es:[TKOPTDA.SigFTerm],-1    ; set forced SIGTERM in progress  ;@SEC
psig0c:                                                                   ;@SEC
endif                                                                     ;@SEC
        SaveReg <ds,es>
        PushP   es:[TKOPTDA.ptda_pTCBHead]      ; Signal thread 1
        movzx   eax,[bp+2]
        PushP   eax                     ; Signal number
        FlatContext <es,ds>,ax
        CCALL32 _SIGPsig,,,PushP        ; Try to post the signal

;       Deal with signals without a signal handler when not holding
;       signals.  Check for refusad or fatal signals.
;
;       Check for ignored or refused signal

        or      eax,eax                 ; Error posting signal?
        RestoreReg <es,ds>
        jnz     short psig4

;       Call successful, save the argument

psig1:  mov     di,[bp+4]               ; Get signal arg
        mov     bl,[bp+2]               ; Get signal #
        movzx   ebx,bl
        mov     es:[TKOPTDA.Sig_arg-2][ebx*2],di  ; Save signal arg in PTDA

;       Check for fatal signal is in _SIGPsig

psig2:  RestoreReg <edi>
        RETC

psig4:  cmp     eax,ERROR_SIGNAL_PENDING ; Was signal already pending or held?
        jne     short psig5             ; No. Look for other errors
        or      byte ptr [bp+3],2       ; Set "busy bit"
        jmp     short psig2

psig5:  mov     ax,[bp]                 ; Signal bitmask
        test    es:[TKOPTDA.Sig_ignf],ax          ; Ignored signal?
        jnz     short psig2             ;  yes, nothing to do

        test    es:[TKOPTDA.Sig_errf],ax          ; Refused signal?
        jz      short psig2             ;  no, skip ahead
        or      byte ptr [bp+3],1       ; Set refused bit
        jmp     short psig2

EndProc psig16


;***    PostSigFocus - send a ^C or a ^Break to the current focus
;
;       This function sends the given signal to the appropriate
;       recipient.
;
;       ENTRY   AL = signal number (SIGINTR or SIGBREAK)
;               CX = signal argument
;               DS = DOSGROUP
;       EXIT    Carry clear
;                   Signal sent
;               Carry set
;                   No recipient
;       USES    BX, DX, Flags

Procedure PostSigFocus,hybrid
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:NOTHING

;       PMONLY  TASKTIME
        TaskTime
        mov     dx,sfi_sigintr          ; Assume SIGINTR
        cmp     al,SIGINTR              ; SIGINTR?
        je      short psf0              ;  yes, skip ahead
        mov     dx,sfi_sigbreak         ; Must be SIGBREAK

IFDEF   MISCSTRICT
        cmp     al,SIGBREAK             ; SIGBREAK?
        je      short psf0              ;  yes, okay
        InternalError <PostSigFocus - Invalid signal number>
ENDIF

psf0:   mov     bl,SISData.SIS_CurScrnGrp ; Get current screen group
        xor     bh,bh
        shl     bx,2                    ; Scale index
        .errnz  ((SIZE SigFoci) - (1 SHL 2)) ; Check scale factor
        add     bx,dx                   ; Adjust for proper signal
        mov     dx,word ptr SigFocus[bx]  ; Get the focus PID
        or      dx,dx                   ; Is there such a guy?
        stc                             ;  assume no
        jz      short psf1              ;  no, return carry set
        mov     bl,1                    ; Send signal to only one process
        call    POST_SIGNAL             ; Returns carry clear if successful
        jmp     short psf2

psf1:   call    KSGKillProcess          ;                                  CDB
psf2:   ret                             ;                                  CDB

EndProc PostSigFocus


HIGH3CODE ENDS


        FARCODE LOW
CODE    SEGMENT


;***    PostPending - Post pending signals
;
;       This function is called from Enter_Kmode and from
;       the idle loop to post any signals in response to
;       interrupt time events such as ^C and ^Break.
;
;       ENTRY   NONE
;       EXIT    NONE
;       USES    Flags

Procedure PostPending,<near,faronly,far16>
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

        TaskTime
        SaveReg <ds>
        DosContext ds
        test    PendingSignals,SIGINTRF+SIGBREAKF ; Any pending?
        jz      short pp2               ;  no, exit
        SaveReg <ax>
        whatmode ax                     ; In protected mode?
        jnc     short pp0               ;  no, exit
        call    PostPendingSub          ; Do the work
        jmp     short pp1
pp0:    SaveReg <es>
        call    ProtMode                ; Switch to protected mode
        DosContext ds
        call    PostPendingSub          ; Do the work in protected mode
        call    RealMode                ; Go back to real mode
        RestoreReg <es>
pp1:    RestoreReg <ax>
pp2:    RestoreReg <ds>
    ASSUME      DS:NOTHING
        RETC

EndProc PostPending


;***    PostPendingSub - worker for PostPending
;
;       ENTRY   DS = DOSGROUP
;       EXIT    NONE
;       USES    Flags

Procedure PostPendingSub,near,local
        ASSUME  DS:DOSGROUP, ES:NOTHING, SS:NOTHING

;       PMONLY  TASKTIME                ; Must be in protected mode
        TaskTime
        SaveReg <bx,cx,dx>
        test    PendingSignals,SIGINTRF ; Pending SIGINTR?
        jz      short pps0              ;  no, skip ahead
        mov     cx,PendingSigArg[SIGINTR*2] ; Get argument
        mov     al,SIGINTR              ; Put signal number in AL
        CALLFAR PostSigFocus            ; Send the signal
pps0:   test    PendingSignals,SIGBREAKF ; Pending SIGBREAK?
        jz      short pps1              ;  no, skip ahead
        mov     cx,PendingSigArg[SIGBREAK*2] ; Get argument
        mov     al,SIGBREAK             ; Put signal number in AL
        CALLFAR PostSigFocus            ; Send the signal
pps1:   mov     PendingSignals,0        ; Clear flags
        RestoreReg <dx,cx,bx>
        ret

EndProc PostPendingSub


;***    SigActive - check if thread 1 has signals to handle
;
;       This function is called to determine if the current
;       thread is thread 1 and if there are signals for it to
;       handle.
;
;       ENTRY   SS = PTDA of the current process
;       EXIT    Carry set
;                   Thread is thread 1 and has signals to handle
;               Carry clear
;                   Thread is not thread 1 or there are no signals to handle
;       USES    Flags

Procedure SigActive,<near,faronly,far16>
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

        SaveReg <bp,esi>
        mov     bp,ss:[TKOPTDA.CurrTCB]
        cmp     ss:[bp].TCBOrdinal,1    ; Thread 1?
;       clc                             ;  (TCBOrdinal is always nonzero: NC)
        jne     short sa0               ;  no, exit
        mov     esi,ss:[TKOPTDA.ptda_pTCBHead]
        push    ds                      ; 123335
        FlatContext ds                  ; 123335
        mov     bp,[esi].TCBSig_cur     ; Get current signals
        or      bp,[esi].TCBSig_pend    ; and pending signals (OR clears cy)
        pop     ds                      ; 123335
        jz      short sa0               ; Carry clear if signals not active

        stc                             ; This thread has signals to handle
sa0:    RestoreReg <esi,bp>
        RETC

EndProc SigActive

CODE    ENDS

           FARCODE HIGH32
HIGH32CODE SEGMENT

;**     SIGPOSTPENDINGHOOK - Thunk to PostPending from context hook
;
;       SIGPOSTPENDINGHOOK is the worker for a global context hook that
;       is fired if pending signals are detected in the idle loop
;       (SchedNext). PostPending cannot be called directly from SchedNext
;       because it might, in the process of posting a signal, touch a
;       not-present TIB when looking for exception handlers and this cannot
;       be done in the idle loop.
;
;       ENTRY   pRefData - Pointer to reference data
;               pFrameBase - Pointer to stack frame base
;
;       EXIT    none
;
;       USES    Flags

Procedure SIGPOSTPENDINGHOOK,pascal
ArgVar  pRefData,DWORD
ArgVar  pFrameBase,DWORD

        EnterProc
        CALL16 PostPending
        LeaveProc

        RETC
EndProc SIGPOSTPENDINGHOOK

;***    VR32IExitMustComplete - Ring 0 portion of DosExitMustComplete
;
;       VR32IExitMustComplete is called from DosExitMustComplete when a
;       signal or asyncronous exception has occurred during a must
;       complete section.
;
;       ENTRY   nothing
;
;       EXIT    Success - (EAX) = NO_ERROR
;
;       USES    EAX, EBX, ECX, ESI, FLAGS

Procedure VR32IExitMustComplete

        EnterProc

        mov     esi,[_pTCBCur]          ; ESI = Current TCB
imc1:   movzx   ebx,[esi].TCBSig_holding        ; EBX = held signals. Can't just do
                                        ;  BSF off TCB location because the
                                        ;  call to _SIGPsig might re-hold the
                                        ;  signal if a 16-bit holdsignal is
                                        ;  in effect.
imc2:   bsf     eax,ebx                 ; EAX = Held signal - 1
        jz      short imc10             ;  No more signals held.
        btr     ebx,eax
        btr     [esi].TCBSig_holding,ax ; Clear held signal
        inc     eax                     ; EAX = Signal number
        SaveReg <ebx,eax>
        CCALL32 _SIGPsig <eax,esi>      ; Post signal
        RestoreReg <ecx,ebx>            ; ECX = Held signal
        jmp     short imc2              ; Look for another signal

imc10:  LeaveProc
        RETC

EndProc VR32IExitMustComplete

;**     _SIGPsig - Generic signal post routine
;
;       This routine is called to post any signal, be it valid in
;       16-bit contexts, 32-bit contexts, or both. It is called
;       from psig16 (post 16-bit signals) and _SIGPostException (32-bit
;       signals).
;
;       ENTRY   psig_SigNum - Signal number
;               psig_pTCB   - TCB of thread in which signal should
;                             be posted.
;
;       EXIT    Success - (EAX) = NO_ERROR
;               Failure - (EAX) = ERROR_SIGNAL_PENDING
;                         (EAX) = ERROR_NO_SIGNAL_SENT
;
;       USES    EAX, EBX, ECX, FLAGS

    ASSUME      DS:FLAT,ES:FLAT,SS:NOTHING

Procedure _SIGPsig
ArgVar  psig_SigNum, DWORD              ; Signal number
ArgVar  psig_pTCB, DWORD                ; Address of TCB to post in

LocalVar psig_usMCCount,WORD            ; To hold must complete count
ifdef SECURITY                                                                ;@SEC
LocalVar fForcedSigTerm,WORD            ; Forced SIGTERM flag             ;@SEC
endif                                                                     ;@SEC

        EnterProc

        SaveReg <esi, edi, ebx>         ; C calling convention

;       PMONLY  TASKTIME
        TaskTime

ifdef SECURITY                                                         ;@SEC
        mov     fForcedSigTerm,0                                          ;@SEC
endif                                                                     ;@SEC

;       Check if the signal is currently held or pending

        mov     eax,[psig_SigNum]
        SigBit                          ; ECX = Signal bit mask
        mov     esi,[psig_pTCB]         ; ESI = pTCB

ifdef SECURITY                                                      ;@SEC
        cmp     eax,SIGTERM             ; SIGTERM ?                       ;@SEC
        jz      short sps0              ;  jmp if yes                     ;@SEC
        cmp     eax,SIGAPTERM           ; SIGAPTERM ?                     ;@SEC
        jnz     short sps0a             ;  jmp if no                      ;@SEC
sps0:   SaveReg <eax>                   ;                                 ;@SEC
        mov     eax,[esi].TCBpPTDA      ;                                 ;@SEC
        cmp     [eax].SigFTerm,-1       ; forced SIGTERM ?                ;@SEC
        RestoreReg <eax>                ;                                 ;@SEC
        jnz     short sps0a             ;  jmp if no                      ;@SEC
        mov     fForcedSigTerm,1        ; indicate forced SIGTERM         ;@SEC
        mov     edi, [esi].TCBpPTDA     ; EDI = pPTDA                     ;@SEC
        jmp     sps3                    ;                                 ;@SEC
sps0a:                                                                    ;@SEC
endif                                                                     ;@SEC
        mov     bx,[esi].TCBSig_pend    ; Get pending and held signals
        and     bx,NOT SIGAPTERMF       ;  Can't postpone Async PTERM.
        or      bx,[esi].TCBSig_holding
        test    bx,cx                   ; currently pending or held?
        jnz     sps6c                   ;  yes, go return error

;       If we are holding signals, hold the signal if holdable.
;       NOTE: SIGTERM was not holdable till PTM 2509.  Keep holdability
;       check for the present.  A super kill (non-holdable kill)
;       could then easily be introduced.

; *** Check for DosMustComplete goes here! (at sps1)

sps1:   SSToDS  edi,[psig_usMCCount]    ; EDI = place to store MC Count
        SaveReg <ecx>
        CCALL32 _SIGGetMustComplete,<esi,edi>
        RestoreReg <ecx>
        cmp     [psig_usMCCount],0      ; In a MC Section?
        jz      short sps2              ;  No. Continue
        SaveReg <ecx>
        CCALL32 _SIGSetMustCompleteFlag,<esi>
        RestoreReg <ecx>
        test    cx,SIG_MCHOLDABLE       ; Can we hold this signal?
        jz      short sps3              ;  No. Post it.
        or      [esi].TCBSig_holding,cx ; Hold the signal
        jmp     sps7                    ; Done for now

        align   4                       ; DWORD align jump target
sps2:   mov     edi, [esi].TCBpPTDA     ; EDI = pPTDA
        cmp     [esi].TCBOrdinal,1      ; Is this thread 1?
        jne     short sps3              ; No. Don't look at HoldSignal

        cmp     [edi].HoldSigCnt,0      ; Holding signals?
        jz      short sps3              ;  no, skip ahead
        test    cx,SIG_HOLDABLE         ; Postponable signal?
        jz      short sps3              ;  no, skip ahead
        or      [esi].TCBSig_holding,cx ; Hold the signal
        jmp     sps7                    ; Done for now

;       Check to see if there exists either an exception handler
;       chain on the appropriate thread or if there is a 16 bit handler
;       registered. In either case, make the signal pending and, if the
;       signal is not being processed (or if the signal is APTERM), wake
;       up the appropriate thread of the signalled process.  The exception
;       handler (if one exists) will be called first, and if that doesn't
;       handle the signal, the 16 bit handler will be called.
;
;       The check for handled signals used to be before the check for
;       holding signals (PTM 2509)

        align   4                       ; DWORD align jump target
sps3:   test    cx,SIG_FLAGS                    ; is it a 16 bit flag?
        jnz     short sps4                      ;  yes. Don't use X-Handler
        test    [edi].Sig_attempted,cx          ; Looking for 16-bit handlers?
        jnz     short sps4                      ;  Yes. Don't look for EH.

        SaveReg <ecx>
        CCALL32 _XCPTCheckExceptionHandler, <esi> ; ESI = pTCB
        or      eax,eax                         ; is there a handler?
        RestoreReg <ecx>
ifdef SECURITY                                                    ;@SEC
        jnz     sps6d                           ; yes, make pending,      ;@SEC
else                                                                      ;@SEC
        jnz     short sps6d                     ; yes, make pending,      ;@SEC
endif                                                                     ;@SEC
                                                ;               wake thread 1

;       There is no 32 bit exception handler, see if there are any 16-bit
;       handlers waiting.

sps4:   cmp     [esi].TCBOrdinal,1              ; Is this thread 1?
        jne     short sps6                      ; No. Don't look for 16-bit
                                                ;  handlers
        test    cx, SIGAPTERMF                  ; 32-bit only signal?
        jnz     short sps6                      ;  Yes. Don't look for 16-bit
                                                ;  handlers.
        mov     eax,[psig_SigNum]               ; EAX = Signal number
        cmp     [edi].Sig_vec-4[eax*4],0        ; Handled signal?
        jne     short sps6d                     ;  yes, go make it pending

; We come here if no signal was sent
; We get here if the signal couldn't be posted because no exception
; handler was available. If the default action for the signal is
; kill, then the thread needs to be killed.

sps6:   test    ecx, SIGAPTERMF         ; Is default action kill?
        jz      short sps6a             ; No. Do nothing.

        mov     eax, [psig_pTCB]        ; EAX = TCB to kill

; The TMF_EXIT_TERM flag means exit w/o calling exception handlers. This
; is set to avoid going into an infinite loop. At this point we've already
; tried exception dispatching and we just want to kill the process.

        or      [esi].TCBMiscFlags, TMF_EXIT_TERM ; Don't call EH's
        SaveReg <ecx>                             ; 84891
        CCALL32 _TKForceThread, <TK_FF_EXIT, eax> ; Wake thread
        RestoreReg <ecx>                          ; 84891

; Look for SIGTERM to kill the process if it won't get handled
; The correct 16-bit actions for SIG_IGN and SIG_ERR will be done
; in psig16 but putting the death logic here stops putting copies of
; death logic in several places.

sps6a:  test    ecx, SIG_DFKIL          ; Default kill?
        jz      short sps6b             ;  No. continue
ifdef SECURITY                                                         ;@SEC
        cmp     fForcedSigTerm,0        ; forced SigTerm ?                ;@SEC
        jnz     short sps6aa            ;  jmp if yes                     ;@SEC
endif                                                                     ;@SEC
        test    [edi].Sig_ignf,cx       ; Ignore it?
        jnz     short sps6b             ;  Yes.
        test    [edi].Sig_errf,cx       ; Error return?
        jnz     short sps6b             ;  Yes. Same as ignore here

sps6aa:

        test    byte ptr [edi].ptda_ProcStatus,PS_XITLST+PS_XITALL
                                        ; Already dying?
        jnz     short sps6b             ;  Yes.
        CCALL32 _TKDieSoonPTDA, <edi, 0, TC_SIGNAL, 0>
ifdef SECURITY                                                            ;@SEC
        cmp     fForcedSigTerm,0        ; forced SigTerm ?                ;@SEC
        jnz     short sps7              ;  jmp if yes                     ;@SEC
endif                                                                     ;@SEC
sps6b:  mov     EAX,ERROR_NO_SIGNAL_SENT
        jmp     short sps8

sps6c:  mov     eax,ERROR_SIGNAL_PENDING ; Set return code
        jmp     short sps8               ; Return

;       Make handled signal pending

        align   4                       ; DWORD align jump target
sps6d:  or      [esi].TCBSig_pend,cx            ; Make signal pending
        and     [esi].TCBSig_cur, NOT SIGAPTERMF        ; This is meaningless
                                                        ; for APTERM because
                                                        ; we want to dispatch
                                                        ; another even if we
                                                        ; are handling one.
        test    [esi].TCBSig_cur,cx             ; Signal being processed?
        jnz     short sps7                      ;  yes, don't force awakening

;       Wake thread one

        CCALL32 _TKForceThread, <TK_FF_SIG, esi> ; Beat on thread

        .errnz (NO_ERROR)
sps7:   xor     eax,eax                 ; Return NO_ERROR

sps8:   RestoreReg <ebx, edi, esi>
        LeaveProc
        RETC

EndProc _SIGPsig

;**     Sig_Proc - Signal a process
;
;       This routine is called, just before process reactiviation,
;       when a signal is pending.  It chooses a signal from the
;       list of pending ones and diddles the user stack to cause
;       the exception handler to be called.
;
;       Sig_Proc clears the TK_FF_SIG bit and sets the "signal in progress"
;       bit which prohibits further signals of the same type until that
;       signal is SIG_ACK'ed.
;
;       Upon entry, the user's stack looks like:
;
;                       +---------------+
;                       |               |
;                       .   Program's   .
;                       .     Stack     .
;
;                       |               |<------+
;                       +---------------+       |
;                                               |
;       And the kernel stack looks like:        |
;                                               |
;                       +---------------+       |
;                       |    User SS    |--+    |
;                       +---------------+  +----+
;                       |    User SP    |--+
;                       +---------------+
;                       |               |
;                       .               .
;                       .   User args   .
;
;                       |               |
;                       +---------------+
;                       |    User CS    |
;                       +---------------+
;                       |    User IP    |
;                       +---------------+
;                       |   User flags  |
;                       +---------------+
;                       |               |
;                       .               .
;                       .   User Regs   .
;
;                       |               |
;                       +---------------+
;
;       Sig_Proc makes them look like:
;
;                       +---------------+
;                       |               |
;                       .   Program's   .
;                       .     Stack     .
;
;                       |               |
;                       +---------------+
;                       |   User flags  |
;                       +---------------+
;                       |    User CS    |
;                       +---------------+
;                       |    User IP    |
;                       +---------------+
;                       |    Sig Arg    |
;                       +---------------+
;                       |    Sig Num    |
;                       +---------------+
;                       | SigHandler CS |
;                       +---------------+
;                       | SigHandler IP |<------+
;                       +---------------+       |
;                                               |
;       and                                     |
;                                               |
;                       +---------------+       |
;                       |    User SS    |--+    |
;                       +---------------+  +----+
;                       |    User SP    |--+
;                       +---------------+
;                       |               |
;                       .               .
;                       .   User args   .
;                           or flags
;                       |               |
;                       +---------------+
;                       | Dispatcher CS |
;                       +---------------+
;                       | Dispatcher IP |
;                       +---------------+
;                       |   User flags  |
;                       +---------------+
;                       |               |
;                       .               .
;                       .   User Regs   .
;
;                       |               |
;                       +---------------+
;
;       Shortly after Sig_Proc returns the system will transfer control
;       to the user process, as usual.  Control will pass, however,
;       to the user's signal handler.
;
;       The user program must then dismiss the pending signal via
;       SIG_ACK system call and go on about his business.  It is
;       the user's responsibility to clean the stack.
;
;       ENTRY   EAX = Signal number
;
;       EXIT    NONE
;
;       USES    EAX, EBX, ECX, EDX, EDI, ESI, FS, GS, Flags
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

sigp_s  struc
        sigp_pfnSignalHdlr      dd      ?
        sigp_usSignalNum        dw      ?
        sigp_usSignalArg        dw      ?
        sigp_ulUserEIP          dd      ?
        sigp_ulUserCS           dd      ?
        sigp_ulUserEFLAG        dd      ?
sigp_s  ends

Procedure Sig_Proc,near
        TaskTime

LocalVar sgp_sigp,<size sigp_s>                 ; signal dispatch struc

        EnterProc
        mov     esi,[_pPTDACur]                 ; (ESI) = current PTDA pointer
        mov     edi,[_pTCBCur]                  ; (EDI) = current TCB pointer
        dec     eax                             ; (EAX) = (signal number - 1)

        mov     edx,[esi+eax*type Sig_vec].Sig_vec ; (EDX) = handler address
        or      edx,edx                         ; Does 16-bit handler exist?
        jz      sgp1                            ; No. Just return
        mov     [sgp_sigp.sigp_pfnSignalHdlr],edx

        mov     dx,[esi+eax*type Sig_arg].Sig_arg ; (DX) = signal argument
        mov     [sgp_sigp.sigp_usSignalArg],dx

        inc     eax                             ; (EAX) = signal number
        mov     [sgp_sigp.sigp_usSignalNum],ax

;       Set up an IRET frame on the user stack for final return
;       to the user from the ring 3 DosISigDispatch routine.
;
;       (ESI) = pPTDACur
;       (EDI) = pTCBCur

        SSToDS  eax,[sgp_sigp.sigp_ulUserCS]
        PCall   KMQUERYCLIENTREGISTER, <EDI, KM_REG_CS, eax>
        or      eax,eax
        jnz     short sgpie2

        SSToDS  eax,[sgp_sigp.sigp_ulUserEIP]
        PCall   KMQUERYCLIENTREGISTER, <EDI, KM_REG_EIP, eax>
        or      eax,eax
        jnz     short sgpie3

        SSToDS  eax,[sgp_sigp.sigp_ulUserEFLAG]
        PCall   KMQUERYCLIENTREGISTER, <EDI, KM_REG_EFLAG, eax>
        or      eax,eax
        jnz     short sgpie2

;       Put the signal dispatcher address on the kernel stack

        movzx   eax,[_pfnSigDispatch].Offst
        PCall   KMSETCLIENTREGISTER, <EDI, KM_REG_EIP, eax>
        or      eax,eax
        jnz     short sgpie2

        movzx   eax,[_pfnSigDispatch].Segmt
        PCall   KMSETCLIENTREGISTER, <EDI, KM_REG_CS, eax>
        or      eax,eax
sgpie3: jnz     short sgpie2                    ; Label for intermediate jump

;       Put the signal proc buffer on the user's stack

        SSToDS  eax,[sgp_sigp]
        PCall   KMPUSHCLIENTSTACK, <EDI, (size sigp_s), eax, TK_UM_FATAL>

;       Ignore errors from KMPushClientStack - stack faults are handled

sgp1:   LeaveProc
        ret
EndProc   Sig_Proc
sgpie2: Panic   <"Sig_Proc: KMQuery/SetClientRegister">

;**     _SigResetSigFocus - Thunk to ResetSigFocus
;
;       _SigResetSigFocus is called from TKApiSetSignalExceptionFocus
;
;       ENTRY   SigNum  - Signal number
;
;       EXIT    None
;
;       USES    ES,Flags

Procedure _SigResetSigFocus,near
ArgVar  SigNum, DWORD

        EnterProc

        DosContext ds,ax
        mov     eax,SigNum
        CALL16  ResetSigFocus
        FlatContext ds,ax

        LeaveProc

        RETC

EndProc _SigResetSigFocus

;***    _SigReset - Clean up after exception handler has been passed signal
;
;       _SigReset masks out invalid signals and either ACKnowledges a
;       signal has been handled by an exception handler or dispatches
;       the signal to a 16-bit handler, or takes the default action, as
;       appropriate.
;
;       ENTRY   sr_SignalNum - Exception number
;               sr_fHandled     - Flag indicating whether the signal was
;                                 handled by the exception handler
;
;       EXIT    None
;
;       USES    EAX, EBX, ECX, EDX

Procedure _SigReset
ArgVar  sr_SignalNum,DWORD
ArgVar  sr_fHandled,DWORD

        ASSUME DS:FLAT, ES:FLAT, FS:nothing, GS:nothing, SS:nothing

        EnterProc
        SaveReg <esi,edi,ds>
        mov     eax,[sr_SignalNum]      ; (EAX) = signal number

        cmp     eax,1                   ; Is signal too small?
        jb      short sr30              ;  Yes. Exit.
        cmp     eax,32                  ; Is signal too large?
        ja      short sr30              ;  Yes. Exit.
        SigBit                          ; (ECX) = signal bit mask
        and     ecx,SIG_SIGNALS         ; Is signal supported?
        jz      short sr30              ;  No. Exit.

        cmp     [sr_fHandled],XCPT_CONTINUE_EXECUTION
        jne     short sr10
        xor     dx,dx
        mov     cx,dx
        mov     bl,SIG_ACK
        SaveReg <ebp>
        CALL16  SetSignal
        RestoreReg <ebp>
        jmp     short sr30

;       al = signal number

sr10:   mov     edi,[_pPTDACur]                 ; (ESI) = current PTDA pointer
        SigBit                                  ; (ECX) = Signal bit
        or      [edi].Sig_attempted,cx          ; we've tried this one
        mov     esi,[_pTCBCur]                  ; ESI = Current TCB
        not     cx
        and     [esi].TCBSig_pend,cx            ; make sure its not pending
        and     [esi].TCBSig_cur,cx             ; turn off bit in TCBSig_cur
        SaveReg <ecx>
        CCALL32 _SIGPsig, <eax, esi>            ; Post it again
        RestoreReg <ecx>
        or      eax,eax                         ; Was it sent?
        jz      short sr30                      ;  Yes.
        and     [edi].Sig_attempted,cx          ; Signal not sent so don't
                                                ; set Sig_attempted
sr30:   RestoreReg <ds,edi,esi>
        LeaveProc
        RETC

EndProc _SigReset

;***    _SigResetAPTERM - Clear SIGAPTERM bit in current thread.
;
;       _SigResetAPTERM clears the SIGAPTERM bit in the current thread.
;       It is invoked via DosAcknowledgeSignalException(XCPT_SIGNAL_APTERM)
;       to acknowledge an async process termination.
;
;       ENTRY   sr_SignalNum    - Exception number
;               sr_fHandled     - Flag indicating whether the signal was
;                                 handled by the exception handler
;
;       EXIT    None
;
;       USES    All

Procedure _SigResetAPTERM                                             ;108449
ArgVar  sr_SignalNum,DWORD                                            ;108449
ArgVar  sr_fHandled,DWORD                                             ;108449

        ASSUME DS:FLAT, ES:FLAT, FS:nothing, GS:nothing, SS:nothing   ;108449

        EnterProc
        SaveReg <esi,eax,ecx>                                         ;108449
        mov     eax,[sr_SignalNum]      ; (EAX) = signal number       ;108449
        cmp     eax,SIGAPTERM           ; Is signal async PTERM?      ;108449
        jne     short sra30             ;  No. Exit.                  ;108449
        cmp     [sr_fHandled],XCPT_CONTINUE_EXECUTION ; Handled?      ;108449
        jne     short sra30             ;  No. Exit.                  ;108449

        SigBit                          ; CX = signal bit mask        ;108449
        not     cx                      ; Clear bit to acknowledge sig;108449
        mov     esi,_pTCBCur            ; ESI = Current TCB           ;108449
        and     [esi].TCBSig_cur,cx     ; Clear bit in current thread ;108449

sra30:  RestoreReg <ecx,eax,esi>                                      ;108449
        LeaveProc                                                     ;108449
        RETC                                                          ;108449

EndProc _SigResetAPTERM                                               ;108449

;***    _SIGApiSendSignalException - Cause a Ctrl-C or Ctrl-Break exception
;
;       _SIGApiSendSignalException is just a exception-to-signal conversion
;       and a call to w_sendsignal. Basically just a thunk.
;
;       ENTRY   sse_pid         - Pid of process subtree
;               sse_ulExceptNum - Exception number (ctrl-C or ctrl-Break)
;
;       EXIT    Success
;                       (EAX) = NO_ERROR
;               Failure
;                       (EAX) = ERROR_NO_SIGNAL_SENT
;                       (EAX) = ERROR_INVALID_PROCID
;                       (EAX) = ERROR_INVALID_FUNCTION
;                       (EAX) = ERROR_SIGNAL_REFUSED
;
;       USES    EAX,BX,ECX,EDX,Flags

Procedure _SIGApiSendSignalException
ArgVar sse_pid,DWORD                    ; PID of command subtree
ArgVar sse_ulExceptNum,DWORD            ; Exception (INTR or BREAK)

        EnterProc
        mov     ecx, [sse_pid]          ; CX = Command Subtree ID
        mov     eax, [sse_ulExceptNum]
        .errnz  (SIGINTR - XCPT_SIGNAL_INTR)
        cmp     eax,SIGINTR             ; Is it a valid SIGINTR?
        je      short sse1              ; Yes.
        .errnz  (SIGBREAK - XCPT_SIGNAL_BREAK)
        cmp     eax,SIGBREAK            ; Is it a valid SIGBREAK?
        je      short sse1              ; Yes.

        mov     ax,ERROR_INVALID_FUNCTION       ; Invalid signal
        jmp     short ssex              ; Bad exception num. Exit

sse1:   SaveReg <ebp, edi, ds>
        CALL16  w_SendSignal
        RestoreReg <ds,edi,ebp>
        jc      short ssex              ; Error code in ax
        .errnz (NO_ERROR)
        xor     eax,eax                 ; else return no error
ssex:   movzx   eax,ax                  ; High half might be garbage
        LeaveProc
        RETC
EndProc _SIGApiSendSignalException

HIGH32CODE ENDS

END
