KeWaitForMultipleObjects

VOID __fastcall KeWaitForMultipleObjects(
        _BYTE *Count,
        VOID **Object,
        _WAIT_TYPE WaitType,
        _KWAIT_REASON WaitReason,
        CHAR WaitMode,
        UINT8 Alertable,
        _LARGE_INTEGER *Timeout,
        _KWAIT_BLOCK *WaitBlockArray){
  _KWAIT_BLOCK *v8; 
  _ETHREAD *CurrentThread; 
  unsigned __int8 CurrentIrql; 
  UINT8 v11; 
  struct _KPRCB *CurrentPrcb; 
  char v13; 
  struct _KPRCB *v14; 
  __int64 v15; 
  struct _KPRCB *v16; 
  volatile unsigned __int8 *p_BlockState; 
  VOID **v18; 
  unsigned __int64 v19; 
  unsigned int v20; 
  _KMUTANT *v21; 
  _LIST_ENTRY *v22; 
  __int64 v23; 
  int v24; 
  unsigned __int64 v25; 
  int v26; 
  unsigned int v27; 
  unsigned __int64 v28; 
  int v29; 
  VOID **v30; 
  struct _KPRCB *v31; 
  __int64 v32; 
  void *v33; 
  _KWAIT_BLOCK *v34; 
  void *v35; 
  _LIST_ENTRY *Flink; 
  _LIST_ENTRY *Blink; 
  __int64 v38; 
  unsigned __int64 v39; 
  unsigned __int64 v40; 
  char v41; 
  struct _KPRCB *v42; 
  struct _KPRCB *v43; 
  unsigned __int8 v45; 
  __int64 v46; 
  __int64 v47; 
  __int64 v48; 
  __int64 v49; 
  unsigned __int64 v50; 
  char v51; 
  _QWORD *v52; 
  _QWORD *v53; 
  __int64 v54; 
  __int64 v55; 
  unsigned int v56; 
  unsigned __int64 v57; 
  __int64 v58; 
  unsigned __int64 v59; 
  _BYTE *v60; 
  __int64 v61; 
  void *v62; 
  struct _KPRCB *v63; 
  __int64 v64; 
  int v65; 
  __int64 v66; 
  struct _KPRCB *v67; 
  __int64 v68; 
  int v69; 
  char v70; 
  int v71; 
  _KPRCB *Prcb; 
  unsigned __int64 v74; 
  __int64 v75; 
  __int64 v76; 
  unsigned int v77; 
  LONGLONG QuadPart; 
  UINT64 SpinCount; 
  UINT64 v80; 
  int v81; 
  int v82; 
  UINT64 v83; 
  UINT64 v84; 
  UINT64 v85; 
  VOID *v86; 
  _SINGLE_LIST_ENTRY ReadyList; 
  _ETHREAD *v88; 
  __int64 v89; 
  char v90[8]; 
  v8 = WaitBlockArray;
  HIDWORD(SpinCount) = WaitReason;
  v77 = (unsigned int)Count;
  QuadPart = 0i64;
  if( (_DWORD)Count == 1 )
  {
    KeWaitForSingleObject(*Object, WaitReason, WaitMode, Alertable, Timeout);
    return;
  }
  CurrentThread = (_ETHREAD *)KeGetCurrentThread();
  v88 = CurrentThread;
  if( !WaitBlockArray )
  {
    if( (unsigned int)Count <= 3 )
    {
      v8 = (_KWAIT_BLOCK *)((char *)CurrentThread + 320);
      goto LABEL_5;
    }
LABEL_117:
    KeBugCheck(0xCui64);
  }
  if( (unsigned int)Count > 0x40 )
    goto LABEL_117;
LABEL_5:
  if( WaitType == WaitAll )
  {
    KiWaitForAllObjects((UINT64)Count, Object, WaitReason, WaitMode, Alertable, Timeout, v8);
    return;
  }
  v86 = 0i64;
  v89 = 0i64;
  v70 = _bittestandreset((signed __int32 *)CurrentThread + 29, 2u);
  if( !v70 )
  {
    CurrentIrql = KeGetCurrentIrql();
    __writecr8(2ui64);
    *((_BYTE *)CurrentThread + 390) = CurrentIrql;
  }
  if( Timeout )
  {
    if( Timeout->HighPart >= 0 )
    {
      QuadPart = Timeout->QuadPart;
      v71 = 1;
    }
    else
    {
      v71 = 2;
      QuadPart = *(_QWORD *)&KUSER_SHARED_DATA.InterruptTime.LowPart
               - KUSER_SHARED_DATA.InterruptTimeBias
               - (Timeout->QuadPart
                + *((_QWORD *)CurrentThread + 31));
    }
  }
  else
  {
    v71 = 0;
  }
  while( 2 )
  {
    v11 = *((_BYTE *)CurrentThread + 390);
    while( 1 )
    {
      *((_DWORD *)CurrentThread + 29) &= ~0x10u;
      *((_BYTE *)CurrentThread + 112) = 0;
      *((_BYTE *)CurrentThread + 391) = WaitMode;
      if( Alertable )
        *((_DWORD *)CurrentThread + 29) |= 0x10u;
      CurrentPrcb = KeGetCurrentPrcb();
      LODWORD(SpinCount) = 0;
      while( _interlockedbittestandset64((volatile signed __int32 *)CurrentThread + 16, 0i64) )
      {
        do
          KeYieldProcessorEx(&SpinCount);
        while( *((_QWORD *)CurrentThread + 8) );
        v46 = *((_QWORD *)CurrentPrcb + 4247);
        if( v46 && *((_BYTE *)CurrentPrcb + 32) <= 1u )
          ++*(_DWORD *)(v46 + 24);
      }
      if( !*((_BYTE *)CurrentThread + 193) || *((_WORD *)CurrentThread + 243) || v11 )
        break;
      KiReleaseThreadLockSafe((INT64)CurrentThread);
      __writecr8(1ui64);
      KiDeliverApc(0, 0i64, 0i64);
      KeGetCurrentIrql();
      __writecr8(2ui64);
      *((_BYTE *)CurrentThread + 390) = 0;
    }
    v13 = BYTE4(SpinCount);
    if( !Alertable )
    {
      if( (*((_BYTE *)CurrentThread + 194) & 2) != 0 && WaitMode )
        goto LABEL_109;
      goto LABEL_19;
    }
    if( *((_BYTE *)CurrentThread + WaitMode + 114) )
    {
      *((_BYTE *)CurrentThread + WaitMode + 114) = 0;
      goto LABEL_109;
    }
    if( WaitMode && *((_ETHREAD **)CurrentThread + 21) != (_ETHREAD *)((char *)CurrentThread + 168) )
    {
      *((_BYTE *)CurrentThread + 194) |= 2u;
      goto LABEL_109;
    }
    if( *((_BYTE *)CurrentThread + 114) )
    {
      *((_BYTE *)CurrentThread + 114) = 0;
LABEL_109:
      KiReleaseThreadLockSafe((INT64)CurrentThread);
      KiCheckForThreadDispatch(KeGetCurrentPrcb(), v11);
      return;
    }
LABEL_19:
    *((_BYTE *)CurrentThread + 388) = 5;
    *((_BYTE *)CurrentThread + 643) = v13;
    *((_DWORD *)CurrentThread + 109) = KUSER_SHARED_DATA.TickCount.LowPart;
    *((_QWORD *)CurrentThread + 8) = 0i64;
    v14 = KeGetCurrentPrcb();
    v15 = *((_QWORD *)v14 + 4247);
    if( v15 && *((_BYTE *)v14 + 32) <= 1u )
      --*(_DWORD *)(v15 + 24);
    v16 = KeGetCurrentPrcb();
    p_BlockState = &v8->BlockState;
    v18 = Object;
    v19 = 0i64;
    Prcb = v16;
    v20 = 0;
    v74 = 0i64;
    do
    {
      LODWORD(v80) = 0;
      v21 = (_KMUTANT *)v18[v20];
      *((_BYTE *)p_BlockState - 1) = 1;
      *p_BlockState = 4;
      *(_WORD *)(p_BlockState + 1) = v20;
      *(_QWORD *)(p_BlockState + 7) = CurrentThread;
      *(_QWORD *)(p_BlockState + 15) = v21;
      if( _interlockedbittestandset(&v21->Header.Lock, 7u) )
      {
        do
        {
          do
            KeYieldProcessorEx(&v80);
          while( (v21->Header.LockNV & 0x80u) != 0 );
        }
        while( _interlockedbittestandset(&v21->Header.Lock, 7u) );
        v18 = Object;
        v19 = v74;
        v16 = Prcb;
      }
      if( (v21->Header.Type & 0x7F) != 2 )
      {
        if( v21->Header.SignalState <= 0 )
          goto LABEL_24;
        v31 = KeGetCurrentPrcb();
        HIDWORD(v84) = 0;
        while( _interlockedbittestandset64((volatile signed __int32 *)CurrentThread + 16, 0i64) )
        {
          do
            KeYieldProcessorEx((UINT64 *)((char *)&v84 + 4));
          while( *((_QWORD *)CurrentThread + 8) );
          v47 = *((_QWORD *)v31 + 4247);
          if( v47 && *((_BYTE *)v31 + 32) <= 1u )
            ++*(_DWORD *)(v47 + 24);
        }
        if( (*((_BYTE *)CurrentThread + 112) & 7) == 0 )
        {
          *((_QWORD *)CurrentThread + 25) = v20;
          *((_QWORD *)CurrentThread + 122) = 0i64;
          if( (v21->Header.Type & 7) == 1 )
          {
            v21->Header.SignalState = 0;
          }
          else if( (v21->Header.Type & 0x7F) == 5 )
          {
            --v21->Header.SignalState;
          }
        }
        v32 = (__int64)Prcb;
LABEL_43:
        _InterlockedAnd(&v21->Header.Lock, 0xFFFFFF7F);
LABEL_44:
        *((_BYTE *)CurrentThread + 388) = 2;
        *((_QWORD *)CurrentThread + 8) = 0i64;
        v33 = (void *)*((_QWORD *)CurrentThread + 122);
        if( v33 )
        {
          *((_QWORD *)CurrentThread + 122) = 0i64;
          LODWORD(v66) = KeAbPreAcquire(v33, 0i64, 1ui64);
          if( v66 )
            *(_BYTE *)(v66 + 26) |= 1u;
        }
        if( v20 )
        {
          v34 = &v8[(unsigned __int8)v20];
          do
          {
            if( v8->BlockState < 5u )
            {
              v35 = v8->Object;
              KiAcquireKobjectLockSafe(v35);
              if( v8->BlockState == 4 )
              {
                Flink = v8->WaitListEntry.Flink;
                Blink = v8->WaitListEntry.Blink;
                if( (_KWAIT_BLOCK *)v8->WaitListEntry.Flink->Blink != v8 || (_KWAIT_BLOCK *)Blink->Flink != v8 )
                  goto LABEL_50;
                Blink->Flink = Flink;
                Flink->Blink = Blink;
              }
              _InterlockedAnd((volatile signed __int32 *)v35, 0xFFFFFF7F);
            }
            ++v8;
          }
          while( v8 != v34 );
        }
        v40 = *((unsigned __int8 *)CurrentThread + 390);
        v41 = *((_BYTE *)CurrentThread + 112);
        if( (v41 & 0x38) != 0 )
        {
          if( (v41 & 0x18) != 0 )
          {
            if( (v41 & 8) != 0 )
              _interlockedbittestandset((volatile signed __int32 *)CurrentThread + 30, 0xCu);
            ReadyList.Next = 0i64;
            v67 = KeGetCurrentPrcb();
            LODWORD(v85) = 0;
            while( _interlockedbittestandset64((volatile signed __int32 *)(v32 + 48), 0i64) )
            {
              do
                KeYieldProcessorEx(&v85);
              while( *(_QWORD *)(v32 + 48) );
              v68 = *((_QWORD *)v67 + 4247);
              if( v68 && *((_BYTE *)v67 + 32) <= 1u )
              {
                v69 = *(_DWORD *)(v68 + 24) + 1;
                *(_DWORD *)(v68 + 24) = v69;
              }
            }
            if( !*(_QWORD *)(v32 + 16) )
              KiSelectNextThread((_KPRCB *)v32, &ReadyList);
            _InterlockedAnd64((volatile signed __int64 *)(v32 + 48), 0i64);
            KiProcessDeferredReadyList(v32, &ReadyList, v40);
          }
          else
          {
            KiCheckForThreadDispatch((_KPRCB *)v32, 1u);
            KiDeliverApc(0, 0i64, 0i64);
            __writecr8(0i64);
          }
        }
        else if( v70 )
        {
          KiCheckForThreadDispatch((_KPRCB *)v32, v40);
        }
        else
        {
          __writecr8(v40);
        }
        return;
      }
      if( (v21->MutantFlags & 2) != 0 )
      {
        _bittestandset64((__int64 *)&v19, v20);
        v74 = v19;
      }
      if( v21->Header.SignalState > 0
        || CurrentThread == v21->OwnerThread && v21->Header.Size == *((_BYTE *)v16 + 12586) )
      {
        if( v21->Header.SignalState == 0x80000000 )
        {
          _InterlockedAnd(&v21->Header.Lock, 0xFFFFFF7F);
          v63 = KeGetCurrentPrcb();
          HIDWORD(v83) = 0;
          while( _interlockedbittestandset64((volatile signed __int32 *)CurrentThread + 16, 0i64) )
          {
            do
              KeYieldProcessorEx((UINT64 *)((char *)&v83 + 4));
            while( *((_QWORD *)CurrentThread + 8) );
            v64 = *((_QWORD *)v63 + 4247);
            if( v64 && *((_BYTE *)v63 + 32) <= 1u )
            {
              v65 = *(_DWORD *)(v64 + 24) + 1;
              *(_DWORD *)(v64 + 24) = v65;
            }
          }
          KiSatisfyThreadWait((__int64)Prcb, (__int64)CurrentThread, v70, (__int64 *)v8, v20);
          RtlRaiseStatus(-1073741423);
        }
        v43 = KeGetCurrentPrcb();
        LODWORD(v83) = 0;
        while( _interlockedbittestandset64((volatile signed __int32 *)CurrentThread + 16, 0i64) )
        {
          do
            KeYieldProcessorEx(&v83);
          while( *((_QWORD *)CurrentThread + 8) );
          v49 = *((_QWORD *)v43 + 4247);
          if( v49 && *((_BYTE *)v43 + 32) <= 1u )
            ++*(_DWORD *)(v49 + 24);
        }
        v32 = (__int64)Prcb;
        if( (*((_BYTE *)CurrentThread + 112) & 7) == 0 )
        {
          *((_QWORD *)CurrentThread + 25) = v20;
          *((_QWORD *)CurrentThread + 122) = 0i64;
          if( v21->Header.SignalState-- == 1 )
            KiWaitSatisfyMutant(v21, (_KTHREAD *)CurrentThread, Prcb);
        }
        goto LABEL_43;
      }
LABEL_24:
      v22 = v21->Header.WaitListHead.Blink;
      if( v22->Flink != &v21->Header.WaitListHead )
LABEL_50:
        __fastfail(3u);
      *(_QWORD *)(p_BlockState - 9) = v22;
      *(_QWORD *)(p_BlockState - 17) = &v21->Header.WaitListHead;
      v22->Flink = (_LIST_ENTRY *)(p_BlockState - 17);
      v21->Header.WaitListHead.Blink = (_LIST_ENTRY *)(p_BlockState - 17);
      _InterlockedAnd(&v21->Header.Lock, 0xFFFFFF7F);
      ++v20;
      p_BlockState += 48;
    }
    while( v20 < v77 );
    v23 = QuadPart;
    v24 = v71;
    v25 = QuadPart;
    if( v71 == 2 )
    {
      v38 = *((unsigned int *)CurrentThread + 238);
      v39 = *(_QWORD *)&KUSER_SHARED_DATA.InterruptTime.LowPart
          - *((_QWORD *)CurrentThread + 31)
          - KUSER_SHARED_DATA.InterruptTimeBias;
      v25 = QuadPart;
      if( *((_BYTE *)CurrentThread + 391)
        && !*((_DWORD *)CurrentThread + 121)
        && !*((_BYTE *)CurrentThread + 390)
        && !*((_BYTE *)CurrentThread + 192)
        && (_DWORD)v38 )
      {
        v25 = QuadPart + v38;
      }
      goto LABEL_53;
    }
    if( v71 )
    {
      if( !QuadPart )
      {
LABEL_76:
        v42 = KeGetCurrentPrcb();
        LODWORD(v84) = 0;
        while( _interlockedbittestandset64((volatile signed __int32 *)CurrentThread + 16, 0i64) )
        {
          do
            KeYieldProcessorEx(&v84);
          while( *((_QWORD *)CurrentThread + 8) );
          v48 = *((_QWORD *)v42 + 4247);
          if( v48 && *((_BYTE *)v42 + 32) <= 1u )
            ++*(_DWORD *)(v48 + 24);
        }
        v32 = (__int64)Prcb;
        if( (*((_BYTE *)CurrentThread + 112) & 7) == 0 )
        {
          *((_QWORD *)CurrentThread + 25) = 258i64;
          *((_QWORD *)CurrentThread + 122) = 0i64;
        }
        goto LABEL_44;
      }
      v39 = *(_QWORD *)&KUSER_SHARED_DATA.SystemTime.LowPart;
LABEL_53:
      if( v39 <= v25 )
      {
        v24 = v71;
        goto LABEL_28;
      }
      goto LABEL_76;
    }
LABEL_28:
    v26 = 0;
    *((_BYTE *)CurrentThread + 587) = v77;
    v27 = 0;
    v28 = 0i64;
    if( v19 )
    {
      do
      {
        _BitScanForward64(&v50, v19);
        v51 = v50;
        HIDWORD(v80) = v50;
        v75 = v19 & ~(1i64 << v50);
        LODWORD(v52) = KeAbPreAcquire(v18[v50], 0i64, 0i64);
        v53 = v52;
        if( !v52 )
          break;
        v28 |= 1i64 << v51;
        KeAbPreWait(v52);
        v19 = v75;
        v18 = Object;
        v54 = (__int64)v53 - v53[-2 * *((unsigned __int8 *)v53 + 24) + 100];
        v55 = v27++;
        v90[v55] = (2
                  * (((((unsigned __int128)(v54 * (__int128)0x2AAAAAAAAAAAAAABi64) >> 64) & 0x8000000000000000ui64) != 0i64)
                   + ((__int64)((unsigned __int128)(v54 * (__int128)0x2AAAAAAAAAAAAAABi64) >> 64) >> 4))) | 1;
      }
      while( v75 );
      CurrentThread = v88;
      v26 = 0;
      v23 = QuadPart;
      v24 = v71;
    }
    v29 = KiCommitThreadWait((__int64)CurrentThread, (__int64 *)v8, v24, v23, &v86);
    v30 = Object;
    if( v86 )
    {
      v56 = 0;
      v57 = v28;
      if( v28 )
      {
        while( 1 )
        {
          _BitScanForward64((unsigned __int64 *)&v58, v57);
          v57 &= ~(1i64 << v58);
          v81 = v58;
          if( v86 == Object[v58] )
            break;
          ++v56;
          if( !v57 )
            goto LABEL_132;
        }
        v28 &= ~(1i64 << v58);
        v59 = v56;
        v60 = (_BYTE *)(*((_QWORD *)KeGetCurrentThread() + 100) + 96i64 * ((unsigned __int8)v90[v56] >> 1));
        KeAbPreAcquire(Object[v58], v60, 0i64);
        v60[26] |= 1u;
        if( v59 >= 6 )
          _report_rangecheckfailure();
        v30 = Object;
        v90[v59] = 0;
        v26 = 0;
      }
LABEL_132:
      *((_QWORD *)CurrentThread + 122) = 0i64;
    }
    for( ; v28; ++v26 )
    {
      _BitScanForward64((unsigned __int64 *)&v61, v28);
      v82 = v61;
      v28 &= ~(1i64 << v61);
      v76 = (unsigned int)v61;
      if( !v90[v26] )
        ++v26;
      v62 = (void *)(*((_QWORD *)KeGetCurrentThread() + 100) + 96i64 * ((unsigned __int8)v90[v26] >> 1));
      KeAbPreAcquire(v30[(unsigned int)v61], v62, 0i64);
      KeAbPostReleaseEx(Object[v76], v62);
      v30 = Object;
    }
    if( v29 == 256 )
    {
      v70 = 0;
      v45 = KeGetCurrentIrql();
      __writecr8(2ui64);
      *((_BYTE *)CurrentThread + 390) = v45;
      continue;
    }
    break;
  }
}

Referenced by:

CcAsyncReadWorker
CcQueueLazyWriteScanThread
CmpDoFileWrite
CmpFinishSystemHivesLoad
EtwpCovSampCaptureWorkerThread
EtwpLogger
ExpWorkQueueManagerThread
FsRtlCancellableWaitForMultipleObjects
KeBalanceSetManager
MiDereferenceSegmentThread
MiIssueAsynchronousFlush
MiMappedPageWriter
MiModifiedPageWriter
MiPartitionWorkingSetManager
MiRebuildLargePagesThread
MiStoreEvictThread
MiWaitForAsynchronousFlushes
MiWaitForFreePagesToZero
MiZeroAllPageFiles
ObWaitForMultipleObjects
PfGenerateTrace
PfTLoggingWorker
PiUEventNotifyUserMode
PnprQuiesceWorker
PopFxProcessWorkPool
PopSleepDeviceList
PopThermalReadCounters
PsShutdownSystem
SMKM_STORE::SmStReadThread
SMKM_STORE::SmStWorker