        SCCSID equ "@(#)smsfta.asm      6.8 92/03/26"

;        IBM/Microsoft Confidential
;
;        Copyright (c) IBM Corporation 1987, 1989
;        Copyright (c) Microsoft Corporation 1987, 1989
;
;        All Rights Reserved

.xlist
include dosseg.inc
include basemaca.inc
include fnomem.inc
include osmaca.inc
include osconst.inc
include mi.inc
include error.inc
include tkexport.inc
include pgexport.inc
include vmexport.inc
include harderr.inc
include basemid.inc
include smexport.inc
.list

        CpuMode 386
        ModName smsfta, FNO_SMSFTA_ASM

        extrn   _TKSleep:near
        extrn   _TKWakeup:near
        extrn   _TKDeclareInversion:near
        extrn   _TKExitInversion:near

        ReferFlat       _pTCBCur,dword
        ReferFlat       _smSFTmap,dword
        ReferGlobal     fNWDEnabled, byte

        EXTRN16 HardError
        EXTRN16 NWDDisableWatchdogNMI
        EXTRN16 OutMessage

DATA    segment
; Moved to sdata.asm for System Anchor Block - f122427
        extrn   _SMswapping:word
DATA    ends

_DATA   segment
; Moved to sdata.asm for System Anchor Block - f122427
        extrn  _smSFTOwner:word
ifdef MEMSTAT
        public _smcSFTAlloc             ; tot # of SFTs alloc'ed
_smcSFTAlloc    dd      0
        public _smcSFTAllocBlock        ; tot # of times we blocked
_smcSFTAllocBlock       dd      0
endif
_DATA   ends

DATA segment
; Moved to sdata.asm for System Anchor Block - f122427
        extrn   _SMCFGMinFree:dword
        extrn   _SMCommit:byte
        public  _SMCFGSwapSize
_SMCFGSwapSize dd       0
DATA ends


        FARCODE HIGH32
_TEXT   segment
        assume ds:nothing, es:nothing, ss:nothing, fs:nothing, gs:nothing

;***LP  _smAllocSFT     - allocate a SFT from the swappers pool
;
;       This very simple routine examines a tiny bitmap to find the
;       first unused swapper SFT, and returns the index of the SFT.
;       If there are no free SFTs, we block and try again later.
;       If this is the case, then all the SFTs are in use by other
;       threads doing swapping.  We know that none of these threads
;       will need another SFT to complete, so there is no danger of
;       deadlock.
;
;       - find first free SFT
;
;       - update SFT bitmap
;
;       - if no free SFTs, block and loop back to try again
;
;       ENTRY   pIndex = addr of location to store SFT index
;       EXIT    (EAX) = error code
;                       NO_ERROR
;                       ERROR_INTERRUPT
;               [pIndex] = index of allocated SFT in swapper SFT table
;
;       WARNINGS        can block
;
;   top:
;       eax = index of first set bit in smSFTmap = index of first free SFT
;       if no bits were set, goto wait
;       store SFT index through parameter pointer
;       clear the bit
;       return NO_ERROR
;
;   wait:
;       ProcBlock(interruptible, &smSFTmap)
;       if (normal wakeup)
;               goto top
;       else
;               return(ERROR_INTERRUPT)
;
Procedure _smAllocSFT, near
        assume ds:FLAT, es:nothing, ss:nothing, fs:nothing, gs:nothing
        ArgVar  pIndex,DWORD
        EnterProc

sas10:  bsf     eax,[_smSFTmap]         ; (eax) = index of first set bit
        jz      short sas20             ; jump if no SFTs available

        btr     [_smSFTmap],eax         ; mark the SFT as allocated
        mov     ecx,[pIndex]            ; get pointer to SFT index variable
        mov     [ecx],eax               ; store the SFT index
ifdef MEMSTAT
        inc     [_smcSFTAlloc]
endif
        mov     edx,[_pTCBCur]
        mov     cx,[edx].TCBNumber
        mov     [_smSFTOwner + eax*2],cx
        inc     [edx].TCBcBoostLock     ; TKEnterInversion();
        xor     eax,eax                 ; set return code to no error
.ERRNZ NO_ERROR
sasx:
        LeaveProc
        RETC

;       Declare a priority inversion on all the owning threads.

sas20:  push    edi
        mov     edi,MAXSIMULSWAP-1

sas21:  movzx   eax,[_smSFTOwner + edi*2]
        CCall   _TKDeclareInversion, <eax>
        dec     edi
        jnz     sas21
        pop     edi

        CCall   _TKSleep, <offset FLAT:_smSFTmap, -1, 0, 0>
                                        ; never timeout, interruptible,
                                        ; multi-wakeup
ifdef MEMSTAT
        inc     [_smcSFTAllocBlock]
endif
        or      eax,eax
        jz      sas10                   ; if it was a normal wakeup, try again

        jmp     sasx                    ; we got a weird wakeup, so return
                                        ; the error
EndProc _smAllocSFT

;***LP  _smHardError
;
;     - smHardError cause a harderror to be displayed if the swap file
;       cannot be extended (out of disk space).
;
;       ENTRY   NONE
;
;       EXIT    NONE
;
;       USES            EAX, ECX, EDX, EFlags
;
;
Procedure _smHardError,near
        ASSUME DS:FLAT,ES:FLAT,SS:NOTHING

        SaveReg <esi,edi,ebx,es,ds>

        mov     dx,1477                 ; dx = message number
        mov     cx,0                    ; cx = number of replacement strings
                                        ; ds:[esi]->replacement strings
        mov     ax,SM_HE_TYPE           ; message
        mov     edi,_pTCBCur
        mov     [edi].TCBAllowed,SM_ALLOWED_FLAGS
;       mov     [edi].TCBAllowed,ALLOWED_ABORT or ALLOWED_IGNORE
        CALL16  HardError

        mov     edi,_pTCBCur
        mov     [edi].TCBFailErr,0
        RestoreReg <ds,es,ebx,edi,esi>
        RETC
EndProc _smHardError

;***LP  _SMPrintFaultMsg
;
;     - SMFatalFault cause a system fatal fault and a message to be
;       displayed when there is no more disk space left for swap file
;       allocation and the entire swapfile is in use.
;
;       ENTRY   NONE
;
;       EXIT    Does not return
;
;       USES            EAX, ECX, EDX, EFlags
;
;
Procedure _SMPrintFatalMsg,near
        ASSUME DS:FLAT,ES:FLAT,SS:NOTHING

IFDEF   SMSTRICT
        Panic   <"SystemFatalFault: insufficient swap space">
ENDIF

        CALL16  NWDDisableWatchdogNMI   ; disable watchdog nmi
        mov     fNWDEnabled,FALSE       ; make it permanent

        sub     ebx,ebx
        mov     eax,MSG_SWAP_FILE_FULL
        CALL16  OutMessage              ; print swapper error message


        hlt                             ; halt the processor
;       spin forever
pfm00:
        jmp  pfm00

EndProc _SMPrintFatalMsg

;***LP  _smFreeSFT      - return an SFT to the swapper's pool
;
;       This routine returns an SFT to the swapper's pool, and
;       runs ayone blocked waiting for an SFT.
;
;       - wack bit in SFT bitmap
;
;       - restart anyone blocked waiting for a swapper SFT
;
;       ENTRY   Index = index of SFT to return to pool
;       EXIT    none
;
;       set bit in smSFTmap
;       ProcRun(&smSFTmap)
;
Procedure _smFreeSFT, near
        assume ds:FLAT, es:nothing, ss:nothing, fs:nothing, gs:nothing
        ArgVar  Index,DWORD

        EnterProc
        mov     eax,[Index]
        bts     [_smSFTmap],eax
ifdef SMSTRICT
        jnc     sfs20
        Panic   "SwapFreeSFT: SFT already free"
endif
sfs20:  mov     [_smSFTOwner + eax*2],0
        CCall   _TKExitInversion
        CCall   _TKWakeup,<offset FLAT:_smSFTmap, 0, 0>
        LeaveProc
        RETC
EndProc _smFreeSFT

_TEXT   ends

        end
