;       SCCSID = @(#)schedapi.asm       6.11 91/10/17
SCCSID  equ     "@(#)schedapi.asm       6.11 91/10/17"
        page    ,132
        title   CP-DOS Scheduler API Routines     **** IBM CONFIDENTIAL ****

;***************************************************************************
;
; Source File Name:   SCHEDAPI.ASM
;
; Descriptive Name:   CP-DOS Scheduler API routines
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1991
;       Copyright (c) Microsoft Corporation 1987, 1991
;
;       All Rights Reserved
;
; Function:     This module contains routines which comprise the
;               applications interface (API) to the scheduler.
;
; Notes:
;     Dependencies:
;                None.
;     Restrictions:
;                The subroutines in this file were written to run in
;             PROTECT MODE only.
;                Process ID zero (which implies the currently executing
;             process) is not allowed at interrupt time.
;                Thread ID zero (which implies the currently executing
;             thread) is not allowed at interrupt time.
;                Enter/ExitCritSec (which assumes the currently executing
;             process) is not allowed at interrupt time.
;
; Entry Points:
;               ForceCritSec:near procedure in segment code
;               SetThreadKbdLocus near procedure in segment code
;               w_EnterCritSec hybrid procedure in segment HIGH3CODE
;               w_ExitCritSec hybrid procedure in segment HIGH3CODE
;               w_GetPrty hybrid procedure in segment HIGH3CODE
;               w_SetFgnd faronly procedure in segment HIGH3CODE
;               w_SetPrty hybrid procedure in segment HIGH3CODE
;
; External References:
;               ScanTasks
;               TKEachThread
;               _TKPidToPTDA
;               TidToTn
;
; Date      Who     Modification
;***************************************************************************
;09-03-91   Mark    Made VDMs have Flat (always regular) priority.  Tagged
;         Fiechtner with "090391".
;18-Nov-95  MLM     Defect 72417, moved find.inc after tkexport.inc
;
;***************************************************************************

.xlist
include dosseg.inc
include basemaca.inc
include osmaca.inc
include fnotask.inc
include osconst.inc
include struc.inc
include mi.inc
include infoseg.inc
include proc.inc
include screen.inc
include ostypes.inc
include sft.inc
include dossymc.inc
include sigdef.inc
include except.inc
include argframe.inc
include pgexport.inc
include vmexport.inc
include selxport.inc
include curdir.inc
include dirent.inc
include sem.inc
include tkexport.inc
include find.inc
include tkptda.inc
include error.inc
include error2.inc
include sched.inc
include mmpha.inc

.list
        CpuMode 386
        ModName ,FNO_SCHEDAPI_ASM

BREAK   <Global Definitions>
        ReferFlat       _ThreadCount,WORD       ;see SCHED.ASM
        ReferFlat       MaxThreads,WORD         ;see SCHED.ASM
        ReferFlat       SISData,BYTE            ;see SDATA.ASM
        ReferFlat       _FgndSGID,WORD          ;see SDATA.ASM
        ReferFlat       _tkFgndPID,WORD         ;                  26215
        ReferFlat       _Sis2,BYTE              ;see pga.asm
        ReferFlat       _Lis2,BYTE              ;see pga.asm
        ReferFlat       _pPTDACur,DWORD
        ReferFlat       _pTCBCur,DWORD
        ReferFlat       _papTCBSlots,DWORD
        ReferFlat       _Resched,BYTE

        EXTRN32         _schWindowBoost
        EXTRN32         _TKDescendant
        EXTRN32         _TKEachThread
        EXTRN32         _TKPidToPTDA
        EXTRN32         _TKScanTasks
        EXTRN32         _TKTidTo_iSlot
        EXTRN32         _TKTidTo_pTCB
        EXTRN32         _TKGetPriority
        EXTRN32         _TKUpdatePriority

;        EXTRN32         _SCHSetState
        EXTRN32         _TKUpdateState
        EXTRN32         _SCHSlotSetPriority


BREAK   <_schMapPid>
;***************************************************************************
;
; Subroutine Name:  _schMapPid
;
; Descriptive Name:   Get the currect Pid to use, even if zero
;
; Function:
;       This routine checks to see if the process id is magic (zero). If it
;       is, it is changed to the process id of the current process.
;
; Notes:
;       Most scheduler functions allow a process id of zero to be passed in
;       to indicate the function applies to the current process.
;
; Entry Point:  _schMapPid
;       Linkage:  C Calling Convention
;
; Entry:
;       Pid = process id
;           0 => Current process
;
; Exit-Normal:
;       (EAX) = process id
;
; Exit-Error:
;       none
;
; Effects:
;       nothing
;
; Internal References:
;              Routines:
;       none
;
; External References:
;              Routines:
;       none
;
; Pseudo Code:
;       Procedure _schMapPid
;         return (Pid==0 ? current Pid : Pid)
;       Return
;
;***************************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schMapPid,,,,esp
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  Pid,DWORD

        movzx   eax,WORD PTR [Pid]
        or      eax,eax
        .if             <z>
          TaskTime
          movzx   eax,WORD PTR ss:[TKOPTDA.ptda_infoseg.LIS_CurProcID]
        .endif
        RETC
EndProc _schMapPid
HIGH32CODE      ENDS


BREAK   <_schMapTid>
;***************************************************************************
;
; Subroutine Name:  _schMapTid
;
; Descriptive Name:   Magic Thread ID?
;
; Function:
;       This routine checks to see if the thread id is magic (zero). If it
;       is, it is changed to the thread id of the current thread.
;
; Notes:
;       Most scheduler functions allow a thread id of zero to be passed in
;       to indicate the function applies to the current thread.
;
; Entry Point:  _schMapTid
;       Linkage:  C Calling Convention
;
; Entry:
;       Tid = thread id
;           0 => current thread
;
; Exit-Normal:
;       EAX = thread id
;
; Exit-Error:
;       none
;
; Effects:
;       nothing
;
; Internal References:
;              Routines:
;       none
;
; External References:
;              Routines:
;       none
;
; Pseudo Code:
;       Procedure _schMapTid
;         return (Tid==0 ? Tid : Current Tid)
;       Return
;
;***************************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schMapTid,,,,esp
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  Tid,DWORD

        movzx   eax,WORD PTR [Tid]
        or      eax,eax
        .if             <z>
          TaskTime
          movzx   eax,WORD PTR ss:[TKOPTDA.ptda_infoseg.LIS_CurThrdID]
        .endif
        RETC
EndProc _schMapTid
HIGH32CODE      ENDS


BREAK   <w_EnterCritSec>
;***********************************************************************
;
; Subroutine Name:  w_EnterCritSec
;
; Descriptive Name:   Enter critical section
;
; Function:
;       This routine disables thread switching for the current process.
;
; Notes:
;       All  other threads in the process (excluding  the calling thread)
;       have a pending  forced-action  posted to put themselves  into the
;       "CritSec" state.
;
;       w_EnterCritSec may be called up to 65535 times without any
;       intervening calls to w_ExitCritSec.  The first call puts the process
;       into a critical section.  Subsequent calls increment a counter
;       which is decremented by w_ExitCritSec.  The process remains in
;       the critical section until this count reaches 0 or until
;       w_ForceExitCritSec is called.
;
;       If  a signal occurs and thread 1 is in a not-ready state, it will
;       be forced  into the "Ready" state  so  that  it  may execute  the
;       signal handler.  Any  processing  thread 1 does  to  satisfy  the
;       signal  must  not access  the critical resource  intended  to  be
;       protected by the w_EnterCritSec.
;
;       The code is optimized for the normal case (entering critical section
;       for the first time), and is arranged for execution to fall through
;       efficently when there are no errors.
;
; Entry Point:  w_EnterCritSec
;       Linkage:  Call (near)
;
; Entry:
;       nothing
;
; Exit-Normal:
;       EAX = 0
;
; Exit-Error:
;       EAX = ERROR_CRITSEC_OVERFLOW
;       EAX = ERROR_INVALID_THREADID
;
; Effects:
;       no registers preserved
;
; Internal References:
;      Routines:
;      none
;
; External References:
;      Routines:
;      none
;
; Pseudo Code:
;       Procedure w_EnterCritSec()
;       If this is the 1st time in or is the original TCB
;          If the counter will not overflow
;            Increment the process's critical section flag
;            Remember this TCB's ID in the PTDA
;            Flag no error
;          Else
;            Flag error
;          Endif
;       Else
;         Flag error
;       Endif
;       Return
;
;***********************************************************************

                FARCODE HIGH3
HIGH3CODE       SEGMENT
Procedure       w_EnterCritSec,<near,far16>
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

        TaskTime

if RAS
;***DT  DosEnterCritSec - Pre-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_PRE_DOSENTERCRITSEC>,
;               TP      = .DosEnterCritSec_PreTrace,
;               TYPE    = (PRE,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosEnterCritSec Pre-Invocation"

        public  DosEnterCritSec_PreTrace
DosEnterCritSec_PreTrace:

        MMPHPreDOSEnterCritSec                  ; Performance Hook (10/03)

;       Maj/Min = Tracecode_Tasking shl 8 + TraceCode_PreEnterCritSec,
;       Data = none
endif ;RAS

;       If there is no current critical section in effect, or if
;       the current thread owns the critical section, then increment
;       the critical section count and (if it did not overflow) then
;       store the current TCB pointer in ptda_pTCBCritSec.

        FlatContext <es>,ax
        mov     eax,ss:[TKOPTDA.ptda_pTCBCritSec]
        .if     <zero eax> or
        .if     <eax eq [_pTCBCur]>
           inc     ss:[TKOPTDA.ptda_cCritSec]   ; increment count
           .if     nz                           ; If the count did not overflow
              mov     eax,[_pTCBCur]
              mov     ss:[TKOPTDA.ptda_pTCBCritSec],eax ; Save TCB pointer
              xor     eax,eax                   ; NO_ERROR

if RAS
;***DT  DosEnterCritSec - Post-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_POST_DOSENTERCRITSEC>,
;               TP      = .DosEnterCritSec_PostTrace,
;               TYPE    = (POST,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosEnterCritSec Post-Invocation"

        public  DosEnterCritSec_PostTrace
DosEnterCritSec_PostTrace:

ecsx:         MMPHPostDOSEnterCritSec           ; Performance Hook (10/83)

;       Maj/Min = Tracecode_Tasking shl 8 + TraceCode_PostEnterCritSec
;       Data = none
else ;RAS
ecsx:
endif ;RAS

         RETC                              ; actual EXIT

           .endif
           dec     ss:[TKOPTDA.ptda_cCritSec]   ; Fix count overflow
           mov     eax,ERROR_CRITSEC_OVERFLOW   ; return error
           jmp     short ecsx                   ; jump back up to actual EXIT
        .else
           mov     eax,ERROR_INVALID_THREADID   ; wrong thread
           jmp     short ecsx                   ; jump back up to actual EXIT
        .endif

EndProc w_EnterCritSec
HIGH3CODE       ENDS


BREAK   <w_ExitCritSec>
;***********************************************************************
;
; Subroutine Name:  w_ExitCritSec
;
; Descriptive Name:  Exit critical section
;
; Function:
;       Re-enables thread switching for the current process.
;
; Notes:
;       w_ExitCritSec counts down the number of previous w_EnterCritSec
;       calls.  When this count reaches 0, the process exits the
;       critical section.  If no critical section is in effect, this
;       routine does nothing.
;
;       If the scheduler has been called since the critical section was
;       entered, then the other threads in the process will have been
;       marked to go into critical section state. The scheduler sets
;       InCritSec to indicate this has happened. If this has occurred
;       then we must clear the threads from this state.
;       All  threads in the  process that have  put  themselves into  the
;       "CritSec" state are put  into  the "Ready"  state.  Those threads
;       that  still   have  the  pending  forced-action   will  have   it
;       discarded.
;
;       If the scheduler was not called the threads will not have been
;       marked and we do not need to do anything to the other threads
;       in the process.
;
;
; Entry Point:  w_ExitCritSec
;       Linkage:  Call (near)
;
; Entry:
;       nothing
;
; Exit-Normal:
;       EAX = 0
;
; Exit-Error:
;       EAX = ERROR_CRITSEC_UNDERFLOW
;       EAX = ERROR_INVALID_THREADID
;
; Effects:
;       no registers preserved
;
; Internal References:
;       Routines:
;       none
;
; External References:
;       Routines:
;         _SCHSetState
;
; Pseudo Code:
;       Procedure w_ExitCritSec()
;       If we are in a critical section
;          If this is the original TCB
;            Decrement the process's critical section flag
;            If the count reached 0
;              Un-remember the original TCB by making ptda_pTCBCritSec zero
;              If critical section was seen by scheduler
;                Clear InCritSec to zero
;                For each thread in the active list
;                  If the TK_FF_CRITSEC flag is set
;                    Clear the TK_FF_CRITSEC flag
;                  Else
;                    Change the thread's state to ready (call _SCHSetState)
;                  Endif
;                EndFor
;              Endif
;            Endif
;            Flag no error
;          Else
;             Flag error
;          Endif
;       Else
;         Flag error
;       Endif
;       Return
;
;***********************************************************************

                FARCODE HIGH3
HIGH3CODE       SEGMENT
Procedure       w_ExitCritSec,<near,far16>
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING
        TaskTime

if RAS
;***DT  DosExitCritSec - Pre-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_PRE_DOSEXITCRITSEC>,
;               TP      = .DosExitCritSec_PreTrace,
;               TYPE    = (PRE,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosExitCritSec Pre-Invocation"

        public  DosExitCritSec_PreTrace
DosExitCritSec_PreTrace:

        MMPHPreDOSExitCritSec                   ; Performance Hook (10/06)

;       Maj/Min = Tracecode_Tasking shl 8 + TraceCode_PreExitCritSec,
;       Data = none
endif ;RAS

;       If the process is in a critical section, decrement ptda_cCritSec.
;       If it was decremented to zero, then clear ptda_pTCBCritSec, and
;       set all the threads in ptda_pTCBPriQCritSec to STATE_READY.  We
;       don't care about TK_FF_CRITSEC here.

        FlatContext <ds>,eax
        .if     <ss:[TKOPTDA.ptda_cCritSec] ne 0>
           mov     eax,ss:[TKOPTDA.ptda_pTCBCritSec]
ifdef MISCSTRICT
           .if     <eax eq [_pTCBCur]>
endif
              dec     ss:[TKOPTDA.ptda_cCritSec]
              .if     <z>
                xor     eax,eax                         ; NO_ERROR
                mov     ss:[TKOPTDA.ptda_pTCBCritSec],eax
                cmp     ss:[TKOPTDA.ptda_pTCBPriQCritSec],eax
                je      short xcs2                      ; nobody waiting - done

                ; We must have rescheduled while in CritSec, AND another
                ; thread in this process must have attempted to exit
                ; the kernel during that time.  Yield the CPU by setting
                ; RESCHED_CRITSLICE, because we know some other CritSec
                ; thread wants to run.  We round-robin between these
                ; threads via ptda_pTCBPriQCritSec.

                FlatContext <es>,ecx
                or      [_Resched],RESCHED_CRITSLICE     ; Critsec Timeslice
xcs0:           mov     ecx,ss:[TKOPTDA.ptda_pTCBPriQCritSec]
                jecxz   short xcs1
;                  CCALL32 _SCHSetState,<ecx,STATE_READY>
                mov     [ecx].TCBState,STATE_READY
                CCALL32 _TKUpdateState,<ecx>
                  jmp     short xcs0
xcs1:
              .endif
              xor             eax,eax                   ;Flag no error
ifdef MISCSTRICT
           .else
;              Panic <"ExitCritsec - Wrong thread">                  PB72788
            mov             eax,ERROR_INVALID_THREADID  ; Flag error PB727888
           .endif
endif
        .else
          mov             eax,ERROR_CRITSEC_UNDERFLOW   ;Flag error
        .endif
xcs2:

if RAS
;***DT  DosExitCritSec - Post-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_POST_DOSEXITCRITSEC>,
;               TP      = .DosExitCritSec_PostTrace,
;               TYPE    = (POST,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosExitCritSec Post-Invocation"

        public  DosExitCritSec_PostTrace
DosExitCritSec_PostTrace:

        MMPHPostDOSExitCritSec                  ; Performance Hook (10/86)

;       Maj/Min = Tracecode_Tasking shl 8 + TraceCode_PostExitCritSec,
;       Data = none
endif ;RAS

        RETC
EndProc w_ExitCritSec
HIGH3CODE       ENDS


BREAK   <w_ForceExitCritSec>
;***********************************************************************
;
; Subroutine Name:  _schForceExitCritSec
;
; Descriptive Name:  Forcibly exit critical section
;
; Function:
;       Re-enables thread switching for the current process.
;
; Notes:
;       _schForceExitCritSec forces the process to exit it's critical
;       section regardless of the critsec count.  It is called upon
;       process termination to wake up threads which may have been
;       in a critical section.  If no critical section is in force,
;       this routine does nothing.
;
; Entry Point:  _schForceExitCritSec
;       Linkage:  C Calling Convention (near)
;
; Entry:
;       nothing
;
; Exit-Normal:
;       nothing
;
; Exit-Error:
;       none
;
; Effects:
;       no registers preserved
;
; Internal References:
;      Routines:
;      w_ExitCritSec
;
; External References:
;      Routines:
;      none
;
; Pseudo Code:
;       Procedure _schForceExitCritSec()
;       If we are in a critical section
;         Set the critical section count to 1
;         Exit the critical section (call w_ExitCritSec)
;       Endif
;       Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schForceExitCritSec
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING
        TaskTime

;       If we are in a critical section, then pretend we are only
;       one level deep, and use w_ExitCritSec to do the work.

        .if         <ss:[TKOPTDA.ptda_cCritSec] ne 0>
          mov         eax,ss:[TKOPTDA.ptda_pTCBCritSec]
          .if         <eax eq [_pTCBCur]>
            mov         ss:[TKOPTDA.ptda_cCritSec],1
            CALL16      w_ExitCritSec           ; we will surely exit
          .endif
        .endif
        RETC
EndProc _schForceExitCritSec
HIGH32CODE      ENDS


BREAK   <w_GetPrty>
;***********************************************************************
;
; Subroutine Name:  w_GetPrty
;
; Descriptive Name:  Get priority
;
; Function:
;       This routine returns the base priority of a thread.
;
; Notes:
;       If  the scope  is "process",  the priority of the first thread of
;       the specified process is returned. If  the scope is "thread", the
;       priority  of  the  specified thread within the current process is
;       returned.
;
; Entry Point:  w_GetPrty
;       Linkage:  Call (near)
;
; Entry:
;       AX = ProcessID or ThreadID
;           0 => the requestor's process/thread is assummed
;       DX = Scope  (would like to make this CX some day)
;           SCOPE_PROCESS
;           SCOPE_THREAD
;
; Exit-Normal:
;       AX = 0
;       BX = priority       (would like to make this DX some day)
;           BL = level
;           BH = class
;               CLASS_IDLETIME
;               CLASS_REGULAR
;               CLASS_TIMECRITICAL
;               CLASS_SERVER
;
; Exit-Error:
;       AX = Error Code
;           ERROR_INVALID_PROCID
;           ERROR_INVALID_THREADID
;           ERROR_ZOMBIE_PROCESS
;           ERROR_INVALID_SCOPE
;
; Effects:
;       no registers preserved
;
; Internal References:
;              Routines:
;       _schMapTid
;
; External References:
;              Routines:
;       _TKPidToPTDA
;       _TKTidTo_iSlot
;
; Pseudo Code:
;       Procedure w_GetPrty(ID,Scope;Status,Priority)
;
;       If Scope is SCOPE_THREAD
;         Handle the magic number (call _schMapTid)
;         Set pPTDA = pPTDACur
;         Set temporary error code to NO_ERROR
;       Else If Scope is SCOPE_PROCESS
;         If (Pid == 0)
;            Set pPTDA = pPTDACur
;            Set temporary error code to NO_ERROR
;         Else
;            Map PID to pPTDA pointer (call _TKPidToPTDA)
;            Set temporary error code return code from _TKPidToPTDA
;         Endif
;         Set Tid = Thread 1
;       Else
;         Set temporary error code to ERROR_INVALID_SCOPE
;       EndIf
;
;       If (temporary error code == NO_ERROR)
;         Map Tid and pPTDA to Slot index (call _TKTidTo_iSlot)
;         Set temporary error code to return code from _TKTidTo_iSlot)
;         If (NO_ERROR from _TKTidTo_iSlot)
;           Get the thread's priority (call _TKGetPriority)
;           Set temporary error code to NO_ERROR
;         Endif
;       EndIf
;       Return (temporary error code)
;
;***********************************************************************

                FARCODE HIGH3
HIGH3CODE       SEGMENT
Procedure       w_GetPrty,HYBRID
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

;       PMONLY

        LocalVar pPTDA,DWORD
        LocalVar pTCB,DWORD

        EnterProc
        TaskTime

        FlatContext <ds,es>

if RAS
;***DT  DosGetPrty - Pre-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_PRE_DOSGETPRTY>,
;               TP      = .DosGetPrty_PreTrace,
;               TYPE    = (PRE,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosGetPrty Pre-Invocation"

        public  DosGetPrty_PreTrace
DosGetPrty_PreTrace:
endif ;RAS

        movzx   edx,dx                  ; (EDX) = Scope
        .if     <edx eq SCOPE_THREAD>   ; If thread scope,
          CCALL32 _schMapTid,<eax>      ; (EAX) = Pid
          mov     edx,[_pPTDACur]
          mov     [pPTDA],edx           ; Use current PTDA
          mov     ecx,eax               ; (ECX) = TID
          xor     eax,eax               ; NO_ERROR, so far

        .elseif <edx eq SCOPE_PROCESS>
          .if     <eax eq 0>            ; If current process
            mov     edx,[_pPTDACur]
            mov     [pPTDA],edx
            xor     eax,eax             ; NO_ERROR, so far
          .else                         ; not current process
            SSToDS  edx,[pPTDA]
            movzx   eax,ax
            CCALL32 _TKPidToPTDA,<eax,edx>
          .endif
          mov     ecx,1                 ; (ECX) = Thread 1
        .else
          mov     eax,ERROR_INVALID_SCOPE
        .endif

        or      eax,eax           ; if NO_ERROR from above,
        .if     <z>
          SSToDS  edx,pTCB
          CCALL32 _TKTidTo_pTCB,<[pPTDA], ecx, edx>
          or      eax,eax
          .if     <z>
            CCALL32 _TKGetPriority,<pTCB>
            mov     ebx,eax         ; bx = priority
            xor     eax,eax         ; NO_ERROR
          .endif
        .endif

if RAS
;***DT  DosGetPrty - Post-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_POST_DOSGETPRTY>,
;               TP      = .DosGetPrty_PostTrace,
;               TYPE    = (POST,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosGetPrty Post-Invocation"

        public  DosGetPrty_PostTrace
DosGetPrty_PostTrace:
endif ;RAS

        cmp     eax,1
        cmc                         ; return status in carry flag
        LeaveProc
        RETC
EndProc w_GetPrty
HIGH3CODE       ENDS


BREAK   <w_SetFgnd>
;***********************************************************************
;
; Subroutine Name:  w_SetFgnd
;
; Descriptive Name:  Set foreground
;
; Function:
;       This call allows one to designate which thread, process or screen
;       group is to receive favored dispatching by adding or removing priority
;       modifiers.
;
; Notes:
;       This call is NOT documented, and should only be used internally.
;
; Entry Point:  w_SetFgnd
;       Linkage:  Call (near)
;
; Entry:
;       AX = ProcessID, ThreadID, or ScreenGroupID
;           0 => the requestor's PID, TID or SGID is assumed
;       DX = Scope
;           0 => (SCOPE_PROCESS) all threads in the indicated process are given
;                a keyboard boost (KBD modifier).  This process is set to
;                be THE keyboard process, and the former keyboard process
;                loses its boost.
;           1 => (SCOPE_FAMILY) not used
;           2 => (SCOPE_THREAD) the specified thread is given an input boost
;                (WINDOW modifier).
;           3 => (SCOPE_SCREENGROUP) all threads in the indicated screen group
;                are given a foreground boost (FGND modifier).  This screen group
;                is set to be THE screen group, and the former screen group
;                loses its boost.
;           8 => (SCOPE_GIVEMSG) the specified thread (thread number) is given
;                an input boost (WINDOW modifier).
;           9 => (SCOPE_TAKEMSG) the specified thread (thread number) loses
;                its input boost (WINDOW modifier).
;          10 => (SCOPE_SLOTNUM) return slot number of the current thread
;
; Exit-Normal:
;       AX = 0
;       carry clear
;
; Exit-Error:
;       AX = Error Code
;           ERROR_INVALID_PROCID
;           ERROR_INVALID_SCOPE
;       carry set
;
; Effects:
;       no registers preserved
;
; Internal References:
;              Routines:
;       SetKbdLocus
;       SetScreenGroupFgnd
;       WindowBoost
;
; External References:
;              Routines:
;       none
;
; Pseudo Code:
;       Procedure w_SetFgnd(ID,Scope;Status)
;          Call appropriate subroutine based on scope parameter
;       Return
;
;***********************************************************************

                FARCODE HIGH3
HIGH3CODE       SEGMENT
Procedure       w_SetFgnd,<FARONLY,Far16>                       ;090391

        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:TASKAREA

;       PMONLY

        LocalVar iSlot,DWORD

        EnterProc
        TaskTime

        FlatContext     <ds,es>
        movzx   eax,ax                  ; (EAX) = TID, PID, SGID, or Slot
        movzx   edx,dx                  ; (EDX) = Scope
        .if <edx eq SCOPE_GIVEMSG> or
        .if <edx eq SCOPE_TAKEMSG>
            CCALL32 _schWindowBoost,<eax,edx>
        .elseif <edx eq SCOPE_PROCESS>
            CCALL32 _schSetKbdLocus,<eax>
        .elseif <edx eq SCOPE_SCREENGROUP>
            CCALL32 _schSetScreenGroupFgnd,<eax>
        .elseif <edx eq SCOPE_THREAD>
            CCALL32 _schMapPid,<eax>
            SSToDS  edx,iSlot
            CCALL32 _TKTidTo_iSlot,<[_pPTDACur], eax, edx>
            or      eax,eax
            .if     <z>
                mov     eax,iSlot
                CCALL32 _schWindowBoost,<iSlot,edx>
            .endif
        .elseif <edx eq SCOPE_SLOTNUM>
            mov     bx,ss:[TKOPTDA.CurrTCB]
            mov     ax,ss:[bx].TCBNumber ;this will look like an error
            movzx   eax,ax
        .else
            mov     eax,ERROR_INVALID_SCOPE
        .endif
        LeaveProc
        cmp     eax,1
        cmc                             ;indicate error for SCI
        RETP
EndProc w_SetFgnd
HIGH3CODE       ENDS


BREAK   <SetKbdLocus>
;***********************************************************************
;
; Subroutine Name:  SetKbdLocus
;
; Descriptive Name:  Set keyboard locus
;
; Function:
;       This call allows one to designate which process has the keyboard and
;       is to receive favored scheduling.
;
; Notes:
;       This call is provided to boost the priority  of  the process with
;       which the user is currently interacting.
;
; Entry Point:  SetKbdLocus
;       Linkage:  C Calling convention
;
; Entry:
;
;
; Exit-Normal:
;       AX = 0
;
; Exit-Error:
;       AX = Error Code
;           ERROR_INVALID_PROCID
;
; Effects:
;       no registers preserved
;
; Internal References:
;       Routines:
;       _schMapPid
;       _schSetThreadKbdLocus
;
; External References:
;       Routines:
;       _TKEachThread
;       _TKPidToPTDA
;
; Pseudo Code:
;       Procedure SetKbdLocus (PID;Status)
;       Handle the magic number (call _schMapPid)
;       Map PID to PTDA pointer (call PidToPtda)
;       If PID is not valid
;         Set return code to ERROR_INVALID_PROCID
;       Else
;         Swap PID and FgndPID
;         Map PID to PTDA pointer (call PidToPtda)
;         If the PID is valid
;           Set the foreground flag in the PTDA
;           For every thread in the process (call _TKEachThread)
;             Make the thread not foreground (call _schSetThreadKbdLocus)
;           EndFor
;         Endif
;         Set the foreground flag in the PTDA
;         For every thread in the process (call _TKEachThread)
;           Make the thread foreground (call _schSetThreadKbdLocus)
;         EndFor
;       EndIf
;       Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure _schSetKbdLocus
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar          pid,DWORD

        LocalVar        pPTDANew,DWORD
        LocalVar        pPTDAOld,DWORD

        EnterProc
        TaskTime

        CCALL32 _schMapPid,<pid>        ; (EAX) = Pid
        lea     edx,pPTDANew
        SSToDS  edx
        CCALL32 _TKPidToPTDA,<eax,edx>
        or      eax,eax
        .if     <z> near
          mov     eax,[pPTDANew]
          movzx   eax,[eax].ptda_Pid
          mov     fs,[_Sis2].is_sel     ;update infoseg copy
          mov     fs:SIS_FgndPID,ax
          mov     [_tkFgndPID],ax            ; Set fgnd PID global copy   26215
          xchg    SISData.SIS_FgndPID,ax;save new foreground PID
          or      ax,ax
          .if     <nz>

            ; remove the old foreground process

            lea     edx,pPTDAOld
            SSToDS  edx
            CCALL32 _TKPidToPTDA,<eax,edx>
            or      eax,eax
            .if     <z>
              mov     eax,pPTDAOld
              mov     [eax].Fgnd,0          ;clear Fgnd flag
              mov     [eax].ptda_infoseg.LIS_Fgnd,0
              cmp     eax,[_pPTDACur]
              .if     <eq>
                ; update infoseg copy for old process, if current
                mov     fs,[_Lis2].is_sel   ;update infoseg copy
                mov     fs:LIS_Fgnd,0
              .endif

              ; pull each thread of old process out of foreground

              CCALL32 _TKEachThread,\
                      <eax, <offset FLAT:_schSetThreadKbdLocus>, 0>
            .endif
          .endif

          ; establish the new foreground process

          mov     eax,pPTDANew
          mov     [eax].Fgnd,-1
          mov     [eax].ptda_infoseg.LIS_Fgnd,-1
          cmp     eax,[_pPTDACur]
          .if     <eq>
            ; update infoseg copy for new process, if current
            mov     fs,[_Lis2].is_sel ;update infoseg copy
            mov     fs:LIS_Fgnd,-1
          .endif

          ; put each thread of new process into foreground

          CCALL32 _TKEachThread,<eax,\
                                 <offset FLAT:_schSetThreadKbdLocus>,\
                                 0>
          xor     eax,eax               ; NO_ERROR
        .endif
        LeaveProc
        cmp     eax,1
        cmc                             ; return status in carry flag
        RETC
EndProc _schSetKbdLocus
HIGH32CODE      ENDS


BREAK   <_schSetThreadKbdLocus>
;***********************************************************************
;
; Subroutine Name:  _schSetThreadKbdLocus
;
; Descriptive Name:   Set the keyboard class modifier
;
; Function:
;     This routine sets the keyboard class modifier of the specified
;     thread.
;
; Notes:
;     If the specified thread is  the  runner  and it it being  removed
;     from the  foreground, or if the specified thread is  in the ready
;     state  and  it is being put in the  foreground and the  runner is
;     not time-critical, Resched will be set.
;
; Entry Point:  _schSetThreadKbdLocus
;     Linkage:  C calling convention (_TKEachThread worker)
;
; Entry:
;       pPTDA           Pointer to PTDA
;       pTCB            Pointer to TCB
;       pData           unused pointer
;
; Exit-Normal:
;     Resched = NZ (see notes)
;
; Exit-Error:
;     none
;
; Effects:
;     nothing
;
; Internal References:
;            Routines:
;
; External References:
;            Routines:
;     none
;
; Pseudo Code:
;     Procedure _SCHSetKbdLocus (pPTDA, pTCB, pData)
;     Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schSetThreadKbdLocus
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  pPTDA,DWORD
        ArgVar  pTCB,DWORD
        ArgVar  pData,DWORD

        EnterProc

        mov     eax,[pPTDA]
        cmp     [eax].Fgnd,0            ; Is process foreground?

        mov     eax,[pTCB]
        jne     short stkl1             ; yes - make it foreground.

        and     [eax].TCBPriClassMod,not CLASSMOD_KEYBOARD
        jmp     short stkl2

stkl1:  or      [eax].TCBPriClassMod,CLASSMOD_KEYBOARD
stkl2:  CCALL32 _TKUpdatePriority,<eax>
        xor     eax,eax
        LeaveProc
        RETC
EndProc _schSetThreadKbdLocus
HIGH32CODE      ENDS


BREAK   <_schSetScreenGroupFgnd>
;***********************************************************************
;
; Subroutine Name:  _schSetScreenGroupFgnd
;
; Descriptive Name:  Set the foreground screen group
;
; Function:
;       This call allows one to designate which screen group is foreground
;       and is to receive favored dispatching.
;
; Notes:
;       This call is provided to boost the priority of the screen group
;       which the user is currently interacting.
;
; Entry Point:  _schSetScreenGroupFgnd
;       Linkage:  C Calling Convention
;
; Entry:
;       SGIDNew = Screen Group
;
; Exit-Normal:
;       EAX = NO_ERROR
;
; Exit-Error:
;       EAX = Error Code
;           ERROR_SMG_INVALID_SGID
;
; Effects:
;
; Internal References:
;     Routines:
;       _schSetProcessFgnd
;
; External References:
;     Routines:
;       ScanTasks
;
; Pseudo Code:
;       Remove the current screen group from the foreground
;       Give the new screen group the foreground
;         (call _schSetProcessFgnd for each process via TKScanTasks)
;       Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schSetScreenGroupFgnd
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  SGIDNew,DWORD

        EnterProc
        mov     eax,[SGIDNew]
        .if     <ax ne [_FgndSGID]>
            ; set the old screen group to background

            movzx   ecx,[_FgndSGID]     ; ECX = old screen group id
            PUSHD   0                   ; *pValues = 0 (Make Background)
            mov     eax,esp
            SSToDS  eax                 ; pValues (on stack)
            CCALL32 _TKScanTasks,<<TK_TG_SCRN or TK_SF_WORKER>, ecx, \
                                  <offset FLAT:_schSetProcessFgnd>,eax>
            pop     ecx                 ; remove *pValues

            ; set the new screen group to foreground

            mov     ecx,[SGIDNew]
            mov     [_FgndSGID],cx      ; Set new foreground ID
            PUSHD   -1                  ; *pValues = -1 (Make Foreground)
            mov     eax,esp
            SSToDS  eax                 ; pValues (on stack)
            CCALL32 _TKScanTasks,<<TK_TG_SCRN or TK_SF_WORKER>, ecx, \
                                  <offset FLAT:_schSetProcessFgnd>,eax>
            pop     ecx                 ; remove *pValues
            .if     <eax eq ERROR_INVALID_SCREEN_GROUP>
                mov     eax,ERROR_SMG_INVALID_SGID
            .endif
        .else
            xor         eax,eax
        .endif
        LeaveProc
        RETC
EndProc _schSetScreenGroupFgnd

HIGH32CODE      ENDS


BREAK   <_schSetProcessFgnd>
;***********************************************************************
;
; Subroutine Name:  _schSetProcessFgnd
;
; Descriptive Name:  Set foreground process
;
; Function:
;     This call allows one to designate a process as foreground
;     and to receive favored dispatching.
;
; Notes:
;     This call is provided to boost the priority of the process
;     which the user is currently seeing.  It is meant to be called
;     by TKScanTasks.
;
; Entry Point:  _schSetProcessFgnd
;     Linkage:  C Calling Convention (TKScanTasks worker)
;
; Entry:
;     pPTDA     = PTDA pointer of process to operate on
;     pfFgnd    = Foreground indicator
;       0  => Leaving foreground
;       NZ => Entering foreground
;
; Exit-Normal:
;     none
;
; Exit-Error:
;     none
;
; Effects:
;     uses EAX, ECX, EDX
;
; Internal References:
;            Routines:
;
; External References:
;            Routines:
;     _TKEachThread
;     _schFgndBoost
;
; Pseudo Code:
;     If process is not detatched
;         Give or remove foreground boost to each thread in the process
;           (call _schFgndBoost for each thread via _TKEachThread)
;     Endif
;     Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schSetProcessFgnd
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  pPTDA,DWORD
        ArgVar  pfFgnd,DWORD

        EnterProc

        cmp     [SISData.SIS_Dynamic],0    ; Dynamic Variation Enabled?
        jz      short schexit              ; no - skip all this.

        mov     eax,[pPTDA]

        .if     <<Byte Ptr [eax].ptda_ProcType> ne PT_DETACHED>      ;090391
           .if     <<Byte Ptr [eax].ptda_ProcType> ne PT_VDM>          ;090391
              CCALL32 _TKEachThread,<eax, <offset FLAT:_schFgndBoost>, [pfFgnd]>
           .else
              CCALL32 _TKEachThread,<eax, <offset FLAT:_schFgndDiskIO>, [pfFgnd]>
           .endif
        .endif

schexit:
        xor     eax,eax
        LeaveProc
        RETC
EndProc _schSetProcessFgnd
HIGH32CODE      ENDS


BREAK   <_schFgndBoost>
;***********************************************************************
;
; Subroutine Name:  _schFgndBoost
;
; Descriptive Name:  Give thread a foreground boost
;
; Function:
;     This call allows one to designate a thread as foreground
;     to receive favored dispatching and disk I/O.
;
; Notes:
;     This call is provided to boost the priority of the process
;     which the user is currently seeing.  It is meant to be called
;     by EachTask.
;
; Entry Point:  _schFgndBoost
;     Linkage:  C Calling Convention (_TKEachThread worker)
;
; Entry:
;     pPTDA     = PTDA pointer of process to operate on
;     pTCB      = TCB pointer of thread to operate on
;     pfFgnd    = Foreground indicator
;       0  => Leaving foreground
;       NZ => Entering foreground
;
; Exit-Normal:
;     none
;
; Exit-Error:
;     none
;
; Effects:
;     uses EAX, ECX, EDX
;
; Internal References:
;            Routines:
;     none
;
; External References:
;            Routines:
;
; Pseudo Code:
;     Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schFgndBoost
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  pPTDA,DWORD
        ArgVar  pTCB,DWORD
        ArgVar  pfFgnd,DWORD

        EnterProc
;        cmp     [SISData.SIS_Dynamic],0 ; Dynamic Variation Enabled?
;        jz      short sfbx              ; no - skip all this.

        mov     eax,[pfFgnd]
        cmp     DWORD PTR [eax],0       ; Set into foreground?
        mov     eax,[pTCB]
        jne     short sfb1              ; yes - continue.

        and     [eax].TCBSpareFlags, not SPFLAGS_FGND_DISKIO
        and     [eax].TCBPriClassMod, not CLASSMOD_FOREGROUND  ; P728388
        jmp     short sfb2

sfb1:   or      [eax].TCBSpareFlags, SPFLAGS_FGND_DISKIO
        or      [eax].TCBPriClassMod, CLASSMOD_FOREGROUND      ; P728388
sfb2:   CCALL32 _TKUpdatePriority,<eax>
sfbx:   xor             eax,eax
        LeaveProc
        RETC
EndProc         _schFgndBoost
HIGH32CODE      ENDS

BREAK   <_schFgndIO>
;***********************************************************************
;
; Subroutine Name:  _schFgndDiskIO
;
; Descriptive Name:  Give an MVDM thread a foreground disk I/O boost
;
; Function:
;     This call allows one to designate a thread as foreground
;     to receive favored I/O dispatching.
;
; Notes:
;     This call is provided to boost the I/O priority of the process
;     which the user is currently seeing.  It is meant to be called
;     by EachTask.
;
; Entry Point:  _schFgndDiskIO
;     Linkage:  C Calling Convention (_TKEachThread worker)
;
; Entry:
;     pPTDA     = PTDA pointer of process to operate on
;     pTCB      = TCB pointer of thread to operate on
;     pfFgnd    = Foreground I/O indicator
;       0  => Leaving foreground
;       NZ => Entering foreground
;
; Exit-Normal:
;     none
;
; Exit-Error:
;     none
;
; Effects:
;     uses EAX, ECX, EDX
;
; Internal References:
;            Routines:
;     none
;
; External References:
;            Routines:
;
; Pseudo Code:
;     Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schFgndDiskIO
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  pPTDA,DWORD
        ArgVar  pTCB,DWORD
        ArgVar  pfFgnd,DWORD

        EnterProc
        cmp     [SISData.SIS_Dynamic],0 ; Dynamic Variation Enabled?
        jz      short sfdiox              ; no - skip all this.

        mov     eax,[pfFgnd]
        cmp     DWORD PTR [eax],0       ; Set into foreground?
        mov     eax,[pTCB]
        jne     short sfdio1            ; yes - continue.

        and     [eax].TCBSpareFlags, not SPFLAGS_FGND_DISKIO
        jmp     short sfdio2

sfdio1: or      [eax].TCBSpareFlags, SPFLAGS_FGND_DISKIO
sfdio2:
sfdiox: xor             eax,eax
        LeaveProc
        RETC
EndProc         _schFgndDiskIO
HIGH32CODE      ENDS


BREAK   <w_SetPrty>
;***********************************************************************
;
; Subroutine Name:  w_SetPrty
;
; Descriptive Name:  Set priority
;
; Function:
;     This routine sets the base priority of a thread or process.
;
; Notes:
;     If  the  scope  is "thread", only  the  priority of the specified
;     thread within  the current process is affected.  If the scope  is
;     "process",  the  priority of all threads of the specified process
;     are affected.  If  the scope is  "family",  the  priority  of all
;     threads  in  the  specified  process,  plus  all threads  in  the
;     decendants of the specified process are affected.
;
; Entry Point:  w_SetPrty
;     Linkage:  Call (near)
;
; Entry:
;     AX = ProcessID or ThreadID
;         0 => the requestor's process/thread is assummed
;     DX = Scope          (would like to change this to CX come day)
;         SCOPE_THREAD
;         SCOPE_PROCESS
;         SCOPE_FAMILY
;     BX = Priority       (would like to change this to DX some day)
;         BH = Class
;             CLASS_NOCHANGE
;             CLASS_IDLETIME
;             CLASS_REGULAR
;             CLASS_TIMECRITICAL
;             CLASS_SERVER
;         BL = Delta {-31..+31}
;             0 => no change
;
; Exit-Normal:
;     AX = 0
;
; Exit-Error:
;     AX = Error Code
;         ERROR_INVALID_PROCID
;         ERROR_INVALID_THREADID
;         ERROR_INVALID_PDELTA
;         ERROR_INVALID_PCLASS
;         ERROR_INVALID_SCOPE
;         ERROR_NOT_DESCENDANT
;
; Effects:
;     no registers preserved
;
; Internal References:
;            Routines:
;     _schMapPid
;     _schMapTid
;
; External References:
;            Routines:
;     EachTask
;     _TKEachThread
;     PidToPtda
;     TidToTn
;
; Pseudo Code:
;     Procedure w_SetPrty(Scope,NewClass,Delta,ID;Status)
;     If NewClass is not valid
;       Set return code to ERROR_INVALID_PCLASS
;     ElseIf Delta is not valid
;       Set return code to ERROR_INVALID_PDELTA
;     ElseIf Scope is SCOPE_THREAD
;       Set TID to ID
;       Handle the magic number (call _schMapTid)
;       Map TID to thread number (call _TKTidTo_iSlot)
;       If TID is valid
;         Set the thread's priority (call _SCHSlotSetPriority)
;       Endif
;     ElseIF Scope is SCOPE_PROCESS
;       Set PID to ID
;       Handle the magic number (call _schMapPid)
;       Map PID to PTDA pointer (call TKPidToPTDA)
;       If Pid is Valid
;         If process is not descendant (call TKDescendant)
;           Set return code to ERROR_NOT_DESCENDANT
;         Else
;           For every thread in the process (call _TKEachThread)
;             Set each thread's priority (call _schSetThreadPrty)
;           EndFor
;         Endif
;       Endif
;     ElseIF Scope is SCOPE_FAMILY
;       Set PID to ID
;       Handle the magic number (call _schMapPid)
;       Map PID to PTDA pointer (call TKPidToPTDA)
;       If PID is valid
;         If process is not descendant (call TKDescendant)
;           Set return code to ERROR_NOT_DESCENDANT
;         Else
;           For every process in the family (call _TKScanTasks)
;             Set each process's priority (call _schSetProcPrty)
;           EndFor
;         Endif
;       Endif
;     Else
;       Set return code to ERROR_INVALID_SCOPE
;     Endif
;     Return
;
;***********************************************************************

                FARCODE HIGH3
HIGH3CODE       SEGMENT
Procedure       w_SetPrty,HYBRID
        ASSUME  DS:NOTHING, ES:NOTHING, FS:NOTHING, GS:NOTHING, SS:NOTHING

        LocalVar        Prty,DWORD
        LocalVar        pPTDA,DWORD
        LocalVar        iSlot,DWORD

        FlatContext     <ds,es>,cx
        mov     cx,dx                   ; cx = scope
        movzx   edx,bx                  ; edx = priority
        EnterProc <edx>                 ; save priority
        TaskTime

if RAS
;***DT  DosSetPrty - Pre-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_PRE_DOSSETPRTY>,
;               TP      = .DosSetPrty_PreTrace,
;               TYPE    = (PRE,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosSetPrty Pre-Invocation",
;               REGS    = (CX,DX,AX),
;               FMT     = "Scope=<FMT_WORD>  Priority Delta= <FMT_BYTE>",
;               FMT     = "Class=<FMT_BYTE>  Process/Thread ID=<FMT_WORD>"

        public  DosSetPrty_PreTrace
DosSetPrty_PreTrace:

;       MMIOPH Performance Hook Removed
;       Maj/Min = Tracecode_Tasking shl 8 + TraceCode_PreSetPrty,
;       Data = cx, dx, ax (Scope, priority class/delta, ID)
endif ;RAS

        .if     <dh ne CLASS_NOCHANGE> and      ; validate class
        .if     <dh ne CLASS_TIME_CRITICAL> and
        .if     <dh ne CLASS_REGULAR> and
        .if     <dh ne CLASS_SERVER> and
        .if     <dh ne CLASS_IDLE_TIME>
          mov     ax,ERROR_INVALID_PCLASS
        .elseif <dl gt DELTA_MAX> or            ; validate delta
        .if     <dl lt DELTA_MIN>
          mov     ax,ERROR_INVALID_PDELTA
        .elseif <cx eq SCOPE_THREAD>

          ; set the thread's priority

          CCALL32 _schMapTid,<eax>              ; (EAX) = Tid
          SaveReg <edx>
          SSToDS  edx,iSlot
          CCALL32 _TKTidTo_iSlot,<[_pPTDACur], eax, edx>
          RestoreReg <edx>
          or      eax,eax
          .if     <z>
            CCALL32 _SCHSlotSetPriority, <iSlot, edx>
            xor     eax,eax
          .endif
        .elseif <cx eq SCOPE_PROCESS>

          ; set the process' priority

          CCALL32 _schMapPid,<eax>              ; (EAX) = Pid
          SSToDS  edx,pPTDA
          CCALL32 _TKPidToPTDA,<eax,edx>
          or      eax,eax
          .if     <z>
            mov     eax,[pPTDA]
            movzx   eax,[eax].ptda_Pid
            CCALL32 _TKDescendant,eax
            or      eax,eax
            .if     <z>
              SaveAlignESP
              lea     ecx,[Prty]
              SSToDS  ecx
              PushP   ecx
              PushP   <offset FLAT:_schSetThreadPrty>
              PushP   pPTDA
              CCALL32 _TKEachThread,,,PushP
              pop     esp
              xor     eax,eax
            .endif
          .endif
        .elseif         <cx eq SCOPE_FAMILY>

          ; set the family's priority

          CCALL32 _schMapPid,<eax>
          lea     ecx,[Prty]
          SSToDS  ecx
          CCALL32 _TKScanTasks,<<TK_TG_CSUB or TK_SF_WORKER>, eax, \
                                <offset FLAT:_schSetProcPrty>, ecx>
        .else
          mov     eax,ERROR_INVALID_SCOPE
        .endif

        or      eax,eax         ; if NO_ERROR
        .if     <z>
          CCALL32 _TKGetPriority,<_pTCBCur>
          mov     ss:[TKOPTDA].ptda_infoseg.LIS_CurThrdPri,ax
          mov     fs,es:[_Lis2].is_sel ;update infoseg copy
          mov     fs:LIS_CurThrdPri,ax
          xor     eax,eax           ;and return with no error
        .endif

if RAS
;***DT  DosSetPrty - Post-Invocation Dynamic Trace
;
;       TRACE   MINOR   = <RAS_POST_DOSSETPRTY>,
;               TP      = .DosSetPrty_PostTrace,
;               TYPE    = (POST,API),
;               GROUP   = TSK,
;               DESC    = "(OS) DosSetPrty Post-Invocation",
;               <LOG_C_RETVAL>,
;               FMT     = "Return Code = <FMT_C_RETVAL>"

        public  DosSetPrty_PostTrace
DosSetPrty_PostTrace:

;       MMIOPH Performance Hook Removed
;       Maj/Min = Tracecode_Tasking shl 8 + TraceCode_PostSetPrty,
;       Data = none
endif ;RAS

        cmp     eax,1                   ; return status in carry flag
        cmc
        LeaveProc
        RETC
EndProc w_SetPrty
HIGH3CODE       ENDS


BREAK   <_SetProcPrty>
;***********************************************************************
;
; Subroutine Name:  _SetProcPrty
;
; Descriptive Name:  Set priority on all threads of a process
;
; Function:
;     This routine sets the base priority of a thread
;
; Notes:
;     _schSetProcPrty is a worker routine called from _TKEachThread.
;
; Entry Point:  _schSetProcPrty
;     Linkage:  C Calling Convention
;
; Entry:
;       pPTDA   PTDA pointer
;       pTCB    TCB pointer
;       pPrty   Pointer to (DWORD) Priority
;
; Exit-Normal:
;     AX = 0
;
; Exit-Error:
;     none
;
; Effects:
;     uses eax, ecx, edx
;
; Internal References:
;            Routines:
;     SetPriority
;
; External References:
;            Routines:
;       none
;
; Pseudo Code:
;     Procedure _schSetProcPrty (pPTDA, pPrty)
;       _TKEachThread (pPTDA, _schSetThreadPrty, pPrty)
;     Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schSetProcPrty
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  pPTDA,DWORD
        ArgVar  pValues,DWORD

        EnterProc
        CCALL32 _TKEachThread,<pPTDA, <offset FLAT:_schSetThreadPrty>, pValues>
        xor     eax,eax
        LeaveProc
        RETC
EndProc _schSetProcPrty
HIGH32CODE      ENDS


BREAK   <_SetThreadPrty>
;***********************************************************************
;
; Subroutine Name:  _schSetThreadPrty
;
; Descriptive Name:  Set priority on a thread
;
; Function:
;     This routine sets the base priority of a thread
;
; Notes:
;     _schSetThreadPrty is a worker routine called from _TKEachThread.
;
; Entry Point:  _schSetThreadPrty
;     Linkage:  C Calling Convention
;
; Entry:
;       pPTDA   PTDA pointer
;       pTCB    TCB pointer
;       pPrty   Pointer to (DWORD) Priority
;
; Exit-Normal:
;     AX = 0
;
; Exit-Error:
;     none
;
; Effects:
;     uses eax, ecx, edx
;
; Internal References:
;            Routines:
;     SetPriority
;
; External References:
;            Routines:
;       none
;
; Pseudo Code:
;     Procedure _SetThreadPrty (pPTDA, pTCB, pPrty)
;       call SetPriority (pTCB-> TCBNumber, *pPrty)
;     Return
;
;***********************************************************************

                FARCODE HIGH32
HIGH32CODE      SEGMENT
Procedure       _schSetThreadPrty
        ASSUME  DS:FLAT, ES:FLAT, FS:NOTHING, GS:NOTHING, SS:NOTHING

        ArgVar  pPTDA,DWORD
        ArgVar  pTCB,DWORD
        ArgVar  pPrty,DWORD

        EnterProc
        mov     eax,[pTCB]
        movzx   eax,[eax].TCBNumber      ; (EAX) = Slot
        mov     ecx,[pPrty]
        movzx   ecx,WORD PTR [ecx]      ; (ECX) = *pPrty
        CCALL32 _SCHSlotSetPriority,<eax,ecx>
        xor     eax,eax
        LeaveProc
        RETC
EndProc _schSetThreadPrty
HIGH32CODE      ENDS

                end
