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"
28SC_DECLARE_ASSERT_PROVIDER(FibersAssert, SC_FIBERS_EXPORT);
30#define SC_FIBERS_ASSERT_RELEASE(e) SC_ASSERT_PROVIDER_RELEASE(SC::FibersAssert, e)
31#define SC_FIBERS_ASSERT_DEBUG(e) SC_ASSERT_PROVIDER_DEBUG(SC::FibersAssert, e)
32#define SC_FIBERS_TRUST_RESULT(expression) SC_FIBERS_ASSERT_RELEASE(expression)
35struct FiberAutoResetEvent;
40struct FiberJobClassDiagnostics;
41struct FiberJobClassInternal;
42struct FiberJobClassOptions;
43struct FiberJobContext;
46struct FiberJobScheduler;
48struct FiberJobWorkerPool;
49struct FiberJobWorkerPoolThreadEntry;
50struct FiberJobWorkerThread;
56struct FiberTaskClassDiagnostics;
57struct FiberTaskClassInternal;
58struct FiberTaskClassOptions;
60struct FiberTaskPoolDiagnostics;
62struct FiberVirtualStack;
63struct FiberVirtualStackInternal;
64struct FiberVirtualStackOptions;
65struct FiberStackClass;
66struct FiberStackClassDiagnostics;
67struct FiberStackClassInternal;
68struct FiberStackClassOptions;
69struct FiberSchedulerDiagnostics;
70struct FiberTraceEvent;
71struct FiberTraceHooks;
73struct FiberAllocatorInterface;
74struct FiberAllocatorVirtualOptions;
76struct FiberWorkerPoolWakeEvent;
77struct FiberWorkerPool;
78struct FiberWorkerPoolOptions;
79struct FiberWorkerPoolThreadEntry;
80struct FiberWorkerThread;
82#if SC_PLATFORM_WINDOWS
83static constexpr int FiberContextStorageSize = 2048;
84#elif SC_PLATFORM_ARM64
85static constexpr int FiberContextStorageSize = 224;
87static constexpr int FiberContextStorageSize = 128;
89static constexpr int FiberContextStorageAlignment = 16;
90static constexpr int FiberStackAlignment = 16;
91static constexpr int FiberStackMinimumSize = 4096;
93static constexpr int FiberInjectionSlotStorageSize =
sizeof(
void*) +
sizeof(
size_t);
99 static constexpr size_t FourKiB = 4 * 1024;
100 static constexpr size_t EightKiB = 8 * 1024;
101 static constexpr size_t ThirtyTwoKiB = 32 * 1024;
102 static constexpr size_t SixtyFourKiB = 64 * 1024;
110 [[nodiscard]] Span<char> memory()
const;
111 [[nodiscard]]
size_t sizeInBytes()
const;
112 [[nodiscard]]
size_t usableSizeInBytes()
const;
113 [[nodiscard]]
size_t alignmentWasteInBytes()
const;
114 [[nodiscard]]
bool isUsable()
const;
115 void fillHighWaterMark();
116 [[nodiscard]]
size_t highWaterUsedBytes()
const;
117 [[nodiscard]]
size_t highWaterUnusedBytes()
const;
125 Span<char> stackMemory;
126 void* stackOwner =
nullptr;
131 static constexpr int Windows = 64;
132 static constexpr int Apple = 64;
133 static constexpr int Linux = 64;
134 static constexpr int Default = 64;
135 static constexpr size_t Alignment =
alignof(
void*);
137 using Object = FiberVirtualStackInternal;
139using FiberVirtualStackOpaque = OpaqueObject<FiberVirtualStackDefinition>;
144 size_t usableSizeInBytes = FiberStackSize::SixtyFourKiB;
145 bool guardPage =
true;
150 static constexpr int Windows = 176;
151 static constexpr int Apple = 176;
152 static constexpr int Linux = 176;
153 static constexpr int Default = 176;
154 static constexpr size_t Alignment =
alignof(
void*);
156 using Object = FiberStackClassInternal;
158using FiberStackClassOpaque = OpaqueObject<FiberStackClassDefinition>;
162 size_t stackSizeInBytes = FiberStackSize::SixtyFourKiB;
163 size_t maxStacks = 0;
164 bool guardPage =
true;
170 size_t activeStacks = 0;
171 size_t peakActiveStacks = 0;
172 size_t stackSizeInBytes = 0;
173 size_t guardSizeInBytes = 0;
174 size_t reservedSizeBytes = 0;
175 size_t committedSizeBytes = 0;
176 size_t peakCommittedBytes = 0;
177 size_t highWaterUsedBytes = 0;
192 [[nodiscard]] Result acquire(
FiberStack& outStack);
193 [[nodiscard]] Result release(
FiberStack& stack);
194 [[nodiscard]] Result waitForAvailableSlot(
FiberScheduler& scheduler);
196 void fillHighWaterMarks();
199 [[nodiscard]]
bool isReserved()
const;
200 [[nodiscard]]
bool owns(
const FiberStack& stack)
const;
201 [[nodiscard]]
size_t capacity()
const;
202 [[nodiscard]]
size_t activeCount()
const;
207 FiberStackClassOpaque internal;
210enum class FiberAllocatorMode : uint8_t
221 size_t numAllocations = 0;
222 size_t numReleases = 0;
224 size_t requestedBytesAllocated = 0;
225 size_t requestedBytesReleased = 0;
227 size_t bytesInUse = 0;
228 size_t peakBytesInUse = 0;
230 size_t numAllocationFailures = 0;
231 size_t lastFailedAllocationSize = 0;
232 size_t largestFailedAllocationSize = 0;
237 size_t reserveBytes = 0;
238 size_t initialCommitBytes = 0;
243 virtual void* allocateImpl(
const void* owner,
size_t numBytes,
size_t alignment) = 0;
244 virtual void releaseImpl(
void* memory) = 0;
258 [[nodiscard]] Result createFixed(Span<char> storage);
260 [[nodiscard]] Result createMalloc();
262 [[nodiscard]] Result validateClose()
const;
263 [[nodiscard]] Result close();
265 [[nodiscard]]
void* allocate(
const void* owner,
size_t numBytes,
size_t alignment);
266 void release(
void* memory);
267 static void releaseFromAnyAllocator(
void* memory);
269 [[nodiscard]] FiberAllocatorMode mode()
const;
271 [[nodiscard]]
bool isOpen()
const;
273 [[nodiscard]]
size_t used()
const;
274 [[nodiscard]]
size_t capacity()
const;
275 [[nodiscard]]
size_t peakUsed()
const;
276 [[nodiscard]]
size_t failedAllocationSize()
const;
277 [[nodiscard]]
size_t reservedBytes()
const;
278 [[nodiscard]]
size_t committedBytes()
const;
283 Result initializeFixedStorage(Span<char> storage);
284 void* allocateFromBlocks(
const void* owner,
size_t numBytes,
size_t alignment);
285 void releaseBlock(BlockHeader& header);
286 bool ensureCommitted(
size_t sizeInBytes);
287 void releaseVirtualMemory();
288 void recordAllocationFailure(
size_t numBytes);
291 FiberAllocatorMode currentMode = FiberAllocatorMode::None;
293 Span<char> fixedStorage;
294 BlockHeader* firstBlock =
nullptr;
297 void* virtualMemory =
nullptr;
298 size_t virtualReservedBytes = 0;
299 size_t virtualCommittedBytes = 0;
317 [[nodiscard]] Span<char> memory()
const;
318 [[nodiscard]]
size_t usableSizeInBytes()
const;
319 [[nodiscard]]
size_t reservedSizeInBytes()
const;
320 [[nodiscard]]
size_t guardSizeInBytes()
const;
321 [[nodiscard]]
bool isReserved()
const;
324 FiberVirtualStackOpaque internal;
328enum class FiberTaskStatus
338enum class FiberTaskSuspendAction
345struct FiberCancellationToken;
356 [[nodiscard]]
bool isActive()
const;
360 [[nodiscard]]
const FiberTask* runningTask()
const;
377 size_t localReadyFibers = 0;
378 size_t localDequeCapacity = 0;
379 size_t localDequeHead = 0;
380 volatile size_t localDequeTop = 0;
381 volatile size_t localDequeBottom = 0;
382 size_t localReadyPeakFibers = 0;
383 size_t localSpilledFibers = 0;
384 size_t stealAttempts = 0;
385 size_t stealVictimProbes = 0;
386 size_t stolenFibers = 0;
387 size_t stolenBatches = 0;
388 size_t stolenBatchPeak = 0;
389 size_t failedSteals = 0;
390 size_t stealCursor = 0;
391 volatile size_t runAttempts = 0;
392 volatile size_t idlePolls = 0;
393 volatile size_t idleSpinIterations = 0;
394 volatile size_t parkAttempts = 0;
395 volatile size_t parkedWakeups = 0;
396 volatile size_t executedFibers = 0;
397 size_t completedFibers = 0;
398 volatile size_t yieldedFibers = 0;
399 size_t waitingFibers = 0;
400 volatile int32_t activeRegistryLock = 0;
401 bool workerActive =
false;
402 bool localSchedulingActive =
false;
403 bool stealCursorInitialized =
false;
405 AlignedStorage<FiberContextStorageSize, FiberContextStorageAlignment> rootContextStorage;
407 [[nodiscard]] FiberContext& rootContext();
410#if SC_PLATFORM_WINDOWS
411static constexpr int FiberWorkerThreadStorageSize =
sizeof(
void*);
413static constexpr int FiberWorkerThreadStorageSize =
sizeof(
void*) * 2;
415static constexpr int FiberWorkerThreadStorageAlignment =
alignof(
void*);
426 [[nodiscard]]
bool wasStarted()
const;
427 [[nodiscard]] Result result()
const;
431 friend struct FiberWorkerPoolThreadEntry;
433 AlignedStorage<FiberWorkerThreadStorageSize, FiberWorkerThreadStorageAlignment> threadStorage;
436 size_t workerIndex = 0;
437 uint64_t affinityMask = 0;
438 uint8_t priority = 0;
439 Result threadResult = Result(
true);
440 bool started =
false;
442 Result startThread();
444 Result runThreadEntry();
445 Result applyThreadPolicy();
448enum class FiberWorkerThreadPriority : uint8_t
459 size_t dequeCapacityPerWorker = 0;
461 size_t injectionCapacity = 0;
462 size_t idleSpinAttempts = 32;
463 Span<const uint64_t> affinityMasks;
464 FiberWorkerThreadPriority threadPriority = FiberWorkerThreadPriority::Default;
469 size_t readyFibers = 0;
470 size_t readyPeakFibers = 0;
471 size_t dequeCapacity = 0;
472 size_t spilledFibers = 0;
473 size_t stealAttempts = 0;
474 size_t stealVictimProbes = 0;
475 size_t stolenFibers = 0;
476 size_t stolenBatches = 0;
477 size_t stolenBatchPeak = 0;
478 size_t failedSteals = 0;
479 size_t runAttempts = 0;
480 size_t idlePolls = 0;
481 size_t idleSpinIterations = 0;
482 size_t parkAttempts = 0;
483 size_t parkedWakeups = 0;
484 size_t executedFibers = 0;
485 size_t completedFibers = 0;
486 size_t yieldedFibers = 0;
487 size_t waitingFibers = 0;
493 size_t wakeNotifications = 0;
495 size_t wakeSignals = 0;
500 size_t readyFibers = 0;
501 size_t globalReadyFibers = 0;
502 size_t activeFibers = 0;
503 size_t injectionCapacity = 0;
504 size_t injectionReady = 0;
505 size_t injectionPublishing = 0;
506 size_t injectionPeak = 0;
507 size_t injectionSpills = 0;
508 size_t injectionClaimBatchPeak = 0;
509 size_t injectionLockAcquisitions = 0;
510 size_t injectionLockContentions = 0;
511 size_t injectionLockSpinRetries = 0;
512 size_t injectionLockPeakSpinRetries = 0;
514 size_t lockAcquisitions = 0;
515 size_t lockContentions = 0;
516 size_t lockSpinRetries = 0;
517 size_t lockPeakSpinRetries = 0;
518 size_t lockSpawn = 0;
519 size_t lockReady = 0;
520 size_t lockSynchronization = 0;
521 size_t lockCompletion = 0;
522 size_t lockControl = 0;
525enum class FiberTraceEventType : uint8_t
535 FiberTraceEventType type = FiberTraceEventType::TaskStarted;
544 using Callback = void (*)(
void* userData,
const FiberTraceEvent& event);
546 Callback callback =
nullptr;
547 void* userData =
nullptr;
559 Result start(
FiberScheduler& scheduler, Span<FiberWorker> workerStorage, Span<FiberWorkerThread> threadStorage);
560 Result start(
FiberScheduler& scheduler, Span<FiberWorker> workerStorage, Span<FiberWorkerThread> threadStorage,
562 Result requestStop();
566 [[nodiscard]]
bool isRunning()
const;
567 [[nodiscard]]
size_t workerCount()
const;
575 static constexpr int Windows =
sizeof(
void*) * 16;
576 static constexpr int Apple =
sizeof(
void*) * 16;
577 static constexpr int Linux =
sizeof(
void*) * 16;
578 static constexpr int Default = Linux;
580 static constexpr size_t Alignment =
alignof(
void*);
582 using Object = FiberWorkerPoolWakeEvent;
585 using WakeEventOpaque = OpaqueObject<WakeEventDefinition>;
592 Span<FiberWorker> workers;
593 Span<FiberWorkerThread> threads;
594 WakeEventOpaque wakeEvent;
595 mutable volatile int32_t stopRequested = 0;
596 mutable volatile int32_t running = 0;
597 size_t idleSpinAttempts = 0;
598 bool localDequesCreated =
false;
599 bool injectionCreated =
false;
601 void wakeOneWorker();
602 void wakeAllWorkers();
603 void resetWakeDiagnostics();
604 [[nodiscard]]
bool waitForWork(uint32_t observedGeneration);
605 [[nodiscard]] uint32_t wakeGeneration()
const;
607 Result workerMain(
size_t workerIndex);
618 void requestCancel();
620 Result check()
const;
622 [[nodiscard]]
bool isCancellationRequested()
const;
630 mutable volatile int32_t requested = 0;
638 Result check()
const;
640 [[nodiscard]]
bool isValid()
const;
641 [[nodiscard]]
bool isCancellationRequested()
const;
654enum class FiberJobStatus
666 [[nodiscard]]
FiberJob& job()
const;
667 [[nodiscard]]
bool isCancellationRequested()
const;
668 Result checkCancellation()
const;
692 [[nodiscard]]
bool isActive()
const;
693 [[nodiscard]]
bool isCompleted()
const;
694 [[nodiscard]]
bool isCancellationRequested()
const;
695 [[nodiscard]] FiberJobStatus status()
const;
696 [[nodiscard]] Result result()
const;
712 Result jobResult = Result(
true);
713 volatile int32_t jobStatus =
static_cast<int32_t
>(FiberJobStatus::Invalid);
714 uint32_t cancelGeneration = 0;
715 volatile bool cancelRequested =
false;
716 bool poolRetained =
false;
721 size_t readyJobs = 0;
722 size_t readyPeakJobs = 0;
723 size_t dequeCapacity = 0;
724 size_t executedJobs = 0;
725 size_t claimBatches = 0;
726 size_t claimedJobs = 0;
727 size_t claimBatchPeak = 0;
728 size_t stealAttempts = 0;
729 size_t stolenJobs = 0;
730 size_t failedSteals = 0;
733#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
735#pragma warning(disable : 4324)
746 [[nodiscard]]
bool isActive()
const;
749 [[nodiscard]]
FiberJob* runningJob();
750 [[nodiscard]]
const FiberJob* runningJob()
const;
764 size_t localDequeCapacity = 0;
765 size_t lastDequeCapacity = 0;
766 volatile size_t localDequeTop = 0;
767 volatile size_t localDequeBottom = 0;
769 size_t localReadyPeakJobs = 0;
770 size_t executedJobs = 0;
771 size_t claimBatches = 0;
772 size_t claimedJobs = 0;
773 size_t claimBatchPeak = 0;
774 size_t stealCursor = 0;
775 size_t stealAttempts = 0;
776 size_t stolenJobs = 0;
777 size_t failedSteals = 0;
778 bool workerActive =
false;
779 bool distributedCounts =
false;
781 alignas(128)
volatile size_t ownedReadyJobs = 0;
782 alignas(128)
volatile size_t ownedActiveJobs = 0;
784#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
792#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
794#pragma warning(disable : 4324)
804 Result create(Span<FiberJob*> readyStorage);
807 Result createWorkerDeques(
FiberAllocator& allocator, Span<FiberJobWorker> workers,
size_t capacityPerWorker);
808 void releaseWorkerDeques(Span<FiberJobWorker> workers);
810 Result spawn(
FiberJob& job, FiberJob::Procedure procedure);
813 Result
spawn(Span<FiberJob> jobs, FiberJob::Procedure procedure);
815 Result runOne(
bool& outRanJob);
816 Result runOne(
FiberJobWorker& worker, Span<FiberJobWorker> workerGroup,
bool& outRanJob);
818 Result run(
FiberJobWorker& worker, Span<FiberJobWorker> workerGroup);
821 Result requestCancel(
FiberJob& job);
823 Result requestCancelAll();
825 [[nodiscard]]
bool isOpen()
const;
830 [[nodiscard]]
size_t capacity()
const;
835 [[nodiscard]]
FiberJob* currentJob();
846 Span<FiberJob*> queueStorage;
848 size_t queueHead = 0;
849 size_t queueTail = 0;
850 size_t queueCount = 0;
852 alignas(128)
volatile size_t readyJobs = 0;
853 alignas(128)
volatile size_t activeJobs = 0;
855 alignas(128)
mutable volatile int32_t queueLock = 0;
856 volatile uint32_t cancelGeneration = 0;
860 struct QueueLockGuard;
863 Result complete(
FiberJob& job, Result result);
868 bool usesDistributedAccounting(
const FiberJobWorker& worker)
const;
869 bool isWorkerStopRequested()
const;
871#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
884 [[nodiscard]]
bool wasStarted()
const;
885 [[nodiscard]] Result result()
const;
889 friend struct FiberJobWorkerPoolThreadEntry;
891 AlignedStorage<FiberWorkerThreadStorageSize, FiberWorkerThreadStorageAlignment> threadStorage;
894 size_t workerIndex = 0;
895 uint64_t affinityMask = 0;
896 uint8_t priority = 0;
897 Result threadResult = Result(
true);
898 bool started =
false;
900 Result startThread();
902 Result runThreadEntry();
903 Result applyThreadPolicy();
909 size_t dequeCapacityPerWorker = 0;
910 size_t idleSpinAttempts = 32;
913 bool keepAliveWhenIdle =
false;
915 Span<const uint64_t> affinityMasks;
916 FiberWorkerThreadPriority threadPriority = FiberWorkerThreadPriority::Default;
932 Result requestStop();
937 [[nodiscard]]
bool isRunning()
const;
938 [[nodiscard]]
size_t workerCount()
const;
939 [[nodiscard]]
size_t parkedWorkerCount()
const;
943 static constexpr int Windows =
sizeof(
void*) * 16;
944 static constexpr int Apple =
sizeof(
void*) * 16;
945 static constexpr int Linux =
sizeof(
void*) * 16;
946 static constexpr int Default = Linux;
948 static constexpr size_t Alignment =
alignof(
void*);
950 using Object = FiberWorkerPoolWakeEvent;
953 using WakeEventOpaque = OpaqueObject<WakeEventDefinition>;
960 Span<FiberJobWorker> workers;
961 Span<FiberJobWorkerThread> threads;
962 WakeEventOpaque wakeEvent;
963 mutable volatile int32_t stopRequested = 0;
964 mutable volatile int32_t running = 0;
965 size_t idleSpinAttempts = 0;
966 bool keepAliveWhenIdle =
false;
968 void wakeOneWorker();
969 void wakeAllWorkers();
970 [[nodiscard]]
bool waitForWork(uint32_t observedGeneration);
971 [[nodiscard]] uint32_t wakeGeneration()
const;
972 [[nodiscard]]
bool isStopRequested()
const;
974 Result workerMain(
size_t workerIndex);
980 size_t retainedJobs = 0;
981 size_t availableJobs = 0;
983 size_t peakRetainedJobs = 0;
988 static constexpr int Windows = 48;
989 static constexpr int Apple = 48;
990 static constexpr int Linux = 48;
991 static constexpr int Default = 48;
992 static constexpr size_t Alignment =
alignof(
void*);
994 using Object = FiberJobClassInternal;
996using FiberJobClassOpaque = OpaqueObject<FiberJobClassDefinition>;
1005 size_t capacity = 0;
1021 [[nodiscard]] Result validateClose()
const;
1022 [[nodiscard]] Result close();
1025 [[nodiscard]]
bool isOpen()
const;
1026 [[nodiscard]]
bool owns(
const FiberJob& job)
const;
1027 [[nodiscard]]
size_t capacity()
const;
1032 FiberJobClassOpaque internal;
1044 Result create(Span<FiberJob> jobStorage);
1052 [[nodiscard]]
bool isOpen()
const;
1053 [[nodiscard]]
bool owns(
const FiberJob& job)
const;
1054 [[nodiscard]]
size_t capacity()
const;
1055 [[nodiscard]]
size_t retainedCount()
const;
1056 [[nodiscard]]
size_t availableCount()
const;
1062 Span<FiberJob> jobs;
1065 size_t retainedJobs = 0;
1066 size_t peakRetainedJobs = 0;
1068 mutable volatile int32_t poolLock = 0;
1071 void releaseAcquired(
FiberJob& job);
1072 void releaseAcquiredUnlocked(
FiberJob& job);
1073 void recordPublished();
1079 Result result = Result(
true);
1095 Result requestCancel();
1098 [[nodiscard]]
size_t pendingCount()
const;
1099 [[nodiscard]]
size_t jobCount()
const;
1100 [[nodiscard]]
size_t countErrors()
const;
1101 Result collectErrors(Span<FiberJobGroupError> errors,
size_t& outErrors)
const;
1108 size_t pendingJobs = 0;
1109 size_t totalJobs = 0;
1111 mutable volatile int32_t groupLock = 0;
1113 Result prepareSpawn()
const;
1115 void unlinkSpawnFailure(
FiberJob& job);
1124 void* userData =
nullptr;
1125 bool setUserData =
false;
1138#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
1139#pragma warning(push)
1140#pragma warning(disable : 4324)
1156 [[nodiscard]]
bool isValid()
const;
1157 [[nodiscard]]
bool isStarted()
const;
1158 [[nodiscard]]
bool isCompleted()
const;
1159 [[nodiscard]]
bool isActive()
const;
1160 [[nodiscard]]
bool isCancellationRequested()
const;
1161 [[nodiscard]] FiberTaskStatus status()
const;
1162 [[nodiscard]] Result result()
const;
1163 void setUserData(
void* data);
1164 [[nodiscard]]
void* userData()
const;
1168 friend struct FiberTaskClassInternal;
1172 AlignedStorage<FiberContextStorageSize, FiberContextStorageAlignment> contextStorage;
1174 Procedure procedure;
1190 Span<char> originStackMemory;
1193 void* runningWorker =
nullptr;
1194 void* stackOwner =
nullptr;
1195 void* taskUserData =
nullptr;
1196 Result taskResult = Result(
true);
1197 volatile int32_t taskStatus =
static_cast<int32_t
>(FiberTaskStatus::Invalid);
1198 FiberTaskSuspendAction suspendAction = FiberTaskSuspendAction::None;
1199 volatile bool cancelRequested =
false;
1200 bool suspendInterruptible =
false;
1202 [[nodiscard]] FiberContext& context();
1203 [[nodiscard]]
const FiberContext& context()
const;
1208 static constexpr int Windows = 96;
1209 static constexpr int Apple = 96;
1210 static constexpr int Linux = 96;
1211 static constexpr int Default = 96;
1212 static constexpr size_t Alignment =
alignof(
void*);
1214 using Object = FiberTaskClassInternal;
1216using FiberTaskClassOpaque = OpaqueObject<FiberTaskClassDefinition>;
1220 size_t maxTasks = 0;
1225 size_t capacity = 0;
1226 size_t activeTasks = 0;
1227 size_t availableTasks = 0;
1228 size_t peakActiveTasks = 0;
1243 [[nodiscard]] Result acquire(
FiberTask*& outTask);
1244 [[nodiscard]] Result release(
FiberTask& task);
1245 [[nodiscard]] Result waitForAvailableSlot(
FiberScheduler& scheduler);
1246 [[nodiscard]] Result validateClose()
const;
1247 [[nodiscard]] Result close();
1250 [[nodiscard]]
bool isOpen()
const;
1251 [[nodiscard]]
bool owns(
const FiberTask& task)
const;
1252 [[nodiscard]]
size_t capacity()
const;
1253 [[nodiscard]]
size_t activeCount()
const;
1254 [[nodiscard]]
size_t availableCount()
const;
1259 FiberTaskClassOpaque internal;
1271 [[nodiscard]]
size_t value()
const;
1276 volatile size_t counterValue = 0;
1286 Result result = Result(
true);
1308 Result waitAll(Result* outFirstError =
nullptr);
1309 Result waitAllCancelOnParentCancel(Result* outFirstError =
nullptr);
1310 Result waitCancelOnError(Result* outFirstError =
nullptr);
1315 [[nodiscard]]
size_t pending()
const;
1316 [[nodiscard]]
size_t countErrors()
const;
1317 Result collectErrors(Span<FiberTaskGroupError> errors,
size_t& outErrors)
const;
1326 Result prepareSpawn()
const;
1328 Result findFirstError(Result* outFirstError)
const;
1334 size_t capacity = 0;
1335 size_t activeTasks = 0;
1336 size_t availableTasks = 0;
1337 bool classBacked =
false;
1346 FiberTaskPool(Span<FiberTask> taskStorage, Span<char> stackStorage,
size_t stackSize);
1362 [[nodiscard]]
size_t capacity()
const;
1363 [[nodiscard]]
size_t activeCount()
const;
1364 [[nodiscard]]
size_t availableCount()
const;
1365 [[nodiscard]]
bool hasAvailableTask()
const;
1371 [[nodiscard]]
size_t stackSizeInBytes()
const;
1372 void fillHighWaterMarks();
1373 Result stackHighWaterUsedBytes(
size_t stackIndex,
size_t& outBytes)
const;
1374 Result stackHighWaterUnusedBytes(
size_t stackIndex,
size_t& outBytes)
const;
1383 WaitNode* next =
nullptr;
1385 size_t minimumAvailable = 1;
1386 bool notified =
false;
1389 Span<FiberTask> tasks;
1391 size_t stackSize = 0;
1392 size_t nextTask = 0;
1397 WaitNode* availabilityWaitHead =
nullptr;
1398 WaitNode* availabilityWaitTail =
nullptr;
1400 mutable volatile int32_t primitiveLock = 0;
1402 Result stackAt(
size_t stackIndex,
FiberStack& outStack)
const;
1403 void queueAvailabilityWaiter(WaitNode& node);
1405 bool removeAvailabilityWaiter(WaitNode& node);
1422 [[nodiscard]]
bool isSignaled()
const;
1428 WaitNode* next =
nullptr;
1429 bool notified =
false;
1432 WaitNode* waitHead =
nullptr;
1433 WaitNode* waitTail =
nullptr;
1434 bool signaled =
false;
1435 mutable volatile int32_t primitiveLock = 0;
1437 void queueWaiter(WaitNode& node);
1438 bool removeWaiter(WaitNode& node);
1455 [[nodiscard]]
bool isSignaled()
const;
1461 WaitNode* next =
nullptr;
1462 bool notified =
false;
1465 WaitNode* waitHead =
nullptr;
1466 WaitNode* waitTail =
nullptr;
1467 bool signaled =
false;
1468 mutable volatile int32_t primitiveLock = 0;
1470 void queueWaiter(WaitNode& node);
1471 bool popWaiter(WaitNode*& node);
1472 bool removeWaiter(WaitNode& node);
1488 [[nodiscard]]
size_t available()
const;
1494 WaitNode* next =
nullptr;
1495 bool notified =
false;
1498 WaitNode* waitHead =
nullptr;
1499 WaitNode* waitTail =
nullptr;
1500 size_t availableCount = 0;
1501 mutable volatile int32_t primitiveLock = 0;
1503 void queueWaiter(WaitNode& node);
1504 WaitNode* popWaiter();
1505 bool removeWaiter(WaitNode& node);
1520 [[nodiscard]]
bool isLocked()
const;
1521 [[nodiscard]]
bool isOwnedByCurrentTask(
FiberScheduler& scheduler)
const;
1527 WaitNode* next =
nullptr;
1529 bool notified =
false;
1532 WaitNode* waitHead =
nullptr;
1533 WaitNode* waitTail =
nullptr;
1534 bool locked =
false;
1536 mutable volatile int32_t primitiveLock = 0;
1538 void queueWaiter(WaitNode& node);
1539 WaitNode* popWaiter();
1540 bool removeWaiter(WaitNode& node);
1560 Result runOnce(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1563 Result runNoWait(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1564 Result runReadyFibers();
1566 Result runReadyFibers(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1569 Result run(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1570 Result createWorkerDeques(
FiberAllocator& allocator, Span<FiberWorker> workers,
size_t capacityPerWorker);
1571 void releaseWorkerDeques(Span<FiberWorker> workers);
1575 Result shutdown(
FiberWorker& worker, Span<FiberWorker> workerGroup);
1579 Result requestCancelAll();
1587 void clearTraceHooks();
1590 [[nodiscard]]
const FiberTask* currentTask()
const;
1591 [[nodiscard]]
bool isCurrentTaskCancellationRequested()
const;
1593 [[nodiscard]]
bool hasReadyFibers()
const;
1594 [[nodiscard]]
bool hasActiveFibers()
const;
1595 [[nodiscard]]
size_t readyFiberCount()
const;
1596 [[nodiscard]]
size_t readyFiberCount(
const FiberWorker& worker)
const;
1597 [[nodiscard]]
size_t stolenFiberCount(
const FiberWorker& worker)
const;
1598 [[nodiscard]]
size_t stolenFiberCount(Span<FiberWorker> workers)
const;
1599 [[nodiscard]]
size_t activeFiberCount()
const;
1601 void resetSchedulerDiagnostics();
1606 void resetWorkerDiagnostics(Span<FiberWorker> workers);
1611 struct InjectionSlot;
1617 InjectionSlot* injectionQueue =
nullptr;
1619 size_t injectionCapacity = 0;
1620 volatile size_t injectionHead = 0;
1621 volatile size_t injectionTail = 0;
1622 volatile size_t injectionReady = 0;
1623 volatile size_t injectionPublishing = 0;
1624 volatile size_t injectionPeak = 0;
1625 size_t injectionSpills = 0;
1626 volatile size_t injectionClaimBatchPeak = 0;
1628 mutable volatile int32_t injectionLock = 0;
1630 mutable size_t injectionLockAcquisitions = 0;
1631 mutable size_t injectionLockContentions = 0;
1632 mutable size_t injectionLockSpinRetries = 0;
1633 mutable size_t injectionLockPeakSpinRetries = 0;
1637 volatile size_t readyFibers = 0;
1638 volatile size_t globalReadyFibers = 0;
1639 volatile size_t activeFibers = 0;
1641 mutable volatile int32_t schedulerLock = 0;
1643 mutable size_t schedulerLockAcquisitions = 0;
1644 mutable size_t schedulerLockContentions = 0;
1645 mutable size_t schedulerLockSpinRetries = 0;
1646 mutable size_t schedulerLockPeakSpinRetries = 0;
1648 mutable size_t schedulerLockSpawn = 0;
1649 mutable size_t schedulerLockReady = 0;
1650 mutable size_t schedulerLockSynchronization = 0;
1651 mutable size_t schedulerLockCompletion = 0;
1652 mutable size_t schedulerLockControl = 0;
1656 enum class LockCategory : uint8_t
1666 struct InjectionLockGuard;
1668 void lock(LockCategory category)
const;
1669 void unlock()
const;
1670 void lockInjection()
const;
1671 void unlockInjection()
const;
1672 void trace(FiberTraceEventType type,
FiberTask* task,
FiberWorker* worker,
size_t value = 0)
const;
1675 Result initializeTaskForSpawn(
FiberTask& task,
FiberStack& stack, FiberTask::Procedure procedure,
1680 Result createInjectionQueue(
FiberAllocator& allocator,
size_t capacity);
1681 void releaseInjectionQueue();
1682 [[nodiscard]]
bool tryReserveInjection(
size_t& position);
1683 void publishInjection(
size_t position,
FiberTask* task);
1684 void discardInjectionTombstones();
1685 [[nodiscard]]
bool tryPushInjectionUnlocked(
FiberTask& task);
1686 [[nodiscard]]
FiberTask* popInjection();
1687 void notifyReadyWorkUnlocked();
1688 void pushReadyUnlocked(
FiberTask& task);
1693 [[nodiscard]]
FiberTask* popReadyUnlocked();
1696 [[nodiscard]]
FiberTask* popReadyUnlocked(
FiberWorker& worker, Span<FiberWorker> stealWorkers);
1699 [[nodiscard]]
FiberTask* stealReadyUnlocked(
FiberWorker& worker, Span<FiberWorker> stealWorkers);
1704 void publishSuspensionUnlocked(
FiberTask& task);
1705 void finishCurrentTask(
FiberTask& task, Result result);
1706 Result cancelTaskUnlocked(
FiberTask& task);
1707 void linkActiveUnlocked(
FiberTask& task);
1708 void unlinkActiveUnlocked(
FiberTask& task);
1710 void adoptWorkerReadyUnlocked(
FiberWorker& worker);
1711 void unlinkWorkerActive(
FiberTask& task);
1714 Result waitImpl(
FiberCounter& counter,
bool interruptible);
1716 void wakeCounterWaitersUnlocked(
FiberCounter& counter);
1718 static void taskEntry(
void* userData);
1721#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
Explicit allocator for future fiber scheduler storage.
Definition Fibers.h:250
Auto-reset event that wakes one waiting fiber per signal.
Definition Fibers.h:1443
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:612
Lightweight cancellation token copied into spawned fiber tasks.
Definition Fibers.h:635
Counter used to suspend fibers until a group of operations completes.
Definition Fibers.h:1264
Manual-reset event that wakes waiting fibers when signaled.
Definition Fibers.h:1410
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:1011
Restricted execution context passed to a run-to-completion FiberJob.
Definition Fibers.h:664
Retains one bounded wave of pooled FiberJob results for aggregate inspection.
Definition Fibers.h:1084
Fixed-capacity owner of reusable FiberJob records with explicit completed-result release.
Definition Fibers.h:1037
Fixed-capacity scheduler for stackless run-to-completion jobs.
Definition Fibers.h:797
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
Never reports false while ready work transfers from the external queue to a worker.
bool hasActiveJobs() const
Never reports false while active work transfers from the external queue to a worker.
No-allocation OS-thread-owning pool for bounded stackless FiberJob execution.
Definition Fibers.h:921
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:877
Caller-owned parallel execution agent for the FiberJob runtime.
Definition Fibers.h:739
Caller-owned stackless CPU job. Its address must remain stable while active.
Definition Fibers.h:681
Cooperative mutex for fibers running on one FiberScheduler.
Definition Fibers.h:1510
Cooperative fiber scheduler with explicit workers and caller-owned storage.
Definition Fibers.h:1545
Counting semaphore for cooperative fibers.
Definition Fibers.h:1477
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:182
Common requested sizes for virtual fiber stack classes.
Definition Fibers.h:98
Caller-owned stack storage used by fiber contexts.
Definition Fibers.h:107
Allocator-backed fixed-capacity storage for reusable FiberTask objects.
Definition Fibers.h:1233
One failed task collected from a FiberTaskGroup.
Definition Fibers.h:1284
Convenience helper for spawning a group of child tasks and waiting on their completion.
Definition Fibers.h:1291
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:1333
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:1121
Caller-owned task object scheduled by FiberScheduler.
Definition Fibers.h:1145
Options for reserving a virtual-memory-backed fiber stack.
Definition Fibers.h:143
Virtual-memory-backed stack storage with an optional no-access guard page below the stack.
Definition Fibers.h:304
No-allocation OS-thread-owning worker pool using caller-provided worker and thread storage.
Definition Fibers.h:552
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:419
Caller-owned execution agent for running ready fibers on the current OS thread.
Definition Fibers.h:349