24 static constexpr size_t MaxProcessors = 64;
28 bool tryAcquire(
size_t processor) {
29 return processor < MaxProcessors && m_State.compareAndSwap(0, processor + 1);
32 bool ownedBy(
size_t processor)
const {
33 return processor < MaxProcessors && (m_State.value() & ~PhaseMask) == processor + 1;
36 bool activeBy(
size_t processor)
const {
37 return processor < MaxProcessors && m_State.value() == processor + 1;
40 bool markQuiesced(
size_t processor) {
41 return processor < MaxProcessors &&
42 m_State.compareAndSwap(processor + 1, QuiescedBit | (processor + 1));
45 bool claimQuiesced(
size_t processor) {
46 return processor < MaxProcessors &&
47 m_State.compareAndSwap(QuiescedBit | (processor + 1), processor + 1);
52 if (processor >= MaxProcessors) {
56 size_t state = m_State.value();
57 while ((state & QuiescedBit) && !(state & TerminalBit)) {
58 if (m_State.compareAndSwap(state, processor + 1)) {
61 state = m_State.value();
68 if (processor >= MaxProcessors) {
72 size_t state = m_State.value();
73 while ((state & FailedBit) && !(state & (QuiescedBit | TerminalBit))) {
74 if (m_State.compareAndSwap(state, processor + 1)) {
77 state = m_State.value();
82 bool quiescedBy(
size_t processor)
const {
83 return processor < MaxProcessors && m_State.value() == (QuiescedBit | (processor + 1));
86 bool markTerminal(
size_t processor) {
87 return processor < MaxProcessors &&
88 m_State.compareAndSwap(processor + 1, TerminalBit | (processor + 1));
91 bool claimTerminal(
size_t processor) {
92 return processor < MaxProcessors &&
93 m_State.compareAndSwap(TerminalBit | (processor + 1), processor + 1);
96 bool terminalBy(
size_t processor)
const {
97 return processor < MaxProcessors && m_State.value() == (TerminalBit | (processor + 1));
100 bool markFailed(
size_t processor) {
101 return processor < MaxProcessors &&
102 m_State.compareAndSwap(processor + 1, FailedBit | (processor + 1));
105 bool failedBy(
size_t processor)
const {
106 return processor < MaxProcessors && m_State.value() == (FailedBit | (processor + 1));
109 bool release(
size_t processor) {
110 return processor < MaxProcessors && m_State.compareAndSwap(processor + 1, 0);
114 return m_State.value() != 0;
118 static constexpr size_t QuiescedBit = size_t(1) << (
sizeof(size_t) * 8 - 1);
119 static constexpr size_t TerminalBit = QuiescedBit >> 1;
120 static constexpr size_t FailedBit = TerminalBit >> 1;
121 static constexpr size_t PhaseMask = QuiescedBit | TerminalBit | FailedBit;
274 static constexpr size_t MaxProcessors = 64;
280 processor(MaxProcessors),
282 acknowledgedToken(0) {}
288 size_t acknowledgedToken;
292 : m_Owner(false), m_Generation(0), m_NextGeneration(0), m_Address(0), m_Expected(0) {}
294 static constexpr bool supportsContext(ExecutionContext context) {
295 return context == ExecutionContext::WaitableThread || context == ExecutionContext::AtomicThread;
298 static constexpr bool onlyCurrentProcessorServiceable(
size_t processorCount,
299 size_t terminalProcessors) {
300 return processorCount && terminalProcessors >= (processorCount - 1);
304 return m_Owner.compareAndSwap(
false,
true);
307 bool publish(uintptr_t address,
size_t processor,
size_t processorCount,
308 uint64_t expected = ~uint64_t(0)) {
309 uint64_t available = 0;
310 if (!m_Owner || m_Generation || processor >= processorCount ||
311 !processorMask(processorCount, available)) {
314 if (expected == ~uint64_t(0)) {
315 expected = available;
317 if (!expected || (expected & ~available) || !(expected & (uint64_t(1) << processor))) {
321 const size_t initiatorState = m_ProcessorState[processor].value();
322 if (isServing(initiatorState)) {
326 size_t generation = 0;
327 if (!selectNextGeneration(generation)) {
332 m_Expected = expected;
333 m_ProcessorState[processor] = acknowledgedToken(generation);
334 m_NextGeneration = generation;
337 m_Generation = generation;
341 bool beginService(
size_t processor,
Service& service) {
342 if (processor >= MaxProcessors || service.generation) {
346 const size_t generation = m_Generation.value();
347 if (!generation || !(m_Expected.value() & (uint64_t(1) << processor))) {
351 const size_t serving = servingToken(generation);
352 const size_t acknowledged = acknowledgedToken(generation);
353 const size_t previous = m_ProcessorState[processor].value();
354 if (isServing(previous) || previous == acknowledged ||
355 !m_ProcessorState[processor].compareAndSwap(previous, serving)) {
362 const uintptr_t address = m_Address.value();
363 return revalidateServiceClaim(processor, generation, address, serving, acknowledged, service);
366 bool finishService(
Service& service) {
367 if (!service.generation || service.processor >= MaxProcessors) {
374 const bool acknowledged = m_ProcessorState[service.processor].compareAndSwap(
375 service.servingToken, service.acknowledgedToken);
376 const bool current = acknowledged && m_Generation.value() == service.generation;
381 bool complete()
const {
382 const size_t generation = m_Generation.value();
383 const uint64_t expected = m_Expected.value();
384 return generation && expected && allAcknowledged(generation, expected) &&
385 m_Generation.value() == generation;
392 bool drained()
const {
393 for (
size_t processor = 0; processor < MaxProcessors; ++processor) {
394 if (isServing(m_ProcessorState[processor].value())) {
402 if (m_Generation || !drained()) {
405 return m_Owner.compareAndSwap(
true,
false);
412 bool retainedClosed()
const {
413 return m_Owner && !m_Generation && drained();
416 size_t generation()
const {
417 return m_Generation.value();
420 uintptr_t address()
const {
421 return m_Address.value();
424 uint64_t expectedMask()
const {
425 return m_Expected.value();
428 uint64_t acknowledgedMask()
const {
429 const size_t generation = m_Generation.value();
430 return generation ? acknowledgedMask(generation) : 0;
433 size_t servicing()
const {
435 for (
size_t processor = 0; processor < MaxProcessors; ++processor) {
436 if (isServing(m_ProcessorState[processor].value())) {
444 friend class LocalApicTlbShootdownTestPeer;
446 static constexpr size_t ServingBit = 1;
447 static constexpr size_t MaxGeneration = ~size_t(0) >> 1;
449 static constexpr bool isServing(
size_t token) {
450 return token & ServingBit;
453 static constexpr size_t acknowledgedToken(
size_t generation) {
454 return generation << 1;
457 static constexpr size_t servingToken(
size_t generation) {
458 return acknowledgedToken(generation) | ServingBit;
461 bool revalidateServiceClaim(
size_t processor,
size_t generation, uintptr_t address,
462 size_t serving,
size_t acknowledged,
Service& service) {
463 if (m_Generation.value() != generation) {
464 m_ProcessorState[processor].compareAndSwap(serving, acknowledged);
468 service.generation = generation;
469 service.address = address;
470 service.processor = processor;
471 service.servingToken = serving;
472 service.acknowledgedToken = acknowledged;
476 bool selectNextGeneration(
size_t& generation)
const {
477 size_t candidate = m_NextGeneration.value();
478 for (
size_t attempt = 0; attempt <= MaxProcessors; ++attempt) {
479 candidate = candidate == MaxGeneration ? 1 : candidate + 1;
480 bool present =
false;
481 for (
size_t processor = 0; processor < MaxProcessors; ++processor) {
482 if ((m_ProcessorState[processor].value() >> 1) == candidate) {
488 generation = candidate;
495 uint64_t acknowledgedMask(
size_t generation)
const {
496 uint64_t acknowledged = 0;
497 const size_t token = acknowledgedToken(generation);
498 for (
size_t processor = 0; processor < MaxProcessors; ++processor) {
499 if (m_ProcessorState[processor].value() == token) {
500 acknowledged |= uint64_t(1) << processor;
506 bool allAcknowledged(
size_t generation, uint64_t expected)
const {
507 const size_t token = acknowledgedToken(generation);
508 for (
size_t processor = 0; expected; ++processor, expected >>= 1) {
509 if ((expected & 1) && m_ProcessorState[processor].value() != token) {
516 static bool processorMask(
size_t processorCount, uint64_t& mask) {
517 if (!processorCount || processorCount > MaxProcessors) {
520 mask = processorCount == MaxProcessors ? ~uint64_t(0) : (uint64_t(1) << processorCount) - 1;