RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) { RTCpuSetEmpty(pSet); int idCpu = RTMpGetCount(); while (idCpu-- > 0) RTCpuSetAdd(pSet, idCpu); return pSet; }
RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) { RTCPUID iCpu = RTMpGetCount(); RTCpuSetEmpty(pSet); while (iCpu-- > 0) RTCpuSetAddByIndex(pSet, iCpu); return pSet; }
RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) { RTCpuSetEmpty(pSet); RTCPUID cMax = rtMpFreeBsdMaxCpus(); for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) if (RTMpIsCpuPossible(idCpu)) RTCpuSetAdd(pSet, idCpu); return pSet; }
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { RTCpuSetEmpty(pSet); RTCPUID cMax = rtMpLinuxMaxCpus(); for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) if (RTMpIsCpuOnline(idCpu)) RTCpuSetAdd(pSet, idCpu); return pSet; }
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { RTCpuSetEmpty(pSet); RTCPUID cCpus = RTMpGetCount(); for (RTCPUID idCpu = 0; idCpu < cCpus; idCpu++) if (RTMpIsCpuOnline(idCpu)) RTCpuSetAdd(pSet, idCpu); return pSet; }
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { #ifdef CONFIG_SMP RTCPUID idCpu; RTCpuSetEmpty(pSet); idCpu = RTMpGetMaxCpuId(); do { if (RTMpIsCpuOnline(idCpu)) RTCpuSetAdd(pSet, idCpu); } while (idCpu-- > 0); #else RTCpuSetEmpty(pSet); RTCpuSetAdd(pSet, RTMpCpuId()); #endif return pSet; }
DECLHIDDEN(int) rtR0MpNotificationNativeInit(void) { int rc; # ifdef CPU_DOWN_FAILED RTCpuSetEmpty(&g_MpPendingOfflineSet); # endif rc = register_cpu_notifier(&g_NotifierBlock); AssertMsgReturn(!rc, ("%d\n", rc), RTErrConvertFromErrno(rc)); return VINF_SUCCESS; }
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { #if 0 return RTMpGetSet(pSet); #else RTCpuSetEmpty(pSet); RTCPUID cMax = rtMpDarwinMaxCpus(); for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) if (RTMpIsCpuOnline(idCpu)) RTCpuSetAdd(pSet, idCpu); return pSet; #endif }
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { RTCPUID idCpu; RTCpuSetEmpty(pSet); idCpu = RTMpGetMaxCpuId(); do { if (RTMpIsCpuOnline(idCpu)) RTCpuSetAdd(pSet, idCpu); } while (idCpu-- > 0); return pSet; }
RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) { RTCPUID idCpu; RTCpuSetEmpty(pSet); idCpu = RTMpGetMaxCpuId(); /* it's inclusive */ do { if (RTMpIsCpuPossible(idCpu)) RTCpuSetAdd(pSet, idCpu); } while (idCpu-- > 0); return pSet; }
RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet) { cpu_set_t LnxCpuSet; int rc = pthread_getaffinity_np(pthread_self(), sizeof(LnxCpuSet), &LnxCpuSet); if (rc != 0) return RTErrConvertFromErrno(errno); /* convert */ RTCpuSetEmpty(pCpuSet); for (unsigned iCpu = 0; iCpu < RT_MIN(CPU_SETSIZE, RTCPUSET_MAX_CPUS); iCpu++) if (CPU_ISSET(iCpu, &LnxCpuSet)) RTCpuSetAddByIndex(pCpuSet, iCpu); return VINF_SUCCESS; }
RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet) { #if 0 RTCPUID cCpus = rtMpDarwinMaxCpus(); return RTCpuSetFromU64(RT_BIT_64(cCpus) - 1); #else RTCpuSetEmpty(pSet); RTCPUID cMax = rtMpDarwinMaxCpus(); for (RTCPUID idCpu = 0; idCpu < cMax; idCpu++) if (RTMpIsCpuPossible(idCpu)) RTCpuSetAdd(pSet, idCpu); return pSet; #endif }
RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet) { processorid_t iOldCpu; int rc = processor_bind(P_LWPID, P_MYID, PBIND_QUERY, &iOldCpu); if (rc) return RTErrConvertFromErrno(errno); if (iOldCpu == PBIND_NONE) RTMpGetPresentSet(pCpuSet); else { RTCpuSetEmpty(pCpuSet); if (RTCpuSetAdd(pCpuSet, iOldCpu) != 0) return VERR_INTERNAL_ERROR_5; } return VINF_SUCCESS; }
RTDECL(PRTCPUSET) RTMpGetPresentSet(PRTCPUSET pSet) { #ifdef RT_STRICT RTCPUID cCpusPresent = 0; #endif RTCpuSetEmpty(pSet); RTCPUID cCpus = RTMpGetCount(); for (RTCPUID idCpu = 0; idCpu < cCpus; idCpu++) if (RTMpIsCpuPresent(idCpu)) { RTCpuSetAdd(pSet, idCpu); #ifdef RT_STRICT cCpusPresent++; #endif } Assert(cCpusPresent == RTMpGetPresentCount()); return pSet; }
RTR3DECL(int) RTThreadSetAffinityToCpu(RTCPUID idCpu) { int rc; if (idCpu == NIL_RTCPUID) rc = RTThreadSetAffinity(NULL); else { int iCpu = RTMpCpuIdToSetIndex(idCpu); if (iCpu >= 0) { RTCPUSET CpuSet; RTCpuSetEmpty(&CpuSet); RTCpuSetAddByIndex(&CpuSet, iCpu); rc = RTThreadSetAffinity(&CpuSet); } else rc = VERR_CPU_NOT_FOUND; } return rc; }
DECLHIDDEN(int) rtR0MpNotificationNativeInit(void) { if (ASMAtomicReadBool(&g_fSolCpuWatch) == true) return VERR_WRONG_ORDER; /* * Register the callback building the online cpu set as we do so. */ RTCpuSetEmpty(&g_rtMpSolCpuSet); mutex_enter(&cpu_lock); register_cpu_setup_func(rtMpNotificationCpuEvent, NULL /* pvArg */); for (int i = 0; i < (int)RTMpGetCount(); ++i) if (cpu_is_online(cpu[i])) rtMpNotificationCpuEvent(CPU_ON, i, NULL /* pvArg */); ASMAtomicWriteBool(&g_fSolCpuWatch, true); mutex_exit(&cpu_lock); return VINF_SUCCESS; }
RTR3DECL(int) RTThreadGetAffinity(PRTCPUSET pCpuSet) { RTCpuSetEmpty(pCpuSet); RTCpuSetAddByIndex(pCpuSet, 0); return VINF_SUCCESS; }
int main() { RTTEST hTest; RTEXITCODE rcExit = RTTestInitAndCreate("tstRTMp-1", &hTest); if (rcExit != RTEXITCODE_SUCCESS) return rcExit; RTTestBanner(hTest); /* * Present and possible CPUs. */ RTCPUID cCpus = RTMpGetCount(); if (cCpus > 0) RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetCount -> %u\n", cCpus); else { RTTestIFailed("RTMpGetCount returned zero"); cCpus = 1; } RTCPUID cCoreCpus = RTMpGetCoreCount(); if (cCoreCpus > 0) RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetCoreCount -> %d\n", (int)cCoreCpus); else { RTTestIFailed("RTMpGetCoreCount returned zero"); cCoreCpus = 1; } RTTESTI_CHECK(cCoreCpus <= cCpus); RTCPUSET Set; PRTCPUSET pSet = RTMpGetSet(&Set); RTTESTI_CHECK(pSet == &Set); if (pSet == &Set) { RTTESTI_CHECK((RTCPUID)RTCpuSetCount(&Set) == cCpus); RTTestIPrintf(RTTESTLVL_ALWAYS, "Possible CPU mask:\n"); for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) { RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu); if (RTCpuSetIsMemberByIndex(&Set, iCpu)) { RTTestIPrintf(RTTESTLVL_ALWAYS, "%2d - id %d: %u/%u MHz", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu)); if (RTMpIsCpuPresent(idCpu)) RTTestIPrintf(RTTESTLVL_ALWAYS, RTMpIsCpuOnline(idCpu) ? " online\n" : " offline\n"); else { if (!RTMpIsCpuOnline(idCpu)) RTTestIPrintf(RTTESTLVL_ALWAYS, " absent\n"); else { RTTestIPrintf(RTTESTLVL_ALWAYS, " online but absent!\n"); RTTestIFailed("Cpu with index %d is report as !RTIsCpuPresent while RTIsCpuOnline returns true!\n", iCpu); } } if (!RTMpIsCpuPossible(idCpu)) RTTestIFailed("Cpu with index %d is returned by RTCpuSet but not RTMpIsCpuPossible!\n", iCpu); } else if (RTMpIsCpuPossible(idCpu)) RTTestIFailed("Cpu with index %d is returned by RTMpIsCpuPossible but not RTCpuSet!\n", iCpu); else if (RTMpGetCurFrequency(idCpu) != 0) RTTestIFailed("RTMpGetCurFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu); else if (RTMpGetMaxFrequency(idCpu) != 0) RTTestIFailed("RTMpGetMaxFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu); } } else { RTCpuSetEmpty(&Set); RTCpuSetAdd(&Set, RTMpCpuIdFromSetIndex(0)); } /* * Online CPUs. */ RTCPUID cCpusOnline = RTMpGetOnlineCount(); if (cCpusOnline > 0) { if (cCpusOnline <= cCpus) RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetOnlineCount -> %d\n", (int)cCpusOnline); else { RTTestIFailed("RTMpGetOnlineCount -> %d, expected <= %d\n", (int)cCpusOnline, (int)cCpus); cCpusOnline = cCpus; } } else { RTTestIFailed("RTMpGetOnlineCount -> %d\n", (int)cCpusOnline); cCpusOnline = 1; } RTCPUID cCoresOnline = RTMpGetOnlineCoreCount(); if (cCoresOnline > 0) RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetOnlineCoreCount -> %d\n", (int)cCoresOnline); else { RTTestIFailed("RTMpGetOnlineCoreCount -> %d, expected <= %d\n", (int)cCoresOnline, (int)cCpusOnline); cCoresOnline = 1; } RTTESTI_CHECK(cCoresOnline <= cCpusOnline); RTCPUSET SetOnline; pSet = RTMpGetOnlineSet(&SetOnline); if (pSet == &SetOnline) { if (RTCpuSetCount(&SetOnline) <= 0) RTTestIFailed("RTMpGetOnlineSet returned an empty set!\n"); else if ((RTCPUID)RTCpuSetCount(&SetOnline) > cCpus) RTTestIFailed("RTMpGetOnlineSet returned a too high value; %d, expected <= %d\n", RTCpuSetCount(&SetOnline), cCpus); RTTestIPrintf(RTTESTLVL_ALWAYS, "Online CPU mask:\n"); for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) if (RTCpuSetIsMemberByIndex(&SetOnline, iCpu)) { RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu); RTTestIPrintf(RTTESTLVL_ALWAYS, "%2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu), RTMpIsCpuOnline(idCpu) ? "online" : "offline"); if (!RTCpuSetIsMemberByIndex(&Set, iCpu)) RTTestIFailed("online cpu with index %2d is not a member of the possible cpu set!\n", iCpu); } /* There isn't any sane way of testing RTMpIsCpuOnline really... :-/ */ } else RTTestIFailed("RTMpGetOnlineSet -> %p, expected %p\n", pSet, &Set); /* * Present CPUs. */ RTCPUID cCpusPresent = RTMpGetPresentCount(); if (cCpusPresent > 0) { if ( cCpusPresent <= cCpus && cCpusPresent >= cCpusOnline) RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetPresentCount -> %d\n", (int)cCpusPresent); else RTTestIFailed("RTMpGetPresentCount -> %d, expected <= %d and >= %d\n", (int)cCpusPresent, (int)cCpus, (int)cCpusOnline); } else { RTTestIFailed("RTMpGetPresentCount -> %d\n", (int)cCpusPresent); cCpusPresent = 1; } RTCPUSET SetPresent; pSet = RTMpGetPresentSet(&SetPresent); if (pSet == &SetPresent) { if (RTCpuSetCount(&SetPresent) <= 0) RTTestIFailed("RTMpGetPresentSet returned an empty set!\n"); else if ((RTCPUID)RTCpuSetCount(&SetPresent) != cCpusPresent) RTTestIFailed("RTMpGetPresentSet returned a bad value; %d, expected = %d\n", RTCpuSetCount(&SetPresent), cCpusPresent); RTTestIPrintf(RTTESTLVL_ALWAYS, "Present CPU mask:\n"); for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) if (RTCpuSetIsMemberByIndex(&SetPresent, iCpu)) { RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu); RTTestIPrintf(RTTESTLVL_ALWAYS, "%2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu), RTMpIsCpuPresent(idCpu) ? "present" : "absent"); if (!RTCpuSetIsMemberByIndex(&Set, iCpu)) RTTestIFailed("online cpu with index %2d is not a member of the possible cpu set!\n", iCpu); } /* There isn't any sane way of testing RTMpIsCpuPresent really... :-/ */ } else RTTestIFailed("RTMpGetPresentSet -> %p, expected %p\n", pSet, &Set); /* Find an online cpu for the next test. */ RTCPUID idCpuOnline; for (idCpuOnline = 0; idCpuOnline < RTCPUSET_MAX_CPUS; idCpuOnline++) if (RTMpIsCpuOnline(idCpuOnline)) break; /* * Quick test of RTMpGetDescription. */ char szBuf[64]; int rc = RTMpGetDescription(idCpuOnline, &szBuf[0], sizeof(szBuf)); if (RT_SUCCESS(rc)) { RTTestIPrintf(RTTESTLVL_ALWAYS, "RTMpGetDescription -> '%s'\n", szBuf); size_t cch = strlen(szBuf); rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch); if (rc != VERR_BUFFER_OVERFLOW) RTTestIFailed("RTMpGetDescription -> %Rrc, expected VERR_BUFFER_OVERFLOW\n", rc); rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch + 1); if (RT_FAILURE(rc)) RTTestIFailed("RTMpGetDescription -> %Rrc, expected VINF_SUCCESS\n", rc); } else RTTestIFailed("RTMpGetDescription -> %Rrc\n", rc); return RTTestSummaryAndDestroy(hTest); }
DECLHIDDEN(int) rtR0InitNative(void) { /* * Init the Nt cpu set. */ #ifdef IPRT_TARGET_NT4 KAFFINITY ActiveProcessors = (UINT64_C(1) << KeNumberProcessors) - UINT64_C(1); #else KAFFINITY ActiveProcessors = KeQueryActiveProcessors(); #endif RTCpuSetEmpty(&g_rtMpNtCpuSet); RTCpuSetFromU64(&g_rtMpNtCpuSet, ActiveProcessors); /** @todo Port to W2K8 with > 64 cpus/threads. */ /* * Initialize the function pointers. */ #ifdef IPRT_TARGET_NT4 g_pfnrtNtExSetTimerResolution = NULL; g_pfnrtNtKeFlushQueuedDpcs = NULL; g_pfnrtHalRequestIpiW7Plus = NULL; g_pfnrtHalRequestIpiPreW7 = NULL; g_pfnrtNtHalSendSoftwareInterrupt = NULL; g_pfnrtKeIpiGenericCall = NULL; g_pfnrtKeInitializeAffinityEx = NULL; g_pfnrtKeAddProcessorAffinityEx = NULL; g_pfnrtKeGetProcessorIndexFromNumber = NULL; g_pfnrtRtlGetVersion = NULL; g_pfnrtKeQueryInterruptTime = NULL; g_pfnrtKeQueryInterruptTimePrecise = NULL; g_pfnrtKeQuerySystemTime = NULL; g_pfnrtKeQuerySystemTimePrecise = NULL; #else UNICODE_STRING RoutineName; RtlInitUnicodeString(&RoutineName, L"ExSetTimerResolution"); g_pfnrtNtExSetTimerResolution = (PFNMYEXSETTIMERRESOLUTION)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeFlushQueuedDpcs"); g_pfnrtNtKeFlushQueuedDpcs = (PFNMYKEFLUSHQUEUEDDPCS)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"HalRequestIpi"); g_pfnrtHalRequestIpiW7Plus = (PFNHALREQUESTIPI_W7PLUS)MmGetSystemRoutineAddress(&RoutineName); g_pfnrtHalRequestIpiPreW7 = (PFNHALREQUESTIPI_PRE_W7)g_pfnrtHalRequestIpiW7Plus; RtlInitUnicodeString(&RoutineName, L"HalSendSoftwareInterrupt"); g_pfnrtNtHalSendSoftwareInterrupt = (PFNHALSENDSOFTWAREINTERRUPT)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeIpiGenericCall"); g_pfnrtKeIpiGenericCall = (PFNRTKEIPIGENERICCALL)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeInitializeAffinityEx"); g_pfnrtKeInitializeAffinityEx = (PFNKEINITIALIZEAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeAddProcessorAffinityEx"); g_pfnrtKeAddProcessorAffinityEx = (PFNKEADDPROCESSORAFFINITYEX)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeGetProcessorIndexFromNumber"); g_pfnrtKeGetProcessorIndexFromNumber = (PFNKEGETPROCESSORINDEXFROMNUMBER)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"RtlGetVersion"); g_pfnrtRtlGetVersion = (PFNRTRTLGETVERSION)MmGetSystemRoutineAddress(&RoutineName); # ifndef RT_ARCH_AMD64 RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTime"); g_pfnrtKeQueryInterruptTime = (PFNRTKEQUERYINTERRUPTTIME)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTime"); g_pfnrtKeQuerySystemTime = (PFNRTKEQUERYSYSTEMTIME)MmGetSystemRoutineAddress(&RoutineName); # endif RtlInitUnicodeString(&RoutineName, L"KeQueryInterruptTimePrecise"); g_pfnrtKeQueryInterruptTimePrecise = (PFNRTKEQUERYINTERRUPTTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName); RtlInitUnicodeString(&RoutineName, L"KeQuerySystemTimePrecise"); g_pfnrtKeQuerySystemTimePrecise = (PFNRTKEQUERYSYSTEMTIMEPRECISE)MmGetSystemRoutineAddress(&RoutineName); #endif /* * HACK ALERT! (and déjà vu warning - remember win32k.sys?) * * Try find _KPRCB::QuantumEnd and _KPRCB::[DpcData.]DpcQueueDepth. * For purpose of verification we use the VendorString member (12+1 chars). * * The offsets was initially derived by poking around with windbg * (dt _KPRCB, !prcb ++, and such like). Systematic harvesting was then * planned using dia2dump, grep and the symbol pack in a manner like this: * dia2dump -type _KDPC_DATA -type _KPRCB EXE\ntkrnlmp.pdb | grep -wE "QuantumEnd|DpcData|DpcQueueDepth|VendorString" * * The final solution ended up using a custom harvester program called * ntBldSymDb that recursively searches thru unpacked symbol packages for * the desired structure offsets. The program assumes that the packages * are unpacked into directories with the same name as the package, with * exception of some of the w2k packages which requires a 'w2k' prefix to * be distinguishable from another. */ RTNTSDBOSVER OsVerInfo; rtR0NtGetOsVersionInfo(&OsVerInfo); /* * Gather consistent CPU vendor string and PRCB pointers. */ KIRQL OldIrql; KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); /* make sure we stay on the same cpu */ union { uint32_t auRegs[4]; char szVendor[4*3+1]; } u; ASMCpuId(0, &u.auRegs[3], &u.auRegs[0], &u.auRegs[2], &u.auRegs[1]); u.szVendor[4*3] = '\0'; uint8_t *pbPrcb; __try /* Warning. This try/except statement may provide some false safety. */ { #if defined(RT_ARCH_X86) PKPCR pPcr = (PKPCR)__readfsdword(RT_OFFSETOF(KPCR,SelfPcr)); pbPrcb = (uint8_t *)pPcr->Prcb; #elif defined(RT_ARCH_AMD64) PKPCR pPcr = (PKPCR)__readgsqword(RT_OFFSETOF(KPCR,Self)); pbPrcb = (uint8_t *)pPcr->CurrentPrcb; #else # error "port me" pbPrcb = NULL; #endif } __except(EXCEPTION_EXECUTE_HANDLER) { pbPrcb = NULL; } /* * Search the database */ if (pbPrcb) { /* Find the best matching kernel version based on build number. */ uint32_t iBest = UINT32_MAX; int32_t iBestDelta = INT32_MAX; for (uint32_t i = 0; i < RT_ELEMENTS(g_artNtSdbSets); i++) { if (g_artNtSdbSets[i].OsVerInfo.fChecked != OsVerInfo.fChecked) continue; if (OsVerInfo.fSmp /*must-be-smp*/ && !g_artNtSdbSets[i].OsVerInfo.fSmp) continue; int32_t iDelta = RT_ABS((int32_t)OsVerInfo.uBuildNo - (int32_t)g_artNtSdbSets[i].OsVerInfo.uBuildNo); if ( iDelta == 0 && (g_artNtSdbSets[i].OsVerInfo.uCsdNo == OsVerInfo.uCsdNo || OsVerInfo.uCsdNo == MY_NIL_CSD)) { /* prefect */ iBestDelta = iDelta; iBest = i; break; } if ( iDelta < iBestDelta || iBest == UINT32_MAX || ( iDelta == iBestDelta && OsVerInfo.uCsdNo != MY_NIL_CSD && RT_ABS(g_artNtSdbSets[i ].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo) < RT_ABS(g_artNtSdbSets[iBest].OsVerInfo.uCsdNo - (int32_t)OsVerInfo.uCsdNo) ) ) { iBestDelta = iDelta; iBest = i; } } if (iBest < RT_ELEMENTS(g_artNtSdbSets)) { /* Try all sets: iBest -> End; iBest -> Start. */ bool fDone = false; int32_t i = iBest; while ( i < RT_ELEMENTS(g_artNtSdbSets) && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo))) i++; if (!fDone) { i = (int32_t)iBest - 1; while ( i >= 0 && !(fDone = rtR0NtTryMatchSymSet(&g_artNtSdbSets[i], pbPrcb, u.szVendor, &OsVerInfo))) i--; } } else DbgPrint("IPRT: Failed to locate data set.\n"); } else DbgPrint("IPRT: Failed to get PCBR pointer.\n"); KeLowerIrql(OldIrql); /* Lowering the IRQL early in the hope that we may catch exceptions below. */ #ifndef IN_GUEST if (!g_offrtNtPbQuantumEnd && !g_offrtNtPbDpcQueueDepth) DbgPrint("IPRT: Neither _KPRCB::QuantumEnd nor _KPRCB::DpcQueueDepth was not found! Kernel %u.%u %u %s\n", OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free"); # ifdef DEBUG else DbgPrint("IPRT: _KPRCB:{.QuantumEnd=%x/%d, .DpcQueueDepth=%x/%d} Kernel %u.%u %u %s\n", g_offrtNtPbQuantumEnd, g_cbrtNtPbQuantumEnd, g_offrtNtPbDpcQueueDepth, OsVerInfo.uMajorVer, OsVerInfo.uMinorVer, OsVerInfo.uBuildNo, OsVerInfo.fChecked ? "checked" : "free"); # endif #endif /* * Special IPI fun for RTMpPokeCpu. * * On Vista and later the DPC method doesn't seem to reliably send IPIs, * so we have to use alternative methods. The NtHalSendSoftwareInterrupt * is preferrable, but it's AMD64 only. The NalRequestIpip method changed * in Windows 7 with the lots-of-processors-support, but it's the only * targeted IPI game in town if we cannot use KeInsertQueueDpc. Worst case * we use broadcast IPIs. */ if ( OsVerInfo.uMajorVer > 6 || (OsVerInfo.uMajorVer == 6 && OsVerInfo.uMinorVer > 0)) g_pfnrtHalRequestIpiPreW7 = NULL; else g_pfnrtHalRequestIpiW7Plus = NULL; g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingDpc; #ifndef IPRT_TARGET_NT4 if (g_pfnrtNtHalSendSoftwareInterrupt) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalSendSoftwareInterrupt; else if ( g_pfnrtHalRequestIpiW7Plus && g_pfnrtKeInitializeAffinityEx && g_pfnrtKeAddProcessorAffinityEx && g_pfnrtKeGetProcessorIndexFromNumber) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingHalReqestIpiW7Plus; else if (OsVerInfo.uMajorVer >= 6 && g_pfnrtKeIpiGenericCall) g_pfnrtMpPokeCpuWorker = rtMpPokeCpuUsingBroadcastIpi; /* else: Windows XP should send always send an IPI -> VERIFY */ #endif return VINF_SUCCESS; }
int main() { RTR3InitExeNoArguments(0); RTPrintf("tstMp-1: TESTING...\n"); /* * Present and possible CPUs. */ RTCPUID cCpus = RTMpGetCount(); if (cCpus > 0) RTPrintf("tstMp-1: RTMpGetCount -> %d\n", (int)cCpus); else { RTPrintf("tstMp-1: FAILURE: RTMpGetCount -> %d\n", (int)cCpus); g_cErrors++; cCpus = 1; } RTCPUSET Set; PRTCPUSET pSet = RTMpGetSet(&Set); if (pSet == &Set) { if ((RTCPUID)RTCpuSetCount(&Set) != cCpus) { RTPrintf("tstMp-1: FAILURE: RTMpGetSet returned a set with a different cpu count; %d, expected %d\n", RTCpuSetCount(&Set), cCpus); g_cErrors++; } RTPrintf("tstMp-1: Possible CPU mask:\n"); for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) { RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu); if (RTCpuSetIsMemberByIndex(&Set, iCpu)) { RTPrintf("tstMp-1: %2d - id %d: %u/%u MHz", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu)); if (RTMpIsCpuPresent(idCpu)) RTPrintf(RTMpIsCpuOnline(idCpu) ? " online\n" : " offline\n"); else { if (!RTMpIsCpuOnline(idCpu)) RTPrintf(" absent\n"); else { RTPrintf(" online but absent!\n"); RTPrintf("tstMp-1: FAILURE: Cpu with index %d is report as !RTIsCpuPresent while RTIsCpuOnline returns true!\n", iCpu); g_cErrors++; } } if (!RTMpIsCpuPossible(idCpu)) { RTPrintf("tstMp-1: FAILURE: Cpu with index %d is returned by RTCpuSet but not RTMpIsCpuPossible!\n", iCpu); g_cErrors++; } } else if (RTMpIsCpuPossible(idCpu)) { RTPrintf("tstMp-1: FAILURE: Cpu with index %d is returned by RTMpIsCpuPossible but not RTCpuSet!\n", iCpu); g_cErrors++; } else if (RTMpGetCurFrequency(idCpu) != 0) { RTPrintf("tstMp-1: FAILURE: RTMpGetCurFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu); g_cErrors++; } else if (RTMpGetMaxFrequency(idCpu) != 0) { RTPrintf("tstMp-1: FAILURE: RTMpGetMaxFrequency(%d[idx=%d]) didn't return 0 as it should\n", (int)idCpu, iCpu); g_cErrors++; } } } else { RTPrintf("tstMp-1: FAILURE: RTMpGetSet -> %p, expected %p\n", pSet, &Set); g_cErrors++; RTCpuSetEmpty(&Set); RTCpuSetAdd(&Set, RTMpCpuIdFromSetIndex(0)); } /* * Online CPUs. */ RTCPUID cCpusOnline = RTMpGetOnlineCount(); if (cCpusOnline > 0) { if (cCpusOnline <= cCpus) RTPrintf("tstMp-1: RTMpGetOnlineCount -> %d\n", (int)cCpusOnline); else { RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineCount -> %d, expected <= %d\n", (int)cCpusOnline, (int)cCpus); g_cErrors++; cCpusOnline = cCpus; } } else { RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineCount -> %d\n", (int)cCpusOnline); g_cErrors++; cCpusOnline = 1; } RTCPUSET SetOnline; pSet = RTMpGetOnlineSet(&SetOnline); if (pSet == &SetOnline) { if (RTCpuSetCount(&SetOnline) <= 0) { RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineSet returned an empty set!\n"); g_cErrors++; } else if ((RTCPUID)RTCpuSetCount(&SetOnline) > cCpus) { RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineSet returned a too high value; %d, expected <= %d\n", RTCpuSetCount(&SetOnline), cCpus); g_cErrors++; } RTPrintf("tstMp-1: Online CPU mask:\n"); for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) if (RTCpuSetIsMemberByIndex(&SetOnline, iCpu)) { RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu); RTPrintf("tstMp-1: %2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu), RTMpIsCpuOnline(idCpu) ? "online" : "offline"); if (!RTCpuSetIsMemberByIndex(&Set, iCpu)) { RTPrintf("tstMp-1: FAILURE: online cpu with index %2d is not a member of the possible cpu set!\n", iCpu); g_cErrors++; } } /* There isn't any sane way of testing RTMpIsCpuOnline really... :-/ */ } else { RTPrintf("tstMp-1: FAILURE: RTMpGetOnlineSet -> %p, expected %p\n", pSet, &Set); g_cErrors++; } /* * Present CPUs. */ RTCPUID cCpusPresent = RTMpGetPresentCount(); if (cCpusPresent > 0) { if ( cCpusPresent <= cCpus && cCpusPresent >= cCpusOnline) RTPrintf("tstMp-1: RTMpGetPresentCount -> %d\n", (int)cCpusPresent); else { RTPrintf("tstMp-1: FAILURE: RTMpGetPresentCount -> %d, expected <= %d and >= %d\n", (int)cCpusPresent, (int)cCpus, (int)cCpusOnline); g_cErrors++; } } else { RTPrintf("tstMp-1: FAILURE: RTMpGetPresentCount -> %d\n", (int)cCpusPresent); g_cErrors++; cCpusPresent = 1; } RTCPUSET SetPresent; pSet = RTMpGetPresentSet(&SetPresent); if (pSet == &SetPresent) { if (RTCpuSetCount(&SetPresent) <= 0) { RTPrintf("tstMp-1: FAILURE: RTMpGetPresentSet returned an empty set!\n"); g_cErrors++; } else if ((RTCPUID)RTCpuSetCount(&SetPresent) != cCpusPresent) { RTPrintf("tstMp-1: FAILURE: RTMpGetPresentSet returned a bad value; %d, expected = %d\n", RTCpuSetCount(&SetPresent), cCpusPresent); g_cErrors++; } RTPrintf("tstMp-1: Present CPU mask:\n"); for (int iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++) if (RTCpuSetIsMemberByIndex(&SetPresent, iCpu)) { RTCPUID idCpu = RTMpCpuIdFromSetIndex(iCpu); RTPrintf("tstMp-1: %2d - id %d: %u/%u MHz %s\n", iCpu, (int)idCpu, RTMpGetCurFrequency(idCpu), RTMpGetMaxFrequency(idCpu), RTMpIsCpuPresent(idCpu) ? "present" : "absent"); if (!RTCpuSetIsMemberByIndex(&Set, iCpu)) { RTPrintf("tstMp-1: FAILURE: online cpu with index %2d is not a member of the possible cpu set!\n", iCpu); g_cErrors++; } } /* There isn't any sane way of testing RTMpIsCpuPresent really... :-/ */ } else { RTPrintf("tstMp-1: FAILURE: RTMpGetPresentSet -> %p, expected %p\n", pSet, &Set); g_cErrors++; } /* Find an online cpu for the next test. */ RTCPUID idCpuOnline; for (idCpuOnline = 0; idCpuOnline < RTCPUSET_MAX_CPUS; idCpuOnline++) if (RTMpIsCpuOnline(idCpuOnline)) break; /* * Quick test of RTMpGetDescription. */ char szBuf[64]; int rc = RTMpGetDescription(idCpuOnline, &szBuf[0], sizeof(szBuf)); if (RT_SUCCESS(rc)) { RTPrintf("tstMp-1: RTMpGetDescription -> '%s'\n", szBuf); size_t cch = strlen(szBuf); rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch); if (rc != VERR_BUFFER_OVERFLOW) { RTPrintf("tstMp-1: FAILURE: RTMpGetDescription -> %Rrc, expected VERR_BUFFER_OVERFLOW\n", rc); g_cErrors++; } rc = RTMpGetDescription(idCpuOnline, &szBuf[0], cch + 1); if (RT_FAILURE(rc)) { RTPrintf("tstMp-1: FAILURE: RTMpGetDescription -> %Rrc, expected VINF_SUCCESS\n", rc); g_cErrors++; } } else { RTPrintf("tstMp-1: FAILURE: RTMpGetDescription -> %Rrc\n", rc); g_cErrors++; } if (!g_cErrors) RTPrintf("tstMp-1: SUCCESS\n", g_cErrors); else RTPrintf("tstMp-1: FAILURE - %d errors\n", g_cErrors); return !!g_cErrors; }
RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet) { RTOnce(&g_MpInitOnce, rtMpWinInitOnce, NULL); #ifdef IPRT_WITH_GIP_MP_INFO RTMPWIN_UPDATE_GIP_GLOBALS_AND_GET_PGIP(); if (pGip) { *pSet = pGip->OnlineCpuSet; return pSet; } #endif if (g_pfnGetLogicalProcessorInformationEx) { /* * Get the group relation info. * * In addition to the ASSUMPTIONS that are documented in rtMpWinInitOnce, * we ASSUME that PROCESSOR_GROUP_INFO::MaximumProcessorCount gives the * active processor mask width. */ /** @todo this is not correct for WOW64 */ DWORD cbInfo = g_cbRtMpWinGrpRelBuf; SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pInfo = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)alloca(cbInfo); AssertFatalMsg(g_pfnGetLogicalProcessorInformationEx(RelationGroup, pInfo, &cbInfo) != FALSE, ("last error = %u, cbInfo = %u (in %u)\n", GetLastError(), cbInfo, g_cbRtMpWinGrpRelBuf)); AssertFatalMsg(pInfo->Relationship == RelationGroup, ("Relationship = %u, expected %u!\n", pInfo->Relationship, RelationGroup)); AssertFatalMsg(pInfo->Group.MaximumGroupCount == g_cRtMpWinMaxCpuGroups, ("MaximumGroupCount is %u, expected %u!\n", pInfo->Group.MaximumGroupCount, g_cRtMpWinMaxCpuGroups)); RTCpuSetEmpty(pSet); for (uint32_t idxGroup = 0; idxGroup < pInfo->Group.MaximumGroupCount; idxGroup++) { Assert(pInfo->Group.GroupInfo[idxGroup].MaximumProcessorCount == g_aRtMpWinCpuGroups[idxGroup].cMaxCpus); Assert(pInfo->Group.GroupInfo[idxGroup].ActiveProcessorCount <= g_aRtMpWinCpuGroups[idxGroup].cMaxCpus); KAFFINITY fActive = pInfo->Group.GroupInfo[idxGroup].ActiveProcessorMask; if (fActive != 0) { #ifdef RT_STRICT uint32_t cMembersLeft = pInfo->Group.GroupInfo[idxGroup].ActiveProcessorCount; #endif int const cMembers = g_aRtMpWinCpuGroups[idxGroup].cMaxCpus; for (int idxMember = 0; idxMember < cMembers; idxMember++) { if (fActive & 1) { #ifdef RT_STRICT cMembersLeft--; #endif RTCpuSetAddByIndex(pSet, g_aRtMpWinCpuGroups[idxGroup].aidxCpuSetMembers[idxMember]); fActive >>= 1; if (!fActive) break; } else { fActive >>= 1; } } Assert(cMembersLeft == 0); }