KiBeginThreadWait

VOID __stdcall KiBeginThreadWait(_ETHREAD *Thread, CHAR WaitMode, _KWAIT_REASON WaitReason, UINT8 Alertable){
  unsigned __int8 WaitIrql; 
  __int64 v6; 
  struct _KPRCB *CurrentPrcb; 
  unsigned __int8 v9; 
  _DWORD *SchedulerAssist; 
  UINT64 SpinCount; 
  _KWAIT_REASON v12; 

  v12 = WaitReason;
  WaitIrql = Thread->Tcb.WaitIrql;
  v6 = WaitMode;
  while( 1 )
  {
    Thread->Tcb._bf_0 &= ~0x10u;
    Thread->Tcb.WaitRegister.Flags = 0;
    Thread->Tcb.WaitMode = v6;
    if( Alertable )
      Thread->Tcb._bf_0 |= 0x10u;
    CurrentPrcb = KeGetCurrentPrcb();
    LODWORD(SpinCount) = 0;
    while( _interlockedbittestandset64((volatile signed __int32 *)&Thread->Tcb.ThreadLock, 0i64) )
    {
      do
        KeYieldProcessorEx(&SpinCount);
      while( Thread->Tcb.ThreadLock );
      SchedulerAssist = CurrentPrcb->SchedulerAssist;
      if( SchedulerAssist && CurrentPrcb->NestingLevel <= 1u )
        ++SchedulerAssist[6];
    }
    if( !Thread->Tcb.ApcState.KernelApcPending || Thread->Tcb.SpecialApcDisable || WaitIrql )
      break;
    KiReleaseThreadLockSafe((INT64)Thread);
    __writecr8(1ui64);
    KiDeliverApc(0, 0i64, 0i64);
    KeGetCurrentIrql();
    __writecr8(2ui64);
    Thread->Tcb.WaitIrql = 0;
  }
  v9 = v12;
  if( Alertable )
  {
    if( Thread->Tcb.Alerted[v6] )
    {
      Thread->Tcb.Alerted[v6] = 0;
    }
    else if( (_BYTE)v6 && (unsigned __int8 *)Thread->Tcb.ApcState.ApcListHead[1].Flink != &Thread->Tcb.ApcStateFill[16] )
    {
      Thread->Tcb.ApcState.UserApcPendingAll |= 2u;
    }
    else
    {
      if( !Thread->Tcb.Alerted[0] )
      {
LABEL_9:
        Thread->Tcb.WaitBlockFill6[68] = 5;
        Thread->Tcb.WaitReason = v9;
        Thread->Tcb.WaitBlock[2].SpareLong = KUSER_SHARED_DATA.TickCount.LowPart;
        Thread->Tcb.ThreadLock = 0i64;
        return;
      }
      Thread->Tcb.Alerted[0] = 0;
    }
  }
  else if( (Thread->Tcb.ApcState.UserApcPendingAll & 2) == 0 || !(_BYTE)v6 )
  {
    goto LABEL_9;
  }
  KiReleaseThreadLockSafe((INT64)Thread);
  KiCheckForThreadDispatch(KeGetCurrentPrcb(), WaitIrql);
}

Referenced by:

KeDelayExecutionThread
KeRemovePriQueue
KeWaitForAlertByThreadId
KeWaitForGate
KiWaitForAllObjects