5#include "../Common/CompilerMacrosExport.h"
6#ifndef SC_EXPORT_LIBRARY_FIBERS
7#define SC_EXPORT_LIBRARY_FIBERS 0
9#define SC_FIBERS_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_FIBERS)
11#include "../Common/AlignedStorage.h"
12#include "../Common/Assert.h"
13#include "../Common/Function.h"
14#include "../Common/OpaqueObject.h"
15#include "../Common/PlatformMacrosInstructionSet.h"
16#include "../Common/PlatformMacrosType.h"
17#include "../Common/PrimitiveDefinitions.h"
18#include "../Common/Result.h"
19#include "../Common/Span.h"
20#include "FibersError.h"
29SC_DECLARE_ASSERT_PROVIDER(FibersAssert, SC_FIBERS_EXPORT);
31#define SC_FIBERS_ASSERT_RELEASE(e) SC_ASSERT_PROVIDER_RELEASE(SC::FibersAssert, e)
32#define SC_FIBERS_ASSERT_DEBUG(e) SC_ASSERT_PROVIDER_DEBUG(SC::FibersAssert, e)
33#define SC_FIBERS_TRUST_RESULT(expression) SC_FIBERS_ASSERT_RELEASE(expression)
36struct FiberAutoResetEvent;
41struct FiberJobClassDiagnostics;
42struct FiberJobClassInternal;
43struct FiberJobClassOptions;
44struct FiberJobContext;
47struct FiberJobScheduler;
49struct FiberJobWorkerPool;
50struct FiberJobWorkerPoolThreadEntry;
51struct FiberJobWorkerThread;
57struct FiberTaskClassDiagnostics;
58struct FiberTaskClassInternal;
59struct FiberTaskClassOptions;
61struct FiberTaskPoolDiagnostics;
63struct FiberVirtualStack;
64struct FiberVirtualStackInternal;
65struct FiberVirtualStackOptions;
66struct FiberStackClass;
67struct FiberStackClassDiagnostics;
68struct FiberStackClassInternal;
69struct FiberStackClassOptions;
70struct FiberStackGrowthRuntime;
71struct FiberStackGrowthRuntimeInternal;
72struct FiberStackGrowthThread;
73struct FiberStackGrowthThreadInternal;
74struct FiberSchedulerDiagnostics;
75struct FiberTraceEvent;
76struct FiberTraceHooks;
78struct FiberAllocatorInterface;
79struct FiberAllocatorVirtualOptions;
81struct FiberWorkerPoolWakeEvent;
82struct FiberWorkerPool;
83struct FiberWorkerPoolOptions;
84struct FiberWorkerPoolThreadEntry;
85struct FiberWorkerThread;
87#if SC_PLATFORM_WINDOWS
88static constexpr int FiberContextStorageSize = 2048;
89#elif SC_PLATFORM_ARM64
90static constexpr int FiberContextStorageSize = 224;
92static constexpr int FiberContextStorageSize = 128;
94static constexpr int FiberContextStorageAlignment = 16;
95static constexpr int FiberStackAlignment = 16;
96static constexpr int FiberStackMinimumSize = 4096;
98static constexpr int FiberStackGrowthSignalStackSize = 128 * 1024;
100static constexpr int FiberInjectionSlotStorageSize =
sizeof(
void*) +
sizeof(
size_t);
106 static constexpr size_t FourKiB = 4 * 1024;
107 static constexpr size_t EightKiB = 8 * 1024;
108 static constexpr size_t ThirtyTwoKiB = 32 * 1024;
109 static constexpr size_t SixtyFourKiB = 64 * 1024;
114 static constexpr int Windows = 64;
115 static constexpr int Apple = 128;
116 static constexpr int Linux = 384;
117 static constexpr int Default = Linux;
118 static constexpr size_t Alignment =
alignof(
void*);
120 using Object = FiberStackGrowthRuntimeInternal;
122using FiberStackGrowthRuntimeOpaque = OpaqueObject<FiberStackGrowthRuntimeDefinition>;
133 [[nodiscard]] Result create();
134 [[nodiscard]] Result close();
136 [[nodiscard]]
static bool isSupported();
137 [[nodiscard]]
bool isOpen()
const;
138 [[nodiscard]]
size_t registeredThreadCount()
const;
142 friend struct FiberStackGrowthThreadInternal;
144 FiberStackGrowthRuntimeOpaque internal;
149 static constexpr int Windows = 64;
150 static constexpr int Apple = 128;
151 static constexpr int Linux = 128;
152 static constexpr int Default = Linux;
153 static constexpr size_t Alignment =
alignof(
void*);
155 using Object = FiberStackGrowthThreadInternal;
157using FiberStackGrowthThreadOpaque = OpaqueObject<FiberStackGrowthThreadDefinition>;
170 [[nodiscard]] Result close();
172 [[nodiscard]]
bool isOpen()
const;
175 FiberStackGrowthThreadOpaque internal;
185 [[nodiscard]]
bool isRuntimeOwned()
const;
187 [[nodiscard]] Span<char> memory()
const;
188 [[nodiscard]]
size_t sizeInBytes()
const;
189 [[nodiscard]]
size_t usableSizeInBytes()
const;
190 [[nodiscard]]
size_t alignmentWasteInBytes()
const;
191 [[nodiscard]]
bool isUsable()
const;
192 void fillHighWaterMark();
195 [[nodiscard]]
size_t highWaterUnusedBytes()
const;
203 Span<char> stackMemory;
204 void* stackOwner =
nullptr;
206 size_t runtimeStackSize = 0;
207 bool runtimeOwnedStack =
false;
212 static constexpr int Windows = 64;
213 static constexpr int Apple = 64;
214 static constexpr int Linux = 64;
215 static constexpr int Default = 64;
216 static constexpr size_t Alignment =
alignof(
void*);
218 using Object = FiberVirtualStackInternal;
220using FiberVirtualStackOpaque = OpaqueObject<FiberVirtualStackDefinition>;
225 size_t usableSizeInBytes = FiberStackSize::SixtyFourKiB;
226 bool guardPage =
true;
231 static constexpr int Windows = 224;
232 static constexpr int Apple = 224;
233 static constexpr int Linux = 224;
234 static constexpr int Default = 224;
235 static constexpr size_t Alignment =
alignof(
void*);
237 using Object = FiberStackClassInternal;
239using FiberStackClassOpaque = OpaqueObject<FiberStackClassDefinition>;
241enum class FiberStackCommitMode : uint8_t
249 size_t stackSizeInBytes = FiberStackSize::SixtyFourKiB;
250 size_t maxStacks = 0;
251 bool guardPage =
true;
253 FiberStackCommitMode commitMode = FiberStackCommitMode::Full;
254 size_t initialCommitSizeInBytes = 0;
256 size_t growthCommitSizeInBytes = 0;
262 size_t activeStacks = 0;
263 size_t peakActiveStacks = 0;
264 size_t stackSizeInBytes = 0;
265 size_t guardSizeInBytes = 0;
266 size_t reservedSizeBytes = 0;
267 size_t committedSizeBytes = 0;
268 size_t peakCommittedBytes = 0;
269 size_t highWaterUsedBytes = 0;
270 size_t initialCommitSizeInBytes = 0;
271 size_t growthCommitSizeInBytes = 0;
273 FiberStackCommitMode commitMode = FiberStackCommitMode::Full;
288 [[nodiscard]] Result acquire(
FiberStack& outStack);
289 [[nodiscard]] Result release(
FiberStack& stack);
290 [[nodiscard]] Result waitForAvailableSlot(
FiberScheduler& scheduler);
292 void fillHighWaterMarks();
295 [[nodiscard]]
bool isReserved()
const;
296 [[nodiscard]]
bool owns(
const FiberStack& stack)
const;
297 [[nodiscard]]
size_t capacity()
const;
298 [[nodiscard]]
size_t activeCount()
const;
304 FiberStackClassOpaque internal;
307enum class FiberAllocatorMode : uint8_t
318 size_t numAllocations = 0;
319 size_t numReleases = 0;
321 size_t requestedBytesAllocated = 0;
322 size_t requestedBytesReleased = 0;
324 size_t bytesInUse = 0;
325 size_t peakBytesInUse = 0;
327 size_t numAllocationFailures = 0;
328 size_t lastFailedAllocationSize = 0;
329 size_t largestFailedAllocationSize = 0;
334 size_t reserveBytes = 0;
335 size_t initialCommitBytes = 0;
340 virtual void* allocateImpl(
const void* owner,
size_t numBytes,
size_t alignment) = 0;
341 virtual void releaseImpl(
void* memory) = 0;
355 [[nodiscard]] Result createFixed(Span<char> storage);
357 [[nodiscard]] Result createMalloc();
359 [[nodiscard]] Result validateClose()
const;
360 [[nodiscard]] Result close();
362 [[nodiscard]]
void* allocate(
const void* owner,
size_t numBytes,
size_t alignment);
363 void release(
void* memory);
364 static void releaseFromAnyAllocator(
void* memory);
366 [[nodiscard]] FiberAllocatorMode mode()
const;
368 [[nodiscard]]
bool isOpen()
const;
370 [[nodiscard]]
size_t used()
const;
371 [[nodiscard]]
size_t capacity()
const;
372 [[nodiscard]]
size_t peakUsed()
const;
373 [[nodiscard]]
size_t failedAllocationSize()
const;
374 [[nodiscard]]
size_t reservedBytes()
const;
375 [[nodiscard]]
size_t committedBytes()
const;
380 Result initializeFixedStorage(Span<char> storage);
381 void* allocateFromBlocks(
const void* owner,
size_t numBytes,
size_t alignment);
382 void releaseBlock(BlockHeader& header);
383 bool ensureCommitted(
size_t sizeInBytes);
384 void releaseVirtualMemory();
385 void recordAllocationFailure(
size_t numBytes);
388 FiberAllocatorMode currentMode = FiberAllocatorMode::None;
390 Span<char> fixedStorage;
391 BlockHeader* firstBlock =
nullptr;
394 void* virtualMemory =
nullptr;
395 size_t virtualReservedBytes = 0;
396 size_t virtualCommittedBytes = 0;
414 [[nodiscard]] Span<char> memory()
const;
415 [[nodiscard]]
size_t usableSizeInBytes()
const;
416 [[nodiscard]]
size_t reservedSizeInBytes()
const;
417 [[nodiscard]]
size_t guardSizeInBytes()
const;
418 [[nodiscard]]
bool isReserved()
const;
421 FiberVirtualStackOpaque internal;
425enum class FiberTaskStatus
435enum class FiberTaskSuspendAction
442struct FiberCancellationToken;
453 [[nodiscard]]
bool isActive()
const;
457 [[nodiscard]]
const FiberTask* runningTask()
const;
474 size_t localReadyFibers = 0;
475 size_t localDequeCapacity = 0;
476 size_t localDequeHead = 0;
477 volatile size_t localDequeTop = 0;
478 volatile size_t localDequeBottom = 0;
479 size_t localReadyPeakFibers = 0;
480 size_t localSpilledFibers = 0;
481 size_t stealAttempts = 0;
482 size_t stealVictimProbes = 0;
483 size_t stolenFibers = 0;
484 size_t stolenBatches = 0;
485 size_t stolenBatchPeak = 0;
486 size_t failedSteals = 0;
487 size_t stealCursor = 0;
488 volatile size_t runAttempts = 0;
489 volatile size_t idlePolls = 0;
490 volatile size_t idleSpinIterations = 0;
491 volatile size_t parkAttempts = 0;
492 volatile size_t parkedWakeups = 0;
493 volatile size_t executedFibers = 0;
494 size_t completedFibers = 0;
495 volatile size_t yieldedFibers = 0;
496 size_t waitingFibers = 0;
497 volatile int32_t activeRegistryLock = 0;
498 bool workerActive =
false;
499 bool localSchedulingActive =
false;
500 bool stealCursorInitialized =
false;
502 AlignedStorage<FiberContextStorageSize, FiberContextStorageAlignment> rootContextStorage;
504 [[nodiscard]] FiberContext& rootContext();
507#if SC_PLATFORM_WINDOWS
508static constexpr int FiberWorkerThreadStorageSize =
sizeof(
void*);
510static constexpr int FiberWorkerThreadStorageSize =
sizeof(
void*) * 2;
512static constexpr int FiberWorkerThreadStorageAlignment =
alignof(
void*);
523 [[nodiscard]]
bool wasStarted()
const;
524 [[nodiscard]] Result result()
const;
528 friend struct FiberWorkerPoolThreadEntry;
530 AlignedStorage<FiberWorkerThreadStorageSize, FiberWorkerThreadStorageAlignment> threadStorage;
533 size_t workerIndex = 0;
534 uint64_t affinityMask = 0;
535 uint8_t priority = 0;
536 Result threadResult = Result(
true);
537 bool started =
false;
541 Span<char> stackGrowthSignalStackStorage;
543 Result startThread();
545 Result runThreadEntry();
546 Result applyThreadPolicy();
549enum class FiberWorkerThreadPriority : uint8_t
560 size_t dequeCapacityPerWorker = 0;
562 size_t injectionCapacity = 0;
563 size_t idleSpinAttempts = 32;
564 Span<const uint64_t> affinityMasks;
565 FiberWorkerThreadPriority threadPriority = FiberWorkerThreadPriority::Default;
574 size_t readyFibers = 0;
575 size_t readyPeakFibers = 0;
576 size_t dequeCapacity = 0;
577 size_t spilledFibers = 0;
578 size_t stealAttempts = 0;
579 size_t stealVictimProbes = 0;
580 size_t stolenFibers = 0;
581 size_t stolenBatches = 0;
582 size_t stolenBatchPeak = 0;
583 size_t failedSteals = 0;
584 size_t runAttempts = 0;
585 size_t idlePolls = 0;
586 size_t idleSpinIterations = 0;
587 size_t parkAttempts = 0;
588 size_t parkedWakeups = 0;
589 size_t executedFibers = 0;
590 size_t completedFibers = 0;
591 size_t yieldedFibers = 0;
592 size_t waitingFibers = 0;
598 size_t wakeNotifications = 0;
600 size_t wakeSignals = 0;
605 size_t readyFibers = 0;
606 size_t globalReadyFibers = 0;
607 size_t activeFibers = 0;
608 size_t injectionCapacity = 0;
609 size_t injectionReady = 0;
610 size_t injectionPublishing = 0;
611 size_t injectionPeak = 0;
612 size_t injectionSpills = 0;
613 size_t injectionClaimBatchPeak = 0;
614 size_t injectionLockAcquisitions = 0;
615 size_t injectionLockContentions = 0;
616 size_t injectionLockSpinRetries = 0;
617 size_t injectionLockPeakSpinRetries = 0;
619 size_t lockAcquisitions = 0;
620 size_t lockContentions = 0;
621 size_t lockSpinRetries = 0;
622 size_t lockPeakSpinRetries = 0;
623 size_t lockSpawn = 0;
624 size_t lockReady = 0;
625 size_t lockSynchronization = 0;
626 size_t lockCompletion = 0;
627 size_t lockControl = 0;
630enum class FiberTraceEventType : uint8_t
640 FiberTraceEventType type = FiberTraceEventType::TaskStarted;
649 using Callback = void (*)(
void* userData,
const FiberTraceEvent& event);
651 Callback callback =
nullptr;
652 void* userData =
nullptr;
664 Result start(
FiberScheduler& scheduler, Span<FiberWorker> workerStorage, Span<FiberWorkerThread> threadStorage);
665 Result start(
FiberScheduler& scheduler, Span<FiberWorker> workerStorage, Span<FiberWorkerThread> threadStorage,
667 Result requestStop();
671 [[nodiscard]]
bool isRunning()
const;
672 [[nodiscard]]
size_t workerCount()
const;
680 static constexpr int Windows =
sizeof(
void*) * 16;
681 static constexpr int Apple =
sizeof(
void*) * 16;
682 static constexpr int Linux =
sizeof(
void*) * 16;
683 static constexpr int Default = Linux;
685 static constexpr size_t Alignment =
alignof(
void*);
687 using Object = FiberWorkerPoolWakeEvent;
690 using WakeEventOpaque = OpaqueObject<WakeEventDefinition>;
697 Span<FiberWorker> workers;
698 Span<FiberWorkerThread> threads;
699 WakeEventOpaque wakeEvent;
700 mutable volatile int32_t stopRequested = 0;
701 mutable volatile int32_t running = 0;
702 size_t idleSpinAttempts = 0;
703 bool localDequesCreated =
false;
704 bool injectionCreated =
false;
706 void wakeOneWorker();
707 void wakeAllWorkers();
708 void resetWakeDiagnostics();
709 [[nodiscard]]
bool waitForWork(uint32_t observedGeneration);
710 [[nodiscard]] uint32_t wakeGeneration()
const;
712 Result workerMain(
size_t workerIndex);
723 void requestCancel();
725 Result check()
const;
727 [[nodiscard]]
bool isCancellationRequested()
const;
735 mutable volatile int32_t requested = 0;
743 Result check()
const;
745 [[nodiscard]]
bool isValid()
const;
746 [[nodiscard]]
bool isCancellationRequested()
const;
759enum class FiberJobStatus
771 [[nodiscard]]
FiberJob& job()
const;
772 [[nodiscard]]
bool isCancellationRequested()
const;
773 Result checkCancellation()
const;
797 [[nodiscard]]
bool isActive()
const;
798 [[nodiscard]]
bool isCompleted()
const;
799 [[nodiscard]]
bool isCancellationRequested()
const;
800 [[nodiscard]] FiberJobStatus status()
const;
801 [[nodiscard]] Result result()
const;
817 Result jobResult = Result(
true);
818 volatile int32_t jobStatus =
static_cast<int32_t
>(FiberJobStatus::Invalid);
819 uint32_t cancelGeneration = 0;
820 volatile bool cancelRequested =
false;
821 bool poolRetained =
false;
826 size_t readyJobs = 0;
827 size_t readyPeakJobs = 0;
828 size_t dequeCapacity = 0;
829 size_t executedJobs = 0;
830 size_t claimBatches = 0;
831 size_t claimedJobs = 0;
832 size_t claimBatchPeak = 0;
833 size_t stealAttempts = 0;
834 size_t stolenJobs = 0;
835 size_t failedSteals = 0;
838#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
840#pragma warning(disable : 4324)
851 [[nodiscard]]
bool isActive()
const;
854 [[nodiscard]]
FiberJob* runningJob();
855 [[nodiscard]]
const FiberJob* runningJob()
const;
869 size_t localDequeCapacity = 0;
870 size_t lastDequeCapacity = 0;
871 volatile size_t localDequeTop = 0;
872 volatile size_t localDequeBottom = 0;
874 size_t localReadyPeakJobs = 0;
875 size_t executedJobs = 0;
876 size_t claimBatches = 0;
877 size_t claimedJobs = 0;
878 size_t claimBatchPeak = 0;
879 size_t stealCursor = 0;
880 size_t stealAttempts = 0;
881 size_t stolenJobs = 0;
882 size_t failedSteals = 0;
883 bool workerActive =
false;
884 bool distributedCounts =
false;
886 alignas(128)
volatile size_t ownedReadyJobs = 0;
887 alignas(128)
volatile size_t ownedActiveJobs = 0;
889 mutable volatile int32_t countActivationLock = 0;
891#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
899#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
901#pragma warning(disable : 4324)
911 Result create(Span<FiberJob*> readyStorage);
914 Result createWorkerDeques(
FiberAllocator& allocator, Span<FiberJobWorker> workers,
size_t capacityPerWorker);
915 void releaseWorkerDeques(Span<FiberJobWorker> workers);
917 Result spawn(
FiberJob& job, FiberJob::Procedure procedure);
920 Result
spawn(Span<FiberJob> jobs, FiberJob::Procedure procedure);
922 Result runOne(
bool& outRanJob);
923 Result runOne(
FiberJobWorker& worker, Span<FiberJobWorker> workerGroup,
bool& outRanJob);
925 Result run(
FiberJobWorker& worker, Span<FiberJobWorker> workerGroup);
928 Result requestCancel(
FiberJob& job);
930 Result requestCancelAll();
932 [[nodiscard]]
bool isOpen()
const;
937 [[nodiscard]]
size_t capacity()
const;
942 [[nodiscard]]
FiberJob* currentJob();
953 Span<FiberJob*> queueStorage;
955 size_t queueHead = 0;
956 size_t queueTail = 0;
957 size_t queueCount = 0;
959 alignas(128)
volatile size_t readyJobs = 0;
960 alignas(128)
volatile size_t activeJobs = 0;
962 mutable volatile int32_t countActivationLock = 0;
964 alignas(128)
mutable volatile int32_t queueLock = 0;
965 volatile uint32_t cancelGeneration = 0;
969 struct QueueLockGuard;
970 struct CountActivationLockGuard;
973 Result complete(
FiberJob& job, Result result);
974 size_t confirmedJobCount(
bool ready)
const;
979 bool usesDistributedAccounting(
const FiberJobWorker& worker)
const;
980 bool isJobCancellationRequested(
const FiberJob& job)
const;
981 bool isWorkerStopRequested()
const;
983#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
996 [[nodiscard]]
bool wasStarted()
const;
997 [[nodiscard]] Result result()
const;
1001 friend struct FiberJobWorkerPoolThreadEntry;
1003 AlignedStorage<FiberWorkerThreadStorageSize, FiberWorkerThreadStorageAlignment> threadStorage;
1006 size_t workerIndex = 0;
1007 uint64_t affinityMask = 0;
1008 uint8_t priority = 0;
1009 Result threadResult = Result(
true);
1010 bool started =
false;
1012 Result startThread();
1013 Result joinThread();
1014 Result runThreadEntry();
1015 Result applyThreadPolicy();
1021 size_t dequeCapacityPerWorker = 0;
1022 size_t idleSpinAttempts = 32;
1025 bool keepAliveWhenIdle =
false;
1027 Span<const uint64_t> affinityMasks;
1028 FiberWorkerThreadPriority threadPriority = FiberWorkerThreadPriority::Default;
1050 [[nodiscard]]
bool isRunning()
const;
1051 [[nodiscard]]
size_t workerCount()
const;
1052 [[nodiscard]]
size_t parkedWorkerCount()
const;
1056 static constexpr int Windows =
sizeof(
void*) * 16;
1057 static constexpr int Apple =
sizeof(
void*) * 16;
1058 static constexpr int Linux =
sizeof(
void*) * 16;
1059 static constexpr int Default = Linux;
1061 static constexpr size_t Alignment =
alignof(
void*);
1063 using Object = FiberWorkerPoolWakeEvent;
1066 using WakeEventOpaque = OpaqueObject<WakeEventDefinition>;
1073 Span<FiberJobWorker> workers;
1074 Span<FiberJobWorkerThread> threads;
1075 WakeEventOpaque wakeEvent;
1076 mutable volatile int32_t stopRequested = 0;
1077 mutable volatile int32_t running = 0;
1078 size_t idleSpinAttempts = 0;
1079 bool keepAliveWhenIdle =
false;
1080 volatile uint32_t preparingToWait = 0;
1082 void wakeOneWorker();
1083 void wakeAllWorkers();
1084 void notifyPreparingWorkers();
1085 [[nodiscard]]
bool waitForWork(uint32_t observedGeneration);
1086 [[nodiscard]]
bool waitForPreparedWork(uint32_t observedGeneration);
1087 [[nodiscard]] uint32_t prepareToWaitForWork();
1088 void cancelWaitForWork();
1089 [[nodiscard]] uint32_t wakeGeneration()
const;
1090 [[nodiscard]]
bool isStopRequested()
const;
1092 Result workerMain(
size_t workerIndex);
1097 size_t capacity = 0;
1098 size_t retainedJobs = 0;
1099 size_t availableJobs = 0;
1101 size_t peakRetainedJobs = 0;
1106 static constexpr int Windows = 48;
1107 static constexpr int Apple = 48;
1108 static constexpr int Linux = 48;
1109 static constexpr int Default = 48;
1110 static constexpr size_t Alignment =
alignof(
void*);
1112 using Object = FiberJobClassInternal;
1114using FiberJobClassOpaque = OpaqueObject<FiberJobClassDefinition>;
1123 size_t capacity = 0;
1139 [[nodiscard]] Result validateClose()
const;
1140 [[nodiscard]] Result close();
1143 [[nodiscard]]
bool isOpen()
const;
1144 [[nodiscard]]
bool owns(
const FiberJob& job)
const;
1145 [[nodiscard]]
size_t capacity()
const;
1150 FiberJobClassOpaque internal;
1162 Result create(Span<FiberJob> jobStorage);
1170 [[nodiscard]]
bool isOpen()
const;
1171 [[nodiscard]]
bool owns(
const FiberJob& job)
const;
1172 [[nodiscard]]
size_t capacity()
const;
1173 [[nodiscard]]
size_t retainedCount()
const;
1174 [[nodiscard]]
size_t availableCount()
const;
1180 Span<FiberJob> jobs;
1183 size_t retainedJobs = 0;
1184 size_t peakRetainedJobs = 0;
1186 mutable volatile int32_t poolLock = 0;
1189 void releaseAcquired(
FiberJob& job);
1190 void releaseAcquiredUnlocked(
FiberJob& job);
1191 void recordPublished();
1197 Result result = Result(
true);
1213 Result requestCancel();
1216 [[nodiscard]]
size_t pendingCount()
const;
1217 [[nodiscard]]
size_t jobCount()
const;
1218 [[nodiscard]]
size_t countErrors()
const;
1219 Result collectErrors(Span<FiberJobGroupError> errors,
size_t& outErrors)
const;
1226 size_t pendingJobs = 0;
1227 size_t totalJobs = 0;
1229 mutable volatile int32_t groupLock = 0;
1231 Result prepareSpawn()
const;
1233 void unlinkSpawnFailure(
FiberJob& job);
1242 void* userData =
nullptr;
1243 bool setUserData =
false;
1256#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
1257#pragma warning(push)
1258#pragma warning(disable : 4324)
1274 [[nodiscard]]
bool isValid()
const;
1275 [[nodiscard]]
bool isStarted()
const;
1276 [[nodiscard]]
bool isCompleted()
const;
1277 [[nodiscard]]
bool isActive()
const;
1278 [[nodiscard]]
bool isCancellationRequested()
const;
1279 [[nodiscard]] FiberTaskStatus status()
const;
1280 [[nodiscard]] Result result()
const;
1281 void setUserData(
void* data);
1282 [[nodiscard]]
void* userData()
const;
1286 friend struct FiberTaskClassInternal;
1290 AlignedStorage<FiberContextStorageSize, FiberContextStorageAlignment> contextStorage;
1292 Procedure procedure;
1308 Span<char> originStackMemory;
1311 void* runningWorker =
nullptr;
1312 void* stackOwner =
nullptr;
1313 void* taskUserData =
nullptr;
1314 Result taskResult = Result(
true);
1315 volatile int32_t taskStatus =
static_cast<int32_t
>(FiberTaskStatus::Invalid);
1316 FiberTaskSuspendAction suspendAction = FiberTaskSuspendAction::None;
1317 volatile bool cancelRequested =
false;
1318 bool suspendInterruptible =
false;
1320 [[nodiscard]] FiberContext& context();
1321 [[nodiscard]]
const FiberContext& context()
const;
1326 static constexpr int Windows = 96;
1327 static constexpr int Apple = 96;
1328 static constexpr int Linux = 96;
1329 static constexpr int Default = 96;
1330 static constexpr size_t Alignment =
alignof(
void*);
1332 using Object = FiberTaskClassInternal;
1334using FiberTaskClassOpaque = OpaqueObject<FiberTaskClassDefinition>;
1338 size_t maxTasks = 0;
1343 size_t capacity = 0;
1344 size_t activeTasks = 0;
1345 size_t availableTasks = 0;
1346 size_t peakActiveTasks = 0;
1361 [[nodiscard]] Result acquire(
FiberTask*& outTask);
1362 [[nodiscard]] Result release(
FiberTask& task);
1363 [[nodiscard]] Result waitForAvailableSlot(
FiberScheduler& scheduler);
1364 [[nodiscard]] Result validateClose()
const;
1365 [[nodiscard]] Result close();
1368 [[nodiscard]]
bool isOpen()
const;
1369 [[nodiscard]]
bool owns(
const FiberTask& task)
const;
1370 [[nodiscard]]
size_t capacity()
const;
1371 [[nodiscard]]
size_t activeCount()
const;
1372 [[nodiscard]]
size_t availableCount()
const;
1377 FiberTaskClassOpaque internal;
1389 [[nodiscard]]
size_t value()
const;
1394 volatile size_t counterValue = 0;
1404 Result result = Result(
true);
1426 Result waitAll(Result* outFirstError =
nullptr);
1427 Result waitAllCancelOnParentCancel(Result* outFirstError =
nullptr);
1428 Result waitCancelOnError(Result* outFirstError =
nullptr);
1433 [[nodiscard]]
size_t pending()
const;
1434 [[nodiscard]]
size_t countErrors()
const;
1435 Result collectErrors(Span<FiberTaskGroupError> errors,
size_t& outErrors)
const;
1444 Result prepareSpawn()
const;
1446 Result findFirstError(Result* outFirstError)
const;
1452 size_t capacity = 0;
1453 size_t activeTasks = 0;
1454 size_t availableTasks = 0;
1455 bool classBacked =
false;
1464 FiberTaskPool(Span<FiberTask> taskStorage, Span<char> stackStorage,
size_t stackSize);
1480 [[nodiscard]]
size_t capacity()
const;
1481 [[nodiscard]]
size_t activeCount()
const;
1482 [[nodiscard]]
size_t availableCount()
const;
1483 [[nodiscard]]
bool hasAvailableTask()
const;
1489 [[nodiscard]]
size_t stackSizeInBytes()
const;
1490 void fillHighWaterMarks();
1491 Result stackHighWaterUsedBytes(
size_t stackIndex,
size_t& outBytes)
const;
1492 Result stackHighWaterUnusedBytes(
size_t stackIndex,
size_t& outBytes)
const;
1501 WaitNode* next =
nullptr;
1503 size_t minimumAvailable = 1;
1504 bool notified =
false;
1507 Span<FiberTask> tasks;
1509 size_t stackSize = 0;
1510 size_t nextTask = 0;
1515 WaitNode* availabilityWaitHead =
nullptr;
1516 WaitNode* availabilityWaitTail =
nullptr;
1518 mutable volatile int32_t primitiveLock = 0;
1520 Result stackAt(
size_t stackIndex,
FiberStack& outStack)
const;
1521 void queueAvailabilityWaiter(WaitNode& node);
1523 bool removeAvailabilityWaiter(WaitNode& node);
1540 [[nodiscard]]
bool isSignaled()
const;
1546 WaitNode* next =
nullptr;
1547 bool notified =
false;
1550 WaitNode* waitHead =
nullptr;
1551 WaitNode* waitTail =
nullptr;
1552 bool signaled =
false;
1553 mutable volatile int32_t primitiveLock = 0;
1555 void queueWaiter(WaitNode& node);
1556 bool removeWaiter(WaitNode& node);
1573 [[nodiscard]]
bool isSignaled()
const;
1579 WaitNode* next =
nullptr;
1580 bool notified =
false;
1583 WaitNode* waitHead =
nullptr;
1584 WaitNode* waitTail =
nullptr;
1585 bool signaled =
false;
1586 mutable volatile int32_t primitiveLock = 0;
1588 void queueWaiter(WaitNode& node);
1589 bool popWaiter(WaitNode*& node);
1590 bool removeWaiter(WaitNode& node);
1606 [[nodiscard]]
size_t available()
const;
1612 WaitNode* next =
nullptr;
1613 bool notified =
false;
1616 WaitNode* waitHead =
nullptr;
1617 WaitNode* waitTail =
nullptr;
1618 size_t availableCount = 0;
1619 mutable volatile int32_t primitiveLock = 0;
1621 void queueWaiter(WaitNode& node);
1622 WaitNode* popWaiter();
1623 bool removeWaiter(WaitNode& node);
1638 [[nodiscard]]
bool isLocked()
const;
1639 [[nodiscard]]
bool isOwnedByCurrentTask(
FiberScheduler& scheduler)
const;
1645 WaitNode* next =
nullptr;
1647 bool notified =
false;
1650 WaitNode* waitHead =
nullptr;
1651 WaitNode* waitTail =
nullptr;
1652 bool locked =
false;
1654 mutable volatile int32_t primitiveLock = 0;
1656 void queueWaiter(WaitNode& node);
1657 WaitNode* popWaiter();
1658 bool removeWaiter(WaitNode& node);
1672 Result enableRuntimeOwnedStacks();
1673 [[nodiscard]]
bool usesRuntimeOwnedStacks()
const;
1674 [[nodiscard]] Result checkExecutionThread()
const;
1684 Result runOnce(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1687 Result runNoWait(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1688 Result runReadyFibers();
1690 Result runReadyFibers(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1693 Result run(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1694 Result createWorkerDeques(
FiberAllocator& allocator, Span<FiberWorker> workers,
size_t capacityPerWorker);
1695 void releaseWorkerDeques(Span<FiberWorker> workers);
1699 Result shutdown(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1703 Result requestCancelAll();
1711 void clearTraceHooks();
1714 [[nodiscard]]
const FiberTask* currentTask()
const;
1715 [[nodiscard]]
bool isCurrentTaskCancellationRequested()
const;
1717 [[nodiscard]]
bool hasReadyFibers()
const;
1718 [[nodiscard]]
bool hasActiveFibers()
const;
1719 [[nodiscard]]
size_t readyFiberCount()
const;
1720 [[nodiscard]]
size_t readyFiberCount(
const FiberWorker& worker)
const;
1721 [[nodiscard]]
size_t stolenFiberCount(
const FiberWorker& worker)
const;
1722 [[nodiscard]]
size_t stolenFiberCount(Span<FiberWorker> workers)
const;
1723 [[nodiscard]]
size_t activeFiberCount()
const;
1725 void resetSchedulerDiagnostics();
1730 void resetWorkerDiagnostics(Span<FiberWorker> workers);
1735 struct InjectionSlot;
1741 InjectionSlot* injectionQueue =
nullptr;
1743 size_t injectionCapacity = 0;
1744 volatile size_t injectionHead = 0;
1745 volatile size_t injectionTail = 0;
1746 volatile size_t injectionReady = 0;
1747 volatile size_t injectionPublishing = 0;
1748 volatile size_t injectionPeak = 0;
1749 size_t injectionSpills = 0;
1750 volatile size_t injectionClaimBatchPeak = 0;
1752 mutable volatile int32_t injectionLock = 0;
1754 mutable size_t injectionLockAcquisitions = 0;
1755 mutable size_t injectionLockContentions = 0;
1756 mutable size_t injectionLockSpinRetries = 0;
1757 mutable size_t injectionLockPeakSpinRetries = 0;
1761 void* runtimeStackThread =
nullptr;
1763 volatile size_t readyFibers = 0;
1764 volatile size_t globalReadyFibers = 0;
1765 volatile size_t activeFibers = 0;
1767 mutable volatile int32_t schedulerLock = 0;
1769 mutable size_t schedulerLockAcquisitions = 0;
1770 mutable size_t schedulerLockContentions = 0;
1771 mutable size_t schedulerLockSpinRetries = 0;
1772 mutable size_t schedulerLockPeakSpinRetries = 0;
1774 mutable size_t schedulerLockSpawn = 0;
1775 mutable size_t schedulerLockReady = 0;
1776 mutable size_t schedulerLockSynchronization = 0;
1777 mutable size_t schedulerLockCompletion = 0;
1778 mutable size_t schedulerLockControl = 0;
1782 enum class LockCategory : uint8_t
1792 struct InjectionLockGuard;
1794 void lock(LockCategory category)
const;
1795 void unlock()
const;
1796 void lockInjection()
const;
1797 void unlockInjection()
const;
1798 void trace(FiberTraceEventType type,
FiberTask* task,
FiberWorker* worker,
size_t value = 0)
const;
1801 Result initializeTaskForSpawn(
FiberTask& task,
FiberStack& stack, FiberTask::Procedure procedure,
1806 Result createInjectionQueue(
FiberAllocator& allocator,
size_t capacity);
1807 void releaseInjectionQueue();
1808 [[nodiscard]]
bool tryReserveInjection(
size_t& position);
1809 void publishInjection(
size_t position,
FiberTask* task);
1810 void discardInjectionTombstones();
1811 [[nodiscard]]
bool tryPushInjectionUnlocked(
FiberTask& task);
1812 [[nodiscard]]
FiberTask* popInjection();
1813 [[nodiscard]]
size_t popInjectionTasks(Span<FiberTask*> tasks);
1814 void notifyReadyWorkUnlocked();
1815 void pushReadyUnlocked(
FiberTask& task);
1820 [[nodiscard]]
FiberTask* popReadyUnlocked();
1823 [[nodiscard]]
FiberTask* popReadyUnlocked(
FiberWorker& worker, Span<FiberWorker> stealWorkers);
1826 [[nodiscard]]
FiberTask* stealReadyUnlocked(
FiberWorker& worker, Span<FiberWorker> stealWorkers);
1831 void publishSuspensionUnlocked(
FiberTask& task);
1832 void finishCurrentTask(
FiberTask& task, Result result);
1833 Result cancelTaskUnlocked(
FiberTask& task);
1834 void linkActiveUnlocked(
FiberTask& task);
1835 void unlinkActiveUnlocked(
FiberTask& task);
1837 void adoptWorkerReadyUnlocked(
FiberWorker& worker);
1838 void unlinkWorkerActive(
FiberTask& task);
1841 Result waitImpl(
FiberCounter& counter,
bool interruptible);
1843 void wakeCounterWaitersUnlocked(
FiberCounter& counter);
1845 static void taskEntry(
void* userData);
1848#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
Explicit allocator for future fiber scheduler storage.
Definition Fibers.h:347
Auto-reset event that wakes one waiting fiber per signal.
Definition Fibers.h:1561
Result wait(FiberScheduler &scheduler)
Must be called from a fiber owned by scheduler.
Caller-owned cancellation source shared by one or more fiber tasks.
Definition Fibers.h:717
Lightweight cancellation token copied into spawned fiber tasks.
Definition Fibers.h:740
Counter used to suspend fibers until a group of operations completes.
Definition Fibers.h:1382
Manual-reset event that wakes waiting fibers when signaled.
Definition Fibers.h:1528
Result wait(FiberScheduler &scheduler)
Must be called from a fiber owned by scheduler.
Allocator-backed fixed-capacity storage for stable FiberJob records.
Definition Fibers.h:1129
Restricted execution context passed to a run-to-completion FiberJob.
Definition Fibers.h:769
Retains one bounded wave of pooled FiberJob results for aggregate inspection.
Definition Fibers.h:1202
Fixed-capacity owner of reusable FiberJob records with explicit completed-result release.
Definition Fibers.h:1155
Fixed-capacity scheduler for stackless run-to-completion jobs.
Definition Fibers.h:904
void workerDiagnostics(const FiberJobWorker &worker, FiberJobWorkerDiagnostics &outDiagnostics) const
Diagnostics remain available after a worker pool joins and reset when its deque is configured again.
size_t readyJobCount() const
Returns the exact stable count. A concurrent batch ownership transfer may conservatively overcount.
Result spawn(Span< FiberJob > jobs, FiberJob::Procedure procedure)
Transactionally publishes distinct contiguous records to the current worker or bounded external queue...
size_t activeJobCount() const
Returns the exact stable count. A concurrent batch ownership transfer may conservatively overcount.
bool hasReadyJobs() const
Confirms zero while preventing new ready-count activation across accounting domains.
bool hasActiveJobs() const
Confirms zero while preventing new active-count activation across accounting domains.
No-allocation OS-thread-owning pool for bounded stackless FiberJob execution.
Definition Fibers.h:1033
Result requestStop()
Requests scheduler-wide cooperative cancellation and wakes every worker before the pool drains.
Result join()
Persistent pools reject join until requestStop() has established the terminal boundary.
Result waitIdle()
Waits for the scheduler to reach an idle observation point without stopping a persistent pool.
Caller-owned OS thread storage used by FiberJobWorkerPool.
Definition Fibers.h:989
Caller-owned parallel execution agent for the FiberJob runtime.
Definition Fibers.h:844
Caller-owned stackless CPU job. Its address must remain stable while active.
Definition Fibers.h:786
Cooperative mutex for fibers running on one FiberScheduler.
Definition Fibers.h:1628
Cooperative fiber scheduler with explicit workers and caller-owned storage.
Definition Fibers.h:1663
static bool supportsRuntimeOwnedStacks()
Opt in before spawning. The scheduler remains bound to this thread and rejects worker pools.
Counting semaphore for cooperative fibers.
Definition Fibers.h:1595
Result wait(FiberScheduler &scheduler)
Must be called from a fiber owned by scheduler.
Virtual-memory-backed fixed-size stack slots with caller-controlled capacity.
Definition Fibers.h:278
Explicit owner of process integration required by incrementally committed fiber stacks.
Definition Fibers.h:126
Thread-affine registration for one thread that may execute incrementally committed fiber stacks.
Definition Fibers.h:161
Result create(FiberStackGrowthRuntime &runtime, Span< char > signalStackStorage)
POSIX requires caller-owned alternate signal-stack storage; Windows accepts an empty span.
Common requested sizes for virtual fiber stack classes.
Definition Fibers.h:105
Caller-owned stack storage used by fiber contexts.
Definition Fibers.h:180
static FiberStack runtimeOwned(size_t sizeInBytes)
Fil-C/glibc only: request a hidden runtime-owned stack, not caller storage.
size_t highWaterUsedBytes() const
Runtime-owned stacks expose no measurements; both high-water counters return zero.
Allocator-backed fixed-capacity storage for reusable FiberTask objects.
Definition Fibers.h:1351
One failed task collected from a FiberTaskGroup.
Definition Fibers.h:1402
Convenience helper for spawning a group of child tasks and waiting on their completion.
Definition Fibers.h:1409
Result reset()
Releases completed task records after result/error inspection. Fails while tasks are pending.
Caller-owned pool that pairs FiberTask objects with fixed-size stack slots.
Definition Fibers.h:1451
Result waitForAvailableTasks(FiberScheduler &scheduler, size_t minimumAvailable)
Suspends until at least minimumAvailable task/stack pairs can be acquired.
Optional scheduling inputs used when the short spawn overloads are not expressive enough.
Definition Fibers.h:1239
Caller-owned task object scheduled by FiberScheduler.
Definition Fibers.h:1263
Options for reserving a virtual-memory-backed fiber stack.
Definition Fibers.h:224
Virtual-memory-backed stack storage with an optional no-access guard page below the stack.
Definition Fibers.h:401
Span< char > stackGrowthSignalStackStorage
POSIX requires at least workerCount * FiberStackGrowthSignalStackSize bytes; Windows ignores this spa...
Definition Fibers.h:569
No-allocation OS-thread-owning worker pool using caller-provided worker and thread storage.
Definition Fibers.h:657
void wakeDiagnostics(FiberWorkerPoolWakeDiagnostics &outDiagnostics) const
Returns wake diagnostics for the current or most recently joined run.
size_t parkedWorkerCount() const
Workers currently blocked in the pool wake wait.
Caller-owned OS thread storage used by FiberWorkerPool.
Definition Fibers.h:516
Caller-owned execution agent for running ready fibers on the current OS thread.
Definition Fibers.h:446