RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { int rc; RTMPARGS Args; Args.pfnWorker = pfnWorker; Args.pvUser1 = pvUser1; Args.pvUser2 = pvUser2; Args.idCpu = NIL_RTCPUID; Args.cHits = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) rc = on_each_cpu(rtmpLinuxWrapper, &Args, 1 /* wait */); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) rc = on_each_cpu(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); #else /* older kernels */ # ifdef preempt_disable preempt_disable(); # endif rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); local_irq_disable(); rtmpLinuxWrapper(&Args); local_irq_enable(); # ifdef preempt_enable preempt_enable(); # endif #endif /* older kernels */ Assert(rc == 0); NOREF(rc); return VINF_SUCCESS; }
RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { int rc; RTMPARGS Args; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER; #endif Args.pfnWorker = pfnWorker; Args.pvUser1 = pvUser1; Args.pvUser2 = pvUser2; Args.idCpu = NIL_RTCPUID; Args.cHits = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) rc = on_each_cpu(rtmpLinuxWrapper, &Args, 1 /* wait */); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) rc = on_each_cpu(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); #else /* older kernels */ RTThreadPreemptDisable(&PreemptState); rc = smp_call_function(rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); local_irq_disable(); rtmpLinuxWrapper(&Args); local_irq_enable(); RTThreadPreemptRestore(&PreemptState); #endif /* older kernels */ Assert(rc == 0); NOREF(rc); return VINF_SUCCESS; }
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { int rc; RTMPARGS Args; Args.pfnWorker = pfnWorker; Args.pvUser1 = pvUser1; Args.pvUser2 = pvUser2; Args.idCpu = idCpu; Args.cHits = 0; if (!RTMpIsCpuPossible(idCpu)) return VERR_CPU_NOT_FOUND; # ifdef preempt_disable preempt_disable(); # endif if (idCpu != RTMpCpuId()) { if (RTMpIsCpuOnline(idCpu)) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 1 /* wait */); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); #else /* older kernels */ rc = smp_call_function(rtmpOnSpecificLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); #endif /* older kernels */ Assert(rc == 0); rc = Args.cHits ? VINF_SUCCESS : VERR_CPU_OFFLINE; } else rc = VERR_CPU_OFFLINE; } else { rtmpLinuxWrapper(&Args); rc = VINF_SUCCESS; } # ifdef preempt_enable preempt_enable(); # endif NOREF(rc); return rc; }
RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { IPRT_LINUX_SAVE_EFL_AC(); int rc; RTMPARGS Args; RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER; Args.pfnWorker = pfnWorker; Args.pvUser1 = pvUser1; Args.pvUser2 = pvUser2; Args.idCpu = idCpu; Args.cHits = 0; if (!RTMpIsCpuPossible(idCpu)) return VERR_CPU_NOT_FOUND; RTThreadPreemptDisable(&PreemptState); if (idCpu != RTMpCpuId()) { if (RTMpIsCpuOnline(idCpu)) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 1 /* wait */); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19) rc = smp_call_function_single(idCpu, rtmpLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); #else /* older kernels */ rc = smp_call_function(rtmpOnSpecificLinuxWrapper, &Args, 0 /* retry */, 1 /* wait */); #endif /* older kernels */ Assert(rc == 0); rc = Args.cHits ? VINF_SUCCESS : VERR_CPU_OFFLINE; } else rc = VERR_CPU_OFFLINE; } else { rtmpLinuxWrapper(&Args); rc = VINF_SUCCESS; } RTThreadPreemptRestore(&PreemptState);; NOREF(rc); IPRT_LINUX_RESTORE_EFL_AC(); return rc; }
RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2) { IPRT_LINUX_SAVE_EFL_AC(); int rc; RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER; AssertReturn(idCpu1 != idCpu2, VERR_INVALID_PARAMETER); AssertReturn(!(fFlags & RTMPON_F_VALID_MASK), VERR_INVALID_FLAGS); /* * Check that both CPUs are online before doing the broadcast call. */ RTThreadPreemptDisable(&PreemptState); if ( RTMpIsCpuOnline(idCpu1) && RTMpIsCpuOnline(idCpu2)) { /* * Use the smp_call_function variant taking a cpu mask where available, * falling back on broadcast with filter. Slight snag if one of the * CPUs is the one we're running on, we must do the call and the post * call wait ourselves. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) cpumask_t DstCpuMask; #endif RTCPUID idCpuSelf = RTMpCpuId(); bool const fCallSelf = idCpuSelf == idCpu1 || idCpuSelf == idCpu2; RTMPARGS Args; Args.pfnWorker = pfnWorker; Args.pvUser1 = pvUser1; Args.pvUser2 = pvUser2; Args.idCpu = idCpu1; Args.idCpu2 = idCpu2; Args.cHits = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) cpumask_clear(&DstCpuMask); cpumask_set_cpu(idCpu1, &DstCpuMask); cpumask_set_cpu(idCpu2, &DstCpuMask); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) cpus_clear(DstCpuMask); cpu_set(idCpu1, DstCpuMask); cpu_set(idCpu2, DstCpuMask); #endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) smp_call_function_many(&DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */); rc = 0; #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) rc = smp_call_function_many(&DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */); #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) rc = smp_call_function_mask(DstCpuMask, rtmpLinuxWrapperPostInc, &Args, !fCallSelf /* wait */); #else /* older kernels */ rc = smp_call_function(rtMpLinuxOnPairWrapper, &Args, 0 /* retry */, !fCallSelf /* wait */); #endif /* older kernels */ Assert(rc == 0); /* Call ourselves if necessary and wait for the other party to be done. */ if (fCallSelf) { uint32_t cLoops = 0; rtmpLinuxWrapper(&Args); while (ASMAtomicReadU32(&Args.cHits) < 2) { if ((cLoops & 0x1ff) == 0 && !RTMpIsCpuOnline(idCpuSelf == idCpu1 ? idCpu2 : idCpu1)) break; cLoops++; ASMNopPause(); } } Assert(Args.cHits <= 2); if (Args.cHits == 2) rc = VINF_SUCCESS; else if (Args.cHits == 1) rc = VERR_NOT_ALL_CPUS_SHOWED; else if (Args.cHits == 0) rc = VERR_CPU_OFFLINE; else rc = VERR_CPU_IPE_1; } /* * A CPU must be present to be considered just offline. */ else if ( RTMpIsCpuPresent(idCpu1) && RTMpIsCpuPresent(idCpu2)) rc = VERR_CPU_OFFLINE; else rc = VERR_CPU_NOT_FOUND; RTThreadPreemptRestore(&PreemptState);; IPRT_LINUX_RESTORE_EFL_AC(); return rc; }