KeSetLegacyAffinityThread

UINT64 __stdcall KeSetLegacyAffinityThread(_ETHREAD *Thread, UINT64 Affinity){
  _EPROCESS *Process; 
  unsigned __int64 Mask; 
  unsigned __int8 CurrentIrql; 
  struct _KPRCB *CurrentPrcb; 
  unsigned __int64 v8; 
  _ETHREAD *CurrentThread; 
  INT64 v11; 
  _ETHREAD *NextThread; 
  char v13; 
  INT64 v14; 
  _SINGLE_LIST_ENTRY ReadyList; 
  _GROUP_AFFINITY Affinitya; 

  Process = Thread->Tcb.Process;
  Mask = 0i64;
  if( Affinity )
  {
    ReadyList.Next = 0i64;
    Affinitya = 0i64;
    CurrentIrql = KeGetCurrentIrql();
    __writecr8(2ui64);
    CurrentPrcb = KeGetCurrentPrcb();
    ExAcquireSpinLockSharedAtDpcLevel((PEX_SPIN_LOCK)&Process->Pcb.ProcessLock);
    Affinitya.Group = Thread->Tcb.UserAffinity.Group;
    v8 = KeActiveProcessors.Bitmap[Affinitya.Group] & Affinity;
    if( v8 && (v8 & Process->Pcb.Affinity.Bitmap[Affinitya.Group]) == v8 )
    {
      Mask = Thread->Tcb.UserAffinity.Mask;
      Affinitya.Mask = v8;
      KiSetAffinityThread(&Thread->Tcb, &ReadyList, &Affinitya);
    }
    ExReleaseSpinLockSharedFromDpcLevel((PEX_SPIN_LOCK)&Process->Pcb.ProcessLock);
    KiReadyDeferredReadyList(CurrentPrcb, &ReadyList);
    if( CurrentIrql < 2u )
    {
      CurrentThread = CurrentPrcb->CurrentThread;
      if( CurrentPrcb->NextThread )
      {
        KiAbProcessContextSwitch(&CurrentPrcb->CurrentThread->Tcb, 0i64);
        LODWORD(v14) = 0;
        while( _interlockedbittestandset64((volatile signed __int32 *)&CurrentPrcb->PrcbLock, 0i64) )
        {
          do
            KeYieldProcessorEx((UINT64 *)&v14);
          while( CurrentPrcb->PrcbLock );
        }
        NextThread = CurrentPrcb->NextThread;
        CurrentPrcb->NextThread = 0i64;
        _disable();
        KiEndThreadCycleAccumulation(
          (INT64)CurrentPrcb,
          (INT64)CurrentThread,
          0i64,
          v11,
          v14,
          (INT64)ReadyList.Next,
          Affinitya.Mask);
        _enable();
        CurrentPrcb->CurrentThread = NextThread;
        if( NextThread->Tcb.WaitBlockFill6[68] == 1 )
          NextThread->Tcb.ReadyTime = NextThread->Tcb.ReadyTime
                                    - NextThread->Tcb.WaitBlock[2].SpareLong
                                    + KUSER_SHARED_DATA.TickCount.LowPart;
        NextThread->Tcb.WaitBlockFill6[68] = 2;
        CurrentThread->Tcb.WaitReason = 32;
        CurrentThread->Tcb.WaitIrql = CurrentIrql;
        KiQueueReadyThread(CurrentPrcb, &CurrentThread->Tcb);
        KiSwapContext();
        if( !v13 )
          goto LABEL_8;
      }
      else if( (CurrentThread->Tcb._bf_0 & 0x40) == 0 )
      {
LABEL_8:
        __writecr8(CurrentIrql);
        return Mask;
      }
      __writecr8(1ui64);
      CurrentThread->Tcb._bf_0 &= ~0x40u;
      KiDeliverApc(0, 0i64, 0i64);
      goto LABEL_8;
    }
    if( CurrentPrcb->NextThread && !CurrentPrcb->DpcRoutineActive )
      KiRequestSoftwareInterrupt(CurrentPrcb, 2);
  }
  return Mask;
}

Referenced by:

NtSetInformationThread