;       SCCSID = @(#)tkwksem.asm	6.3 91/06/13
SCCSID  equ     "@(#)tkwksem.asm	6.3 91/06/13"

TITLE   TKWKSEM - Worker routines for kernel semaphores
NAME    TKWKSEM
PAGE    ,132

;***    TKWKSEM.ASM
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;       Title:
;
;       Workers for kernel Event semaphores, semaphore creation and destruction
;       Mutex and Share semaphores are for VDH services only. All others should
;       use KSEM routines which are much well behaved. ksem routines are faster
;       and a comprise for MVDM.
;
;       Modification History:
;
;       89/08/10    Sudeep Bharati  Created
;       90/04/20    Jameel Hyder    Stripped down to a bare minimum

INCL_ERROR_H    equ     1
INCL_ERROR2_H   equ     1
.xlist
include fnotask.inc
include dosseg.inc
include osconst.inc
include basemaca.inc
include osmaca.inc
include infoseg.inc
include vmowner.inc
include dossymc.inc
include sigdef.inc
include except.inc
include pgexport.inc
include vmexport.inc
include selxport.inc
include tkexport.inc
include bseerr.inc
include mi.inc
include tkksem.inc
.list

        CpuMode 386
        ModName , FNO_TKWKSEM_ASM

        ReferFlat       _pTCBCur,DWORD
        ReferGlobal     TaskNumber,WORD

        EXTRN32         _VMAllocKHB
        EXTRN32         _VMFreeKHB
        EXTRN32         _TKSleep
        EXTRN32         _TKWakeup

        FARCODE HIGH32
HIGH32CODE      SEGMENT

ifdef   MISCSTRICT
        EXTRN   ksemownie:near
        EXTRN   ksemsigie:near
        EXTRN   ksemovie:near
endif
ifdef   PMDEBUG
        ReferFlat       szKSEM,BYTE
endif

;***EP  ksemAlloc- Allocate an Event/Mutex/Shared Semaphore
;
;       Allocate/Initialize an Event, Mutex, or Shared Semaphore.
;
;       ENTRY
;           edx - pSem (ksemInit only)
;           ecx - flags [KSEM_NOINTERRUPT|KSEM_NOBLOCK]
;           eax - semaphore type
;
;       EXIT    SUCCESS     eax = NO_ERROR; edx has semaphore handle
;               FAILURE     eax = ERROR_NOT_ENOUGH_MEMORY
;                           Invalid semtype will result in a panic.
;
;       CONTEXT
;           Task
;
;       USES: EAX ECX EDX flags

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemAlloc,near
LocalVar    ksem,DWORD

        EnterProc
        SSToDS  edx,[ksem]
        mov     ch,al                           ; CH = sem type
        push    ecx
        mov     eax,size KSEMMTX                ; Assume mutex
        cmp     ch,KRNL_MUTEXSEM
        je      short ksa05
        mov     eax,size KSEMSHR                ; Assume shared
        cmp     ch,KRNL_SHARESEM
        je      short ksa05
        mov     eax,size KSEMEVT
ksa05:
ifdef   PMDEBUG
        .errnz  KSEM_DISPLAYID - 4
        and     ecx,KSEM_DISPLAYID
        add     eax,ecx
endif
        CCALL32 _VMAllocKHB <VM_HKH_PUB_RESRW, eax, KSEMOWNER, 0, edx>
                                                ; Allocate KSEM structure
        pop     ecx
        mov     edx,[ksem]                      ; EDX = pSem
        LeaveProc
        or      eax,eax
        .errnz  NO_ERROR
        jz      short ksa10
        RETC
Entry ksemInit,near

        mov     ch,al                           ; CH = sem type
        xor     eax,eax

ksa10:  TaskTime                                ; Validate Context

        ; EDX = pSem
        ; CH = sem type
        ; CL = sem flags

ifdef   MISCSTRICT
        mov     [edx].ks_Signature,KSEM_SIGNATURE
        cmp     ch, KRNL_MAXSEMTYPE             ; Validate Sem type
        jb      short ksa20
        Panic   <"ksemCreate: Invalid Parameter">
endif

ksa20:  mov     [edx].ks_bFlags,cl              ; Flags
        mov     [edx].ks_bType,ch               ; Type
;;;     mov     [edx].ks_Owner,ax               ; Zero init rest of the struct
;;;     mov     [edx].ks_cusPendingWriters,ax
        mov     dword ptr [edx].ks_Owner,eax
        .errnz  (ks_cusPendingWriters - ks_Owner - 2)
        cmp     ch,KRNL_EVENTSEM                ; Event semaphore ?
        je      short ksa30                     ; yes, thats all
        mov     [edx].ks_cusNest,ax             ; For MUTEX
        cmp     ch,KRNL_MUTEXSEM                ; Mutex semaphore ?
        je      short ksa30
;;;     mov     [edx].ks_cusReaders,ax
;;;     mov     [edx].ks_cusPendingReaders,ax   ; Request Count 0
        mov     dword ptr [edx].ks_cusReaders,eax
        .errnz  (ks_cusPendingReaders - ks_cusReaders - 2)
;;;     mov     [edx].ks_cusPendingReaderWriters,ax
;;;     mov     [edx].ks_cusPendingUpgrades,ax
ksa30:  RETC
EndProc ksemAlloc


;***EP  ksemCreate - Maintain compatiblity with old ksem routines
;
;       Allocate/Initialize an Event, Mutex, or Shared Semaphore.
;
;       ENTRY   edx - semaphore type
;               ecx - block id
;
;       EXIT    SUCCESS     eax = NO_ERROR; edx has semaphore handle
;               FAILURE     eax = ERROR_NOT_ENOUGH_MEMORY
;                           Invalid semtype will result in a panic.
;
;       CONTEXT
;           Task
;
;       USES: EAX EDX flags

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemCreate,near

        SaveReg <ecx>
        mov     eax,edx                         ; EAX = sem type
ifdef   PMDEBUG
        or      ecx,ecx                         ; if (display id != NULL)
        mov     ecx,KSEM_DISPLAYID              ;  sem flags = KSEM_DISPLAYID
        jnz     short ksc10                     ; else
endif
        xor     ecx,ecx                         ;  sem flags = NULL
ksc10:  cmp     eax,KRNL_MUTEXSEM               ; if (sem type != mutex)
        jne     short ksc20
        or      ecx,KSEM_NOINTERRUPT            ;  sem flags |= KSEM_NOINTERRUPT
ksc20:  CCALL32 ksemAlloc
        RestoreReg <ecx>
        or      eax,eax                         ; Return if error
        .errnz  NO_ERROR
        jnz     short kscx
ifdef   PMDEBUG
        or      ecx,ecx                         ; Display ID ?
        jz      short kscx                      ;  no, done
        movzx   eax,[edx].ks_bType              ; (EAX) = Semaphore type
        movzx   eax,szKSEM[eax]
        mov     dword ptr [edx].[eax],ecx       ; Update display ID
        xor     eax,eax
endif
kscx:   RETC
EndProc ksemCreate


;***EP  ksemDestroy - Destroy a semaphore
;
;       Destroy a semaphore
;
;       ENTRY   edx - handle to the semaphore
;
;       EXIT    SUCCESS - returns othing
;               FAILURE - Panics if:
;                           - semaphore handle is invalid.
;                           - sem is reset or owned.
;       CONTEXT
;           Task
;
;       USES: EAX, ECX, EDX, FLAGS

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemDestroy,near

        TaskTime                                ; Validate calling context
        KSemChkSig edx                          ; Validate sem signature

        cmp     [edx].ks_bType,KRNL_EVENTSEM    ; Event semaphore ?
        je      short ksd10                     ; yes, thats the only check.

ifdef   MISCSTRICT
        cmp     [edx].ks_Owner,0                ; Owned ?
        jne     short ksdie                     ; error if owned
endif
        movzx   eax,[edx].ks_cusNest            ; (EAX) = Nest count
        cmp     [edx].ks_bType,KRNL_MUTEXSEM    ; Mutex semaphore ?
        je      short ksd05
        or      ax,[edx].ks_cusReaders
ksd05:
ifdef   MISCSTRICT
        or      eax,eax                         ; Check that sem is not in use
        jnz     short ksdie                     ; error if owned
endif

ksd10:
ifdef   MISCSTRICT
        mov     [edx].ks_Signature,0            ; Mark signature bad
endif
        CCALL32 _VMFreeKHB <VM_HKH_PUB_RESRW, edx>
        RETC                                    ; Free the KRNLSEM structure
ifdef   MISCSTRICT
ksdie:  Panic   <"ksemDestoy: In Use">
endif
EndProc   ksemDestroy


;***EP  ksemResetEvent - reset an event semaphore
;
;       ksemResetEvent resets an event semaphore.
;
;       ENTRY   edx - handle of a mutex semaphore
;
;       EXIT    returns nothing
;
;       CONTEXT
;           Task or Interrupt
;           Interrupt
;
;       USES:   FLAGS, EAX

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemResetEvent,near

        KSemChkSig  edx,KRNL_EVENTSEM   ; Validate signature
        pushfd
        cli
        mov     ax,TaskNumber
        mov     [edx].ks_Owner,ax
        popfd
        RETC
EndProc ksemResetEvent



;***EP  ksemPostEvent - Post an event semaphore
;
;       ENTRY   edx - handle of an event semaphore
;
;       EXIT    returns nothing
;
;       CONTEXT
;           Task or Interrupt
;           Interrupt
;
;       USES:   FLAGS,EAX

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemPostEvent,near

        KSemChkSig edx,KRNL_EVENTSEM    ; Validate signature
        xor     eax,eax
        cmp     [edx].ks_Owner,ax
        je      short kspx              ; no one reset the semaphore yet
        pushfd
        cli
        mov     [edx].ks_Owner,ax
        cmp     [edx].ks_cusPendingWriters,ax
        je      short ksp10
        SaveReg <ecx,edx>
        lea     edx,[edx].ks_bFlags     ; EDX = Block ID
        CCALL32 _TKWakeup <edx, WAKEUP_SINGLE OR WAKEUP_SINGLE_ALL, NULL>
        RestoreReg <edx,ecx>
ksp10:  popfd
kspx:   RETC
EndProc ksemPostEvent


;***EP  ksemWaitEvent - wait on an event semaphore
;
;       ENTRY   edx - handle of a mutex semaphore
;               ecx - timeout in milliseconds
;
;       EXIT      Success - return NO_ERROR
;                 Failure - ERROR_TIMEOUT
;                           ERROR_INTERRUPT
;                           ERROR_NOBLOCK
;                           Panics if
;                               invalid semaphore handle
;       CONTEXT
;           Task
;
;       USES:   FLAGS

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemWaitEvent,near

        TaskTime                        ; Validate calling context
        KSemChkSig edx,KRNL_EVENTSEM    ; Validate signature
        cli
        xor     eax,eax
        cmp     [edx].ks_Owner,ax       ; Is semaphore owned
        je      short kswx              ;  No, done

        KSemSetDbgAddr edx              ;  yes, block

        inc     [edx].ks_cusPendingWriters
        KSemChkOvf
        mov     al,[edx].ks_bFlags
        and     eax,KSEM_NOINTERRUPT
        SaveReg <ecx,edx>
        lea     edx,[edx].ks_bFlags     ; EDX = Block ID
        CCALL32 _TKSleep <edx,ecx,eax,WAKEUP_SINGLE>
        RestoreReg <edx,ecx>
        KSemClrDbgAddr
        dec     [edx].ks_cusPendingWriters
kswx:   sti                             ; always return;  this allows event
        RETC                            ; semaphores to be "pulsed"
EndProc ksemWaitEvent



;***EP  ksemRequestMutex - Request a mutex semaphore
;
;       ENTRY   edx - handle of a mutex semaphore
;               ecx - timeout in milliseconds
;
;       EXIT      Success - return NO_ERROR
;                 Failure - ERROR_TIMEOUT
;                           ERROR_INTERRUPT
;                           ERROR_NOBLOCK
;                           Panics if
;                               invalid semaphore handle
;                               request count crossing 64k limit.
;       CONTEXT
;           Task
;
;       USES:   FLAGS

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemRequestMutex,near

        TaskTime                        ; Validate calling context
        KSemChkSig edx,KRNL_MUTEXSEM    ; Validate signature

kre10:  mov     ax,TaskNumber
        cmp     [edx].ks_Owner,0        ; Is semaphore free
        jne     short kre20             ; No, see if we are owner
        mov     [edx].ks_Owner,ax       ; pSem->Owner = TaskNumber
        jmp     short kre30

kre20:  cmp     [edx].ks_Owner,ax       ; Are we owner ?
        je      short kre30             ;  Yes, continue

        test    [edx].ks_bFlags,KSEM_NOBLOCK ; Can we block?
        jnz     short krenb             ;  No, return error

        inc     [edx].ks_cusPendingWriters
        KSemSetDbgAddr edx
        mov     al,[edx].ks_bFlags
        and     eax,KSEM_NOINTERRUPT
        SaveReg <ecx,edx>
        CCALL32 _TKSleep <edx, ecx, eax, WAKEUP_SINGLE>
        RestoreReg <edx,ecx>
        dec     [edx].ks_cusPendingWriters
        KSemClrDbgAddr
        or      eax,eax
        .errnz  NO_ERROR
        jz      short kre10
        jmp     short krex
kre30:  inc     [edx].ks_cusNest        ; pSem->cusNest++
        KSemChkOvf
        xor     eax,eax
        .errnz  NO_ERROR
krex:   RETC

krenb:  mov     eax,ERROR_NOBLOCK
        jmp     short krex
EndProc ksemRequestMutex


;***EP  ksemReleaseMutex - release a mutex semaphore
;
;       ENTRY   edx - handle of a mutex semaphore
;
;       EXIT    returns nothing
;
;       CONTEXT
;           Task
;
;       USES:   FLAGS

        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemReleaseMutex,near

        TaskTime                        ; Validate calling context
        KSemChkSig edx,KRNL_MUTEXSEM    ; Validate signature
        KSemChkOwn edx                  ; Validate owner

        dec     [edx].ks_cusNest        ; if (--pSem->cusNest == 0) {
        jnz     short ksmx
        mov     [edx].ks_Owner,0        ;  pSem->Owner = 0

        cmp     [edx].ks_cusPendingWriters,0 ; Any waiting threads ?
        je      short ksmx              ; no, done
        SaveReg <edx,ecx>
        CCALL32 _TKWakeup <edx, WAKEUP_SINGLE, NULL>
        RestoreReg <ecx,edx>
ksmx:   RETC
EndProc ksemReleaseMutex


;***EP  ksemQuery - Query a Semaphore's state
;
;       Query the state of an event or mutex semaphore.
;
;       ENTRY   edx - handle of semaphore to query
;               ecx - pointer to area to be filled in with current
;                                 state of semaphore:
;               direction flag is clear (cld)
;
;       EXIT      Success - returns nothing
;                 Failure - Panics if:
;                               semaphore handle is invalid
;       CONTEXT
;           Task
;           Interrupt
;
;       PSEUDO CODE
;           validate calling context
;           validate hsem
;           fill in the fields of state buffer
;
;       USES: Nothing
;
;       NOTES: This routine is callable only for event and mutex semaphores.
;
;       IMPORTANT NOTE: If any change is made to the buffer structure in which
;       the state  is returned, it should be reflected in both VDHSEMSTATE and
;       KSEMSTATE.


        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
Procedure ksemQuery,near

        KSemChkSig edx                  ; Validate signature
        pushfd
        cli

ifdef   MISCSTRICT
        cmp     [edx].ks_bType,KRNL_SHARESEM
        je      ksemsigie
endif
        cmp     [edx].ks_Owner,0
        setnz   [ecx].kss_fOwned

        mov     [ecx].kss_fWaiter,0
        cmp     [edx].ks_cusPendingWriters,0
        setnz   byte ptr [ecx].kss_fWaiter

        mov     al,[edx].ks_bType
        mov     [ecx].kss_semtype,al

        xor     eax,eax
        cmp     [edx].ks_bType,KRNL_MUTEXSEM    ; Mutex semaphore ?
        jne     short ksq10                     ;  no, kss_cRequest = 0
        mov     ax,[edx].ks_cusNest             ;  yes, get kss_cRequest
ksq10:  mov     [ecx].kss_cRequest,ax

        mov     ax,[edx].ks_Owner
        mov     [ecx].kss_tid,ax
        popfd
        RETC
EndProc ksemQuery

HIGH32CODE      ENDS

        END
