windows-nt/Source/XPSP1/NT/base/mvdm/wow16/kernel31/schedule.asm
2020-09-26 16:20:57 +08:00

675 lines
14 KiB
NASM

title SCHEDULE - task scheduler
.xlist
include kernel.inc
include tdb.inc
include eems.inc
include newexe.inc
.list
if PMODE32
.386
endif
externFP WriteOutProfiles
externFP GlobalCompact
externFP GetFreeSpace
;if KDEBUG
;externFP OutputDebugString
;endif
DataBegin
externB Kernel_InDOS
externB Kernel_flags
externB InScheduler
externB fProfileDirty
externB fProfileMaybeStale
externB fPokeAtSegments
externW WinFlags
;externW EMSCurPID
;externW cur_drive_owner
externW curTDB
externW Win_PDB
externW LockTDB
externW headTDB
externW hShell
externW pGlobalHeap
externW hExeHead
externW f8087
externW
if PMODE32
externW PagingFlags
externD pDisplayCritSec
endif
externD pIsUserIdle
if KDEBUG
externB fPreloadSeg
endif
staticW PokeCount,0
DataEnd
sBegin CODE
assumes cs,CODE
assumes ds,NOTHING
assumes es,NOTHING
externNP LoadSegment
externNP DeleteTask
externNP InsertTask
if PMODE32
externNP DiscardFreeBlocks
externNP ShrinkHeap
endif
if SDEBUG
externNP DebugSwitchOut
externNP DebugSwitchIn
endif
;-----------------------------------------------------------------------;
; Reschedule ;
; ;
; This routine does the task switching. ;
; ;
; Arguments: ;
; none ;
; Returns: ;
; nothing ;
; Error Returns: ;
; nothnig ;
; Registers Preserved: ;
; AX,BX,CX,DX,DI,SI,BP,DS,ES ;
; Registers Destroyed: ;
; none ;
; Calls: ;
; DeleteTask ;
; InsertTask ;
; SaveState ;
; ;
; History: ;
; ;
; Mon 07-Aug-1989 21:53:42 -by- David N. Weise [davidw] ;
; Removed the WinOldApp support and DEC rainbow support. ;
; ;
; Fri 07-Apr-1989 22:16:02 -by- David N. Weise [davidw] ;
; Added support for task ExeHeaders above The Line in Large ;
; Frame EMS. ;
; ;
; Sat Aug 15, 1987 11:41:35p -by- David N. Weise [davidw] ;
; Commented out the cli and sti around the swapping of states. ;
; Sweet Lord, what will this break? ;
; ;
; Fri Feb 06, 1987 00:09:20a -by- David N. Weise [davidw] ;
; Put in support for DirectedYield. ;
; ;
; Tue Feb 03, 1987 08:21:53p -by- David N. Weise [davidw] ;
; Got rid of going inside of DOS for InDOS and ErrorMode. Task ;
; switching should be much better under Windows386 now. ;
; ;
; Mon Sep 29, 1986 05:27:29p -by- Charles Whitmer [chuckwh] ;
; Made it recognize threads. It now does a fast context switch if ;
; just switching between two threads in the same process. ;
; ;
; Mon Sep 29, 1986 05:24:16p -by- Charles Whitmer [chuckwh] ;
; Documented it. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc Reschedule,<PUBLIC,FAR>
cBegin nogen
; get all the registers up on the stack
inc bp
push bp
mov bp,sp
push ds
push si
push di
push ax
push cx
push es
push bx
push dx
public BootSchedule
BootSchedule:
call TaskSwitchProfileUpdate ;Update profile information
public ExitSchedule
ExitSchedule:
; see if we're supposed to do a directed yield
SetKernelDS es
mov cx,curTDB
jcxz search_the_queue ; this happens first after boot time!
mov ds,cx
cmp ds:[TDB_sig],TDB_SIGNATURE
jnz short search_the_queue ; task may have suicided
xor cx,cx
xchg ds:[TDB_Yield_to],cx
jcxz search_the_queue ; nope
mov ds,cx
cmp ds:[TDB_nevents],0 ; anything for this guy?
jnz found_one
; run down the task queue looking for someone with events
search_the_queue:
CheckKernelDS es
mov ax,HeadTDB
keep_searching:
or ax,ax ; Anyone to schedule?
jnz short try_this_one ; Yes, go do it
; if no one is dispatchable, do an idle interrupt
if PMODE32
xor PagingFlags, 4
test PagingFlags, 4
jnz short NoDiscarding ; Every other time through!
test PagingFlags, 8 ; An app has exited?
jz short NoShrink
push es
call ShrinkHeap
pop es
NoShrink:
;;; or PagingFlags, 2 ; Causes early exit from GlobalCompact
;;; mov ax, -1
;;; push es
;;; cCall GlobalCompact,<ax,ax>
;;; pop es
;;; and PagingFlags, not 2
test byte ptr WinFlags[1], WF1_PAGING
jz short NoDiscarding
test PagingFlags, 1
jz short NoDiscarding
call DiscardFreeBlocks
jmps search_the_queue
NoDiscarding:
endif
mov ax, 1 ; Assume User is idle
cmp word ptr pIsUserIdle[2], 0
je short go_idle
call pIsUserIdle
SetKernelDS es
go_idle:
cmp fPokeAtSegments, 0 ; Disabled?
je short @F ; yep, skip
or ax, ax ; Only if USER is idle
jz short @F
inc PokeCount
test PokeCount, 1Fh ; Only every 32 times through
jnz short @F
call PokeAtSegments
jc search_the_queue
@@:
push ax ; Ralph's paranoia
int 28h ; No, generate DOS idle int
pop ax
xor bx, bx
or ax, ax
jnz short tell_ralph
or bl, 1
tell_ralph:
mov ax,1689h ; Do an idle to Win386.
int 2fh
jmp search_the_queue
get_out_fast:
jmp reschedule_done
; see if the given task has events
try_this_one:
mov ds,ax
mov ax,ds:[TDB_next]
cmp ds:[TDB_nevents],0 ; anything for this guy?
jz keep_searching
; is this the guy we're already running?
found_one:
mov di,ds ; DI = handle of new task
cmp di,curTDB
jz short get_out_fast
; is there a locked task?
mov cx,LockTDB ; are any tasks super priority?
jcxz no_locked_task
cmp cx,di ; are we it?
jnz short get_out_fast ; No => don't switch
no_locked_task:
; don't switch if in DOS or int 24 handler
cmp Kernel_InDOS,0 ; if inside INT2[0,4] handler
jnz keep_searching ; ...don't reschedule
inc InScheduler ; set flag for INT 24...
inc ds:[TDB_priority] ; lower task priority
push es
UnSetKernelDS es
cCall DeleteTask,<ds> ; remove him from queue
cCall InsertTask,<ds> ; put him back further down
dec ds:[TDB_priority] ; restore former priority
pop es
ReSetKernelDS es
; Around saving state and restoring state go critical on memory
; heap access because of EMS.
push es
mov es,pGlobalHeap
UnSetKernelDS es
inc es:[gi_lrulock]
pop es
ReSetKernelDS es
; Signature is trashed when we suicide so we dont save state
; for the non-existant task.
mov di,ds ; DI = destination task
xor si,si ; SI is an argument to RestoreState
mov es,curTDB ; ES = current TDB
UnSetKernelDS es
mov ax,es
or ax,ax
jz short dont_save_stack
cmp es:[TDB_sig],TDB_SIGNATURE
jnz short dont_save_stack
mov si,es ; SI = current task
; save the present stack
mov es:[TDB_taskSS],ss
mov es:[TDB_taskSP],sp
dont_save_stack:
; get onto a temporary stack while we switch the EEMS memory
mov ax,es
or ax,ax
jz short dont_save_state
cmp es:[TDB_sig],TDB_SIGNATURE
jnz short dont_save_state
cCall SaveState,<si>
push ds
mov ds,ax
if SDEBUG
call DebugSwitchOut
endif
pop ds
dont_save_state:
SetKernelDS es
mov curTDB,di
mov ax, ds:[TDB_PDB] ; Set our idea of the PDB
mov Win_PDB, ax
;;;mov ax,ds:[TDB_EMSPID]
;;;mov EMSCurPID,ax
cmp f8087, 0
je short no_fldcw
.8087
fnclex
fldcw ds:[TDB_FCW]
no_fldcw:
or Kernel_flags,kf_restore_CtrlC OR kf_restore_disk
if SDEBUG
call DebugSwitchIn
endif
fast_switch:
mov cx,ds:[TDB_taskSS] ; Switch to new task stack.
mov ax,ds:[TDB_taskSP]
mov ss,cx
mov sp,ax
mov curTDB,di
dec InScheduler ; reset flag for INT 24
if PMODE32
mov al,Kernel_Flags[2]
and Kernel_Flags[2],NOT KF2_WIN386CRAZINESS
; Tell the display driver to speak its mind. added 20 feb 1990
test al,KF2_WIN386CRAZINESS
jz short @F
xor ax,ax
push es ; preserve es
cCall pDisplayCritSec,<ax>
pop es
@@:
endif
; Around saving state and restoring state go critical on memory
; arena access because of EMS.
mov es,pGlobalHeap
UnSetKernelDS es
dec es:[gi_lrulock]
; pop the task's registers off the stack
reschedule_done:
pop dx
pop bx
pop es
pop cx
pop ax
pop di
pop si
pop ds
pop bp
dec bp
public dispatch
dispatch:
ret
cEnd nogen
;-----------------------------------------------------------------------;
; LockCurrentTask ;
; ;
; Hack procedure to make the current task god if the passed boolean ;
; is true. ;
; If false, then demotes the current god to a mere mortal. Self ;
; inflicted by definition. ;
; ;
; DavidDS: Note, the USER function, LockMyTask should be called for ;
; Windows apps instead of this if you expect the input queue to work ;
; properly. ;
; ;
; Arguments: ;
; ParmW lock ; ;
; Returns: ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; CX,DX,DI,SI,DS,ES ;
; ;
; Registers Destroyed: ;
; AX,BX ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Sun Jan 04, 1987 04:37:11p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc LockCurrentTask,<PUBLIC,FAR>
; ParmW lock
cBegin nogen ; Crock to save space
mov bx,sp
mov ax,ss:[bx][4] ; get the argument
push ds
SetKernelDS
or ax,ax
jz short lct1
mov ax,curTDB
lct1:
mov LockTDB,ax
pop ds
UnSetKernelDS
ret 2
cEnd nogen
;-----------------------------------------------------------------------;
; IsTaskLocked ;
; ;
; Another hack procedure to determine if the current task is locked. ;
; A non-NULL value is returned if the task is locked and NULL is ;
; returned is the task is not locked. ;
; ;
; Arguments: ;
; ; ;
; Returns: ;
; The value of LockTDB ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; All but AX ;
; ;
; Registers Destroyed: ;
; AX ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; (Tue 20-Oct-1987 : bobgu) Created this thing. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc IsTaskLocked,<PUBLIC,FAR>
cBegin nogen
push ds
SetKernelDS
mov ax,LockTDB
pop ds
UnSetKernelDS
ret
cEnd nogen
;-----------------------------------------------------------------------;
; SaveState ;
; ;
; Saves the state of the current MS-DOS process. This means the per ;
; task interrupt vectors, the drive and directory, EEMS land if any, ;
; and old app stuff if any. ;
; ;
; Arguments: ;
; parmW destination ;
; ;
; Returns: ;
; DS returned in AX. ;
; ;
; Error Returns: ;
; ;
; Registers Preserved: ;
; ;
; Registers Destroyed: ;
; ;
; Calls: ;
; ;
; History: ;
; ;
; Mon 07-Aug-1989 21:53:42 -by- David N. Weise [davidw] ;
; Removed the WinOldApp support. ;
; ;
; Tue Feb 03, 1987 08:21:53p -by- David N. Weise [davidw] ;
; Got rid of the rest of the DOS version dependencies. ;
; ;
; Thu Jan 22, 1987 03:15:15a -by- David N. Weise [davidw] ;
; Took out the saving of the ^C state, DTA address, and ErrorMode. ;
; ;
; Sun Jan 04, 1987 04:40:44p -by- David N. Weise [davidw] ;
; Added this nifty comment block. ;
;-----------------------------------------------------------------------;
assumes ds, nothing
assumes es, nothing
cProc SaveState,<PUBLIC,NEAR>,<si,di,ds>
parmW destination
cBegin
cld
SetKernelDS
mov ax,f8087
UnSetKernelDS
mov ds,destination
or ax,ax
jz short no_fstcw
.8087
fstcw ds:[TDB_FCW]
no_fstcw:
test ds:[TDB_Drive],10000000b; if hi bit set....
jnz short ss_ret ; ...no need to get dir
mov ah,19h
int 21h
mov dl,al
inc dl
or al,10000000b
mov ds:[TDB_Drive],al ; save it (A=0, B=1, etc.)
mov si,TDB_Directory
mov byte ptr [si],'\' ; set "\"
inc si
mov ah,47h ; get current directory...
int 21h
jnc short ss_ret
mov byte ptr [si-1],0 ; indicate error with null byte
ss_ret: mov ax,ds
cEnd
cProc TaskSwitchProfileUpdate,<PUBLIC,NEAR>
cBegin
SetKernelDS es
;** See if we need to write out the profile string cache. We
;** do this at task switch time.
cmp es:fProfileDirty, 0
je short PU_NoFlushProfiles
push es
call WriteOutProfiles
pop es
PU_NoFlushProfiles:
;** Set the flag saying that the profile cache MAY be invalid.
;** If a task switch occurs, on the next Get/SetProfileXXX() we
;** will have to see if the file has been modified by this
;** (or any other) task
mov es:fProfileMaybeStale,1
cEnd
assumes ds, nothing
assumes es, nothing
if PMODE32
.386
else
.286
endif
cProc PokeAtSegments,<PUBLIC,NEAR>
cBegin
push ds
push es
pusha
cCall GetFreeSpace,<2> ; Ignore discardable
or dx, dx ; Insist on > 64k free
if KDEBUG
jz never_again
else
jz short never_again
endif
if PMODE32
SetKernelDS
test WinFlags[1], WF1_PAGING
jz short have_room
sub sp, 30h ; Room for info
smov es, ss
mov di, sp
mov ax, 0500h ; Get Paging Info
int 31h
mov eax, es:[di][14h] ; Free pages
add sp, 30h
cmp eax, 16 ; Insist on 64k
jb short never_again
have_room:
smov es, ds
ResetKernelDS es
else
SetKernelDS es
endif
mov ds, hExehead
UnsetKernelDS
next_exe:
mov cx, ds:[ne_cseg] ; Module has segments?
jcxz no_segs ; no, on to next module
mov di, 1 ; Segment number
mov si, ds:[ne_segtab] ; Pointer to segment table
next_seg:
test ds:[si].ns_flags, NSLOADED ; This segment in memory?
jnz short seg_here ; yes, look at next one
test ds:[si].ns_flags, NSDISCARD ; Only load if discardable
jz short seg_here ; Skip this one
if KDEBUG
push ds
SetKernelDS
mov fPreloadSeg, 1
pop ds
UnsetKernelDS
endif
cCall LoadSegment,<ds,di,-1,-1>
if KDEBUG
push ds
SetKernelDS
mov fPreloadSeg, 0
pop ds
UnsetKernelDS
endif
stc ; We loaded something!
jmps all_done
seg_here:
lea si, [si + size NEW_SEG1] ; On to next segment
inc di
loop next_seg ; looked at all in this module?
no_segs:
mov cx, ds:[ne_pnextexe] ; On to next module
jcxz all_done ; End of list?
mov ax, ds
mov ds, cx
cmp ax, hShell ; Only boot time modules
jne short next_exe
UnSetKernelDS es
never_again:
SetKernelDS
mov fPokeAtSegments, 0 ; That's all folks
clc
all_done:
popa
pop es
pop ds
cEnd
sEnd CODE
end