VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/darwin/mp-r0drv-darwin.cpp

Last change on this file was 109171, checked in by vboxsync, 12 days ago

IPRT/mp-r0drv-darwin.cpp: Reimplemented RTMpOnPair and RTMpOnSpecific on arm to use cpu_xcall, since the broadcast approach doesn't work all that well, especially for RTMpOnPair, when RTMpIsCpuOnline isn't returning the right status and would in any case be subject to a race condition. [fix v2] jiraref:VBP-1653

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.5 KB
Line 
1/* $Id: mp-r0drv-darwin.cpp 109171 2025-05-06 09:48:39Z vboxsync $ */
2/** @file
3 * IPRT - Multiprocessor, Ring-0 Driver, Darwin.
4 */
5
6/*
7 * Copyright (C) 2008-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "the-darwin-kernel.h"
42#include "internal/iprt.h"
43#include <iprt/mp.h>
44
45#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
46# include <iprt/asm-amd64-x86.h>
47#else
48# include <iprt/thread.h>
49#endif
50#include <iprt/cpuset.h>
51#include <iprt/err.h>
52#include "r0drv/mp-r0drv.h"
53
54
55/*********************************************************************************************************************************
56* Global Variables *
57*********************************************************************************************************************************/
58static int32_t volatile g_cMaxCpus = -1;
59
60
61static int rtMpDarwinInitMaxCpus(void)
62{
63 IPRT_DARWIN_SAVE_EFL_AC();
64
65 int32_t cCpus = -1;
66 size_t oldLen = sizeof(cCpus);
67 int rc = sysctlbyname("hw.ncpu", &cCpus, &oldLen, NULL, NULL);
68 if (rc)
69 {
70 printf("IPRT: sysctlbyname(hw.ncpu) failed with rc=%d!\n", rc);
71 cCpus = 64; /* whatever */
72 }
73
74 ASMAtomicWriteS32(&g_cMaxCpus, cCpus);
75
76 IPRT_DARWIN_RESTORE_EFL_AC();
77 return cCpus;
78}
79
80
81DECLINLINE(int) rtMpDarwinMaxCpus(void)
82{
83 int cCpus = g_cMaxCpus;
84 if (RT_UNLIKELY(cCpus <= 0))
85 return rtMpDarwinInitMaxCpus();
86 return cCpus;
87}
88
89
90RTDECL(RTCPUID) RTMpCpuId(void)
91{
92 return cpu_number();
93}
94
95
96RTDECL(int) RTMpCurSetIndex(void)
97{
98 return cpu_number();
99}
100
101
102RTDECL(int) RTMpCurSetIndexAndId(PRTCPUID pidCpu)
103{
104 return *pidCpu = cpu_number();
105}
106
107
108RTDECL(int) RTMpCpuIdToSetIndex(RTCPUID idCpu)
109{
110 return idCpu < RTCPUSET_MAX_CPUS ? (int)idCpu : -1;
111}
112
113
114RTDECL(RTCPUID) RTMpCpuIdFromSetIndex(int iCpu)
115{
116 return (unsigned)iCpu < RTCPUSET_MAX_CPUS ? (RTCPUID)iCpu : NIL_RTCPUID;
117}
118
119
120RTDECL(RTCPUID) RTMpGetMaxCpuId(void)
121{
122 return rtMpDarwinMaxCpus() - 1;
123}
124
125
126RTDECL(bool) RTMpIsCpuPossible(RTCPUID idCpu)
127{
128 return idCpu < RTCPUSET_MAX_CPUS
129 && idCpu < (RTCPUID)rtMpDarwinMaxCpus();
130}
131
132
133RTDECL(PRTCPUSET) RTMpGetSet(PRTCPUSET pSet)
134{
135 RTCPUID idCpu;
136
137 RTCpuSetEmpty(pSet);
138 idCpu = RTMpGetMaxCpuId();
139 do
140 {
141 if (RTMpIsCpuPossible(idCpu))
142 RTCpuSetAdd(pSet, idCpu);
143 } while (idCpu-- > 0);
144 return pSet;
145}
146
147
148RTDECL(RTCPUID) RTMpGetCount(void)
149{
150 return rtMpDarwinMaxCpus();
151}
152
153
154RTDECL(PRTCPUSET) RTMpGetOnlineSet(PRTCPUSET pSet)
155{
156 /** @todo darwin R0 MP */
157 return RTMpGetSet(pSet);
158}
159
160
161RTDECL(RTCPUID) RTMpGetOnlineCount(void)
162{
163 /** @todo darwin R0 MP */
164 /** @todo this is getting worse with M3 Max and 14.x, where we're not able to
165 * RTMpOnAll/Specific on a bunch of performance cores when idle.
166 * Note: We can probably get the processor_t via IOCPU and IOKit. Doubt the
167 * state is of much use there, but it may, though not for the SIGPdisabled. */
168 return RTMpGetCount();
169}
170
171
172RTDECL(bool) RTMpIsCpuOnline(RTCPUID idCpu)
173{
174 /** @todo darwin R0 MP */
175 /** @todo this is getting worse with M3 Max and 14.x, where we're not able to
176 * RTMpOnAll/Specific on a bunch of performance cores when idle. */
177 return RTMpIsCpuPossible(idCpu);
178}
179
180
181RTDECL(uint32_t) RTMpGetCurFrequency(RTCPUID idCpu)
182{
183 /** @todo darwin R0 MP (rainy day) */
184 RT_NOREF(idCpu);
185 return 0;
186}
187
188
189RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu)
190{
191 /** @todo darwin R0 MP (rainy day) */
192 RT_NOREF(idCpu);
193 return 0;
194}
195
196
197RTDECL(bool) RTMpIsCpuWorkPending(void)
198{
199 /** @todo (not used on non-Windows platforms yet). */
200 return false;
201}
202
203
204/**
205 * Wrapper between the native darwin per-cpu callback and PFNRTWORKER
206 * for the RTMpOnAll API.
207 *
208 * @param pvArg Pointer to the RTMPARGS package.
209 */
210static void rtmpOnAllDarwinWrapper(void *pvArg)
211{
212 PRTMPARGS const pArgs = (PRTMPARGS)pvArg;
213 IPRT_DARWIN_SAVE_EFL_AC();
214 pArgs->pfnWorker(cpu_number(), pArgs->pvUser1, pArgs->pvUser2);
215 IPRT_DARWIN_RESTORE_EFL_AC();
216
217#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
218 /* Wake up the thread calling RTMpOnAll if we're the last CPU out of here: */
219 if (ASMAtomicDecU32(&pArgs->cCpusLeftSynch) == 0)
220 thread_wakeup((event_t)&pArgs->cCpusLeftSynch);
221#endif
222}
223
224
225RTDECL(int) RTMpOnAll(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
226{
227 RT_ASSERT_INTS_ON();
228 IPRT_DARWIN_SAVE_EFL_AC();
229
230 RTMPARGS Args;
231 Args.pfnWorker = pfnWorker;
232 Args.pvUser1 = pvUser1;
233 Args.pvUser2 = pvUser2;
234 Args.idCpu = NIL_RTCPUID;
235 Args.cHits = 0;
236
237#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
238 mp_rendezvous_no_intrs(rtmpOnAllDarwinWrapper, &Args);
239
240#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
241 Args.cCpusLeftSynch = 0;
242 if (g_pfnR0DarwinCpuBroadcastXCall && g_pfnR0DarwinCpuNumberMayBeNull)
243 g_pfnR0DarwinCpuBroadcastXCall(&Args.cCpusLeftSynch, TRUE /*fCallSelf*/, rtmpOnAllDarwinWrapper, &Args);
244 else
245 return VERR_NOT_IMPLEMENTED;
246
247#else
248# error "port me"
249#endif
250
251 IPRT_DARWIN_RESTORE_EFL_AC();
252 return VINF_SUCCESS;
253}
254
255
256/**
257 * Wrapper between the native darwin per-cpu callback and PFNRTWORKER
258 * for the RTMpOnOthers API.
259 *
260 * @param pvArg Pointer to the RTMPARGS package.
261 */
262static void rtmpOnOthersDarwinWrapper(void *pvArg)
263{
264 PRTMPARGS const pArgs = (PRTMPARGS)pvArg;
265 RTCPUID const idCpu = cpu_number();
266#if !defined(RT_ARCH_ARM64) && !defined(RT_ARCH_ARM32) /* cpu_broadcast_xcall filters for us */
267 if (pArgs->idCpu != idCpu)
268#endif
269 {
270 IPRT_DARWIN_SAVE_EFL_AC();
271 pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
272 IPRT_DARWIN_RESTORE_EFL_AC();
273 }
274
275#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
276 /* Wake up the thread calling RTMpOnOthers if we're the last CPU out of here: */
277 if (ASMAtomicDecU32(&pArgs->cCpusLeftSynch) == 0)
278 thread_wakeup((event_t)&pArgs->cCpusLeftSynch);
279#endif
280}
281
282
283RTDECL(int) RTMpOnOthers(PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
284{
285 RT_ASSERT_INTS_ON();
286 IPRT_DARWIN_SAVE_EFL_AC();
287
288 RTMPARGS Args;
289 Args.pfnWorker = pfnWorker;
290 Args.pvUser1 = pvUser1;
291 Args.pvUser2 = pvUser2;
292 Args.idCpu = RTMpCpuId();
293 Args.cHits = 0;
294
295#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
296 mp_rendezvous_no_intrs(rtmpOnOthersDarwinWrapper, &Args);
297
298#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
299 Args.cCpusLeftSynch = 0;
300 if (g_pfnR0DarwinCpuBroadcastXCall && g_pfnR0DarwinCpuNumberMayBeNull)
301 g_pfnR0DarwinCpuBroadcastXCall(&Args.cCpusLeftSynch, FALSE /*fCallSelf*/, rtmpOnOthersDarwinWrapper, &Args);
302 else
303 return VERR_NOT_IMPLEMENTED;
304
305#else
306# error "port me"
307#endif
308
309 IPRT_DARWIN_RESTORE_EFL_AC();
310 return VINF_SUCCESS;
311}
312
313
314/**
315 * Wrapper between the native darwin per-cpu callback and PFNRTWORKER
316 * for the RTMpOnSpecific API.
317 *
318 * @param pvArg Pointer to the RTMPARGS package.
319 */
320static void rtmpOnSpecificDarwinBroadcastWrapper(void *pvArg)
321{
322 PRTMPARGS const pArgs = (PRTMPARGS)pvArg;
323 RTCPUID const idCpu = cpu_number();
324 if (pArgs->idCpu == idCpu)
325 {
326 IPRT_DARWIN_SAVE_EFL_AC();
327 pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
328 ASMAtomicIncU32(&pArgs->cHits);
329 IPRT_DARWIN_RESTORE_EFL_AC();
330 }
331#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
332 /* Wake up the thread calling RTMpOnSpecific if we're the last CPU out of here: */
333 if (ASMAtomicDecU32(&pArgs->cCpusLeftSynch) == 0)
334 thread_wakeup((event_t)&pArgs->cCpusLeftSynch);
335#endif
336}
337
338
339#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
340/**
341 * Wrapper between the native darwin on-cpu callback and PFNRTWORKER for the
342 * RTMpOnSpecific API when implemented using cpu_xcall() on arm.
343 *
344 * @param pvArg Pointer to the RTMPARGS package.
345 */
346static void rtmpOnSpecificDarwinSingleWrapper(void *pvArg)
347{
348 PRTMPARGS const pArgs = (PRTMPARGS)pvArg;
349 RTCPUID const idCpu = cpu_number();
350 Assert(pArgs->idCpu == idCpu);
351
352 pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
353 ASMAtomicIncU32(&pArgs->cHits);
354
355 /* Wake up the thread calling RTMpOnSpecific if it has blocked: */
356 if (ASMAtomicDecU32(&pArgs->cCpusLeftSynch) == 0)
357 thread_wakeup((event_t)&pArgs->cCpusLeftSynch);
358}
359#endif /* RT_ARCH_ARM64 || RT_ARCH_ARM32 */
360
361
362RTDECL(int) RTMpOnSpecific(RTCPUID idCpu, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
363{
364 RT_ASSERT_INTS_ON();
365 IPRT_DARWIN_SAVE_EFL_AC();
366
367 RTMPARGS Args;
368 Args.pfnWorker = pfnWorker;
369 Args.pvUser1 = pvUser1;
370 Args.pvUser2 = pvUser2;
371 Args.idCpu = idCpu;
372 Args.cHits = 0;
373
374#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
375 mp_rendezvous_no_intrs(rtmpOnSpecificDarwinBroadcastWrapper, &Args);
376
377#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
378 if (g_pfnR0DarwinCpuXCall && g_pfnR0DarwinCpuNumberMayBeNull)
379 {
380 ASMAtomicWriteU32(&Args.cCpusLeftSynch, 1);
381
382 /*
383 * Prepare waiting on Args.cCpusLeftSynch.
384 */
385 assert_wait((event_t)&Args.cCpusLeftSynch, THREAD_UNINT);
386
387 /*
388 * Disable preemption as we need to deal with cross calls to the same
389 * CPU here to make this work.
390 */
391 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
392 RTThreadPreemptDisable(&PreemptState);
393
394 RTCPUID const idCpuSelf = RTMpCpuId();
395 uint32_t cWaitFor = 0;
396 int rc = VINF_SUCCESS;
397 if (idCpuSelf != idCpu)
398 {
399 kern_return_t const krc = g_pfnR0DarwinCpuXCall(idCpu, rtmpOnSpecificDarwinSingleWrapper, &Args);
400 if (krc == KERN_SUCCESS)
401 cWaitFor = 1;
402 else
403 rc = VERR_CPU_OFFLINE;
404 }
405 else
406 {
407 rtmpOnSpecificDarwinSingleWrapper(&Args);
408 cWaitFor = 0;
409 }
410
411 RTThreadPreemptRestore(&PreemptState);
412
413 /*
414 * Synchronize with any CPUs we've dispatched to pfnWorker.
415 */
416 if (cWaitFor == 0 || ASMAtomicReadU32(&Args.cCpusLeftSynch) == 0)
417 {
418 /* clear_wait(current_thread(), THREAD_AWAKENED); - not exported, so we have to do: */
419 thread_wakeup((event_t)&Args.cCpusLeftSynch);
420 thread_block(THREAD_CONTINUE_NULL);
421 }
422 else
423 thread_block(THREAD_CONTINUE_NULL);
424
425 Assert(rc != VINF_SUCCESS || Args.cHits == 1);
426 IPRT_DARWIN_RESTORE_EFL_AC();
427 return rc;
428 }
429
430 /*
431 * Use broadcast to implement it, just like on x86/amd64:
432 *
433 * Note! This is unreliable, as with 14.7.5 / M3 Max often has several
434 * performance cores completely disabled when the system is idle,
435 * this means that SIGPdisabled is set and they'll be skipped by
436 * cpu_broadcast_xcall. The result is VERR_CPU_NOT_FOUND.
437 */
438 if (g_pfnR0DarwinCpuBroadcastXCall && g_pfnR0DarwinCpuNumberMayBeNull)
439 {
440 Args.cCpusLeftSynch = 0;
441 g_pfnR0DarwinCpuBroadcastXCall(&Args.cCpusLeftSynch, TRUE /*fCallSelf*/, rtmpOnSpecificDarwinBroadcastWrapper, &Args);
442 }
443 else
444 return VERR_NOT_IMPLEMENTED;
445
446#else
447# error "port me"
448#endif
449
450 IPRT_DARWIN_RESTORE_EFL_AC();
451 return Args.cHits == 1
452 ? VINF_SUCCESS
453 : VERR_CPU_NOT_FOUND;
454}
455
456#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32)
457
458/**
459 * Argument package for the darwin.arm64/arm32 RTMpOnPair implemenetation.
460 *
461 * We require a seperate implementation as the generic RTMpOnAll approach
462 * doesn't work reliably, for reasons mentioned above in the RTMpOnSpecific code
463 * and that our RTMpIsCpuOnline implementation is basically missing.
464 */
465typedef struct RTMPONPAIRDARWIN
466{
467 /** The state. */
468 uint32_t volatile fState;
469# define RTMPONPAIRDARWIN_STATE_READY(a_idx) RT_BIT_32(a_idxCpu)
470# define RTMPONPAIRDARWIN_STATE_BOTH_READY UINT32_C(0x00000003)
471# define RTMPONPAIRDARWIN_STATE_SETUP_CANCEL UINT32_C(0x80000000)
472 /** Number of CPUs we're waiting for to complete. */
473 uint32_t volatile cCpusLeftSynch;
474# ifdef RT_STRICT
475 /** For logging/debugging. */
476 uint32_t volatile cCalls;
477 /** For assertions. */
478 RTCPUID aidCpus[2];
479# endif
480 PFNRTMPWORKER pfnWorker;
481 void *pvUser1;
482 void *pvUser2;
483} RTMPONPAIRDARWIN;
484/** Pointer to the an argument package for the generic RTMpOnPair
485 * implemenation. */
486typedef RTMPONPAIRDARWIN *PRTMPONPAIRDARWIN;
487
488/**
489 * Wrapper between the native darwin per-cpu callback and PFNRTWORKER
490 * for the RTMpOnPair API.
491 *
492 * @param pvArg Pointer to the RTMPARGS package.
493 */
494template<uint32_t const a_idxCpu>
495static void rtmpOnPairDarwinWrapper(void *pvArg)
496{
497 PRTMPONPAIRDARWIN const pArgs = (PRTMPONPAIRDARWIN)pvArg;
498 RTCPUID const idCpu = cpu_number();
499 Assert(idCpu == pArgs->aidCpus[a_idxCpu]);
500
501 uint64_t const cMaxLoops = _4G * 8;
502 uint64_t cLoops = 0;
503 uint32_t fState = ASMAtomicOrExU32(&pArgs->fState, RTMPONPAIRDARWIN_STATE_READY(a_idxCpu))
504 | RTMPONPAIRDARWIN_STATE_READY(a_idxCpu);
505 while ( fState == RTMPONPAIRDARWIN_STATE_READY(a_idxCpu)
506 && cLoops++ < cMaxLoops)
507 {
508 ASMNopPause();
509 fState = ASMAtomicUoReadU32(&pArgs->fState);
510 }
511 Assert(cLoops < cMaxLoops);
512
513 if (fState == RTMPONPAIRDARWIN_STATE_BOTH_READY)
514 {
515 pArgs->pfnWorker(idCpu, pArgs->pvUser1, pArgs->pvUser2);
516# ifdef RT_STRICT
517 ASMAtomicIncU32(&pArgs->cCalls);
518# endif
519 }
520
521 /* Wake up the thread calling RTMpOnSpecific if we're the last CPU out of here: */
522 if (ASMAtomicDecU32(&pArgs->cCpusLeftSynch) == 0)
523 thread_wakeup((event_t)&pArgs->cCpusLeftSynch);
524}
525
526
527RTDECL(int) RTMpOnPair(RTCPUID idCpu1, RTCPUID idCpu2, uint32_t fFlags, PFNRTMPWORKER pfnWorker, void *pvUser1, void *pvUser2)
528{
529 RT_ASSERT_INTS_ON();
530 AssertReturn(idCpu1 != idCpu2, VERR_INVALID_PARAMETER);
531 AssertReturn(!(fFlags & RTMPON_F_VALID_MASK), VERR_INVALID_FLAGS);
532
533 /*
534 * Check that both CPUs are valid first.
535 */
536 int rc;
537 if ( RTMpIsCpuOnline(idCpu1)
538 && RTMpIsCpuOnline(idCpu2))
539 {
540 if (g_pfnR0DarwinCpuXCall && g_pfnR0DarwinCpuNumberMayBeNull)
541 {
542 RTMPONPAIRDARWIN Args;
543# ifdef RT_STRICT
544 Args.aidCpus[0] = idCpu1;
545 Args.aidCpus[1] = idCpu2;
546 Args.cCalls = 0;
547# endif
548 Args.pfnWorker = pfnWorker;
549 Args.pvUser1 = pvUser1;
550 Args.pvUser2 = pvUser2;
551 Args.fState = 0;
552 ASMAtomicWriteU32(&Args.cCpusLeftSynch, 2);
553
554 /*
555 * Prepare waiting on Args.cCpusLeftSynch.
556 */
557 assert_wait((event_t)&Args.cCpusLeftSynch, THREAD_UNINT);
558
559 /*
560 * Disable preemption as we need to deal with cross calls to the same
561 * CPU here to make this work.
562 */
563 RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
564 RTThreadPreemptDisable(&PreemptState);
565
566 RTCPUID const idCpuSelf = RTMpCpuId();
567 bool fWait = true;
568 kern_return_t krc;
569 if (idCpuSelf != idCpu1)
570 {
571 krc = g_pfnR0DarwinCpuXCall(idCpu1, rtmpOnPairDarwinWrapper<0>, &Args);
572 if (krc == KERN_SUCCESS)
573 {
574 if (idCpuSelf != idCpu2)
575 {
576 krc = g_pfnR0DarwinCpuXCall(idCpu2, rtmpOnPairDarwinWrapper<1>, &Args);
577 if (krc == KERN_SUCCESS)
578 rc = VINF_SUCCESS;
579 else
580 {
581 ASMAtomicSubU32(&Args.cCpusLeftSynch, 1);
582 ASMAtomicWriteU32(&Args.fState, RTMPONPAIRDARWIN_STATE_SETUP_CANCEL);
583 rc = VERR_CPU_OFFLINE;
584 }
585 }
586 else
587 {
588 rtmpOnPairDarwinWrapper<1>(&Args);
589 rc = VINF_SUCCESS;
590 }
591 }
592 else
593 {
594 fWait = false;
595 rc = VERR_CPU_OFFLINE;
596 }
597 }
598 else
599 {
600 krc = g_pfnR0DarwinCpuXCall(idCpu2, rtmpOnPairDarwinWrapper<1>, &Args);
601 if (krc == KERN_SUCCESS)
602 {
603 rtmpOnPairDarwinWrapper<0>(&Args);
604 rc = VINF_SUCCESS;
605 }
606 else
607 {
608 fWait = false;
609 rc = VERR_CPU_OFFLINE;
610 }
611 }
612
613 RTThreadPreemptRestore(&PreemptState);
614
615 /*
616 * Synchronize with any CPUs we've dispatched to pfnWorker.
617 */
618 if (!fWait || ASMAtomicReadU32(&Args.cCpusLeftSynch) == 0)
619 {
620 /* clear_wait(current_thread(), THREAD_AWAKENED); - not exported, so we have to do: */
621 thread_wakeup((event_t)&Args.cCpusLeftSynch);
622 thread_block(THREAD_CONTINUE_NULL);
623 }
624 else
625 thread_block(THREAD_CONTINUE_NULL);
626 }
627 else
628 rc = VERR_NOT_SUPPORTED;
629 }
630 /*
631 * A CPU must be present to be considered just offline.
632 */
633 else if ( RTMpIsCpuPresent(idCpu1)
634 && RTMpIsCpuPresent(idCpu2))
635 rc = VERR_CPU_OFFLINE;
636 else
637 rc = VERR_CPU_NOT_FOUND;
638 return rc;
639}
640
641
642RTDECL(bool) RTMpOnPairIsConcurrentExecSupported(void)
643{
644 return true;
645}
646
647#endif /* RT_ARCH_ARM64 || RT_ARCH_ARM32 */
648
649
650RTDECL(int) RTMpPokeCpu(RTCPUID idCpu)
651{
652 RT_ASSERT_INTS_ON();
653
654 if (g_pfnR0DarwinCpuInterrupt == NULL)
655 return VERR_NOT_SUPPORTED;
656 IPRT_DARWIN_SAVE_EFL_AC(); /* paranoia */
657 /// @todo use mp_cpus_kick() when available (since 10.10)? It's probably slower (locks, mask iteration, checks), though...
658 g_pfnR0DarwinCpuInterrupt(idCpu);
659 IPRT_DARWIN_RESTORE_EFL_AC();
660 return VINF_SUCCESS;
661}
662
663
664RTDECL(bool) RTMpOnAllIsConcurrentSafe(void)
665{
666 return true;
667}
668
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette