Sane C++ Libraries
C++ Platform Abstraction Libraries
Loading...
Searching...
No Matches
Fibers.h
1// Copyright (c) Stefano Cristiano
2// SPDX-License-Identifier: MIT
3#pragma once
4
5#include "../Common/CompilerMacrosExport.h"
6#ifndef SC_EXPORT_LIBRARY_FIBERS
7#define SC_EXPORT_LIBRARY_FIBERS 0
8#endif
9#define SC_FIBERS_EXPORT SC_COMPILER_LIBRARY_EXPORT(SC_EXPORT_LIBRARY_FIBERS)
10
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"
21
24
27namespace SC
28{
29SC_DECLARE_ASSERT_PROVIDER(FibersAssert, SC_FIBERS_EXPORT);
30
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)
34
35struct FiberCounter;
36struct FiberAutoResetEvent;
37struct FiberContext;
38struct FiberEvent;
39struct FiberJob;
40struct FiberJobClass;
41struct FiberJobClassDiagnostics;
42struct FiberJobClassInternal;
43struct FiberJobClassOptions;
44struct FiberJobContext;
45struct FiberJobGroup;
46struct FiberJobPool;
47struct FiberJobScheduler;
48struct FiberJobWorker;
49struct FiberJobWorkerPool;
50struct FiberJobWorkerPoolThreadEntry;
51struct FiberJobWorkerThread;
52struct FiberMutex;
53struct FiberSemaphore;
54struct FiberScheduler;
55struct FiberTaskGroup;
56struct FiberTaskClass;
57struct FiberTaskClassDiagnostics;
58struct FiberTaskClassInternal;
59struct FiberTaskClassOptions;
60struct FiberTaskPool;
61struct FiberTaskPoolDiagnostics;
62struct FiberTask;
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;
77struct FiberAllocator;
78struct FiberAllocatorInterface;
79struct FiberAllocatorVirtualOptions;
80struct FiberWorker;
81struct FiberWorkerPoolWakeEvent;
82struct FiberWorkerPool;
83struct FiberWorkerPoolOptions;
84struct FiberWorkerPoolThreadEntry;
85struct FiberWorkerThread;
86
87#if SC_PLATFORM_WINDOWS
88static constexpr int FiberContextStorageSize = 2048;
89#elif SC_PLATFORM_ARM64
90static constexpr int FiberContextStorageSize = 224;
91#else
92static constexpr int FiberContextStorageSize = 128;
93#endif
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);
101
104struct SC_FIBERS_EXPORT FiberStackSize
105{
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;
110};
111
113{
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*);
119
120 using Object = FiberStackGrowthRuntimeInternal;
121};
122using FiberStackGrowthRuntimeOpaque = OpaqueObject<FiberStackGrowthRuntimeDefinition>;
123
125struct SC_FIBERS_EXPORT FiberStackGrowthRuntime
126{
129
131 FiberStackGrowthRuntime& operator=(const FiberStackGrowthRuntime&) = delete;
132
133 [[nodiscard]] Result create();
134 [[nodiscard]] Result close();
135
136 [[nodiscard]] static bool isSupported();
137 [[nodiscard]] bool isOpen() const;
138 [[nodiscard]] size_t registeredThreadCount() const;
139
140 private:
141 friend struct FiberStackGrowthThread;
142 friend struct FiberStackGrowthThreadInternal;
143
144 FiberStackGrowthRuntimeOpaque internal;
145};
146
148{
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*);
154
155 using Object = FiberStackGrowthThreadInternal;
156};
157using FiberStackGrowthThreadOpaque = OpaqueObject<FiberStackGrowthThreadDefinition>;
158
160struct SC_FIBERS_EXPORT FiberStackGrowthThread
161{
164
166 FiberStackGrowthThread& operator=(const FiberStackGrowthThread&) = delete;
167
169 [[nodiscard]] Result create(FiberStackGrowthRuntime& runtime, Span<char> signalStackStorage);
170 [[nodiscard]] Result close();
171
172 [[nodiscard]] bool isOpen() const;
173
174 private:
175 FiberStackGrowthThreadOpaque internal;
176};
177
179struct SC_FIBERS_EXPORT FiberStack
180{
181 explicit FiberStack(Span<char> memory);
182
184 static FiberStack runtimeOwned(size_t sizeInBytes);
185 [[nodiscard]] bool isRuntimeOwned() const;
186
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();
194 [[nodiscard]] size_t highWaterUsedBytes() const;
195 [[nodiscard]] size_t highWaterUnusedBytes() const;
196
197 private:
198 friend struct FiberScheduler;
199 friend struct FiberVirtualStack;
200
201 FiberStack(Span<char> memory, void* owner);
202
203 Span<char> stackMemory;
204 void* stackOwner = nullptr;
205
206 size_t runtimeStackSize = 0;
207 bool runtimeOwnedStack = false;
208};
209
211{
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*);
217
218 using Object = FiberVirtualStackInternal;
219};
220using FiberVirtualStackOpaque = OpaqueObject<FiberVirtualStackDefinition>;
221
223struct SC_FIBERS_EXPORT FiberVirtualStackOptions
224{
225 size_t usableSizeInBytes = FiberStackSize::SixtyFourKiB;
226 bool guardPage = true;
227};
228
230{
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*);
236
237 using Object = FiberStackClassInternal;
238};
239using FiberStackClassOpaque = OpaqueObject<FiberStackClassDefinition>;
240
241enum class FiberStackCommitMode : uint8_t
242{
243 Full,
244 Incremental,
245};
246
247struct SC_FIBERS_EXPORT FiberStackClassOptions
248{
249 size_t stackSizeInBytes = FiberStackSize::SixtyFourKiB;
250 size_t maxStacks = 0;
251 bool guardPage = true;
252
253 FiberStackCommitMode commitMode = FiberStackCommitMode::Full;
254 size_t initialCommitSizeInBytes = 0;
256 size_t growthCommitSizeInBytes = 0;
257};
258
259struct SC_FIBERS_EXPORT FiberStackClassDiagnostics
260{
261 size_t capacity = 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;
272
273 FiberStackCommitMode commitMode = FiberStackCommitMode::Full;
274};
275
277struct SC_FIBERS_EXPORT FiberStackClass
278{
281
282 FiberStackClass(const FiberStackClass&) = delete;
283 FiberStackClass& operator=(const FiberStackClass&) = delete;
285 FiberStackClass& operator=(FiberStackClass&&) = delete;
286
287 [[nodiscard]] Result reserve(const FiberStackClassOptions& options);
288 [[nodiscard]] Result acquire(FiberStack& outStack);
289 [[nodiscard]] Result release(FiberStack& stack);
290 [[nodiscard]] Result waitForAvailableSlot(FiberScheduler& scheduler);
291 void release();
292 void fillHighWaterMarks();
293 void diagnostics(FiberStackClassDiagnostics& outDiagnostics) const;
294
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;
299
300 private:
301 friend struct FiberTaskPool;
302 friend struct FiberScheduler;
303
304 FiberStackClassOpaque internal;
305};
306
307enum class FiberAllocatorMode : uint8_t
308{
309 None,
310 Fixed,
311 Virtual,
312 Malloc,
313 Polymorphic,
314};
315
317{
318 size_t numAllocations = 0;
319 size_t numReleases = 0;
320
321 size_t requestedBytesAllocated = 0;
322 size_t requestedBytesReleased = 0;
323
324 size_t bytesInUse = 0;
325 size_t peakBytesInUse = 0;
326
327 size_t numAllocationFailures = 0;
328 size_t lastFailedAllocationSize = 0;
329 size_t largestFailedAllocationSize = 0;
330};
331
333{
334 size_t reserveBytes = 0;
335 size_t initialCommitBytes = 0;
336};
337
339{
340 virtual void* allocateImpl(const void* owner, size_t numBytes, size_t alignment) = 0;
341 virtual void releaseImpl(void* memory) = 0;
342 virtual ~FiberAllocatorInterface() {}
343};
344
346struct SC_FIBERS_EXPORT FiberAllocator
347{
348 FiberAllocator() = default;
349 FiberAllocator(const FiberAllocator&) = delete;
350 FiberAllocator& operator=(const FiberAllocator&) = delete;
351 FiberAllocator(FiberAllocator&&) = delete;
352 FiberAllocator& operator=(FiberAllocator&&) = delete;
354
355 [[nodiscard]] Result createFixed(Span<char> storage);
356 [[nodiscard]] Result createVirtual(FiberAllocatorVirtualOptions options);
357 [[nodiscard]] Result createMalloc();
358 [[nodiscard]] Result createPolymorphic(FiberAllocatorInterface& customAllocatorInterface);
359 [[nodiscard]] Result validateClose() const;
360 [[nodiscard]] Result close();
361
362 [[nodiscard]] void* allocate(const void* owner, size_t numBytes, size_t alignment);
363 void release(void* memory);
364 static void releaseFromAnyAllocator(void* memory);
365
366 [[nodiscard]] FiberAllocatorMode mode() const;
367 [[nodiscard]] FiberAllocatorStatistics statistics() const;
368 [[nodiscard]] bool isOpen() const;
369
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;
376
377 private:
378 struct BlockHeader;
379
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);
386 void resetState();
387
388 FiberAllocatorMode currentMode = FiberAllocatorMode::None;
389 FiberAllocatorStatistics currentStatistics;
390 Span<char> fixedStorage;
391 BlockHeader* firstBlock = nullptr;
392 FiberAllocatorInterface* allocatorInterface = nullptr;
393
394 void* virtualMemory = nullptr;
395 size_t virtualReservedBytes = 0;
396 size_t virtualCommittedBytes = 0;
397};
398
400struct SC_FIBERS_EXPORT FiberVirtualStack
401{
404
405 FiberVirtualStack(const FiberVirtualStack&) = delete;
406 FiberVirtualStack& operator=(const FiberVirtualStack&) = delete;
408 FiberVirtualStack& operator=(FiberVirtualStack&&) = delete;
409
410 Result reserve(const FiberVirtualStackOptions& options);
411 void release();
412
413 [[nodiscard]] FiberStack stack() const;
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;
419
420 private:
421 FiberVirtualStackOpaque internal;
422};
423
425enum class FiberTaskStatus
426{
427 Invalid,
428 Ready,
429 Running,
430 Waiting,
431 Completing,
432 Completed
433};
434
435enum class FiberTaskSuspendAction
436{
437 None,
438 Ready,
439 CounterWait
440};
441
442struct FiberCancellationToken;
443
445struct SC_FIBERS_EXPORT FiberWorker
446{
447 FiberWorker();
448 ~FiberWorker();
449
450 FiberWorker(const FiberWorker&) = delete;
451 FiberWorker& operator=(const FiberWorker&) = delete;
452
453 [[nodiscard]] bool isActive() const;
454 [[nodiscard]] FiberScheduler* scheduler();
455 [[nodiscard]] const FiberScheduler* scheduler() const;
456 [[nodiscard]] FiberTask* runningTask();
457 [[nodiscard]] const FiberTask* runningTask() const;
458
459 private:
460 friend struct FiberWorkerPool;
461 friend struct FiberScheduler;
462
463 Result begin(FiberScheduler& fiberScheduler);
464 void end();
465
466 FiberScheduler* workerScheduler = nullptr;
467 FiberScheduler* localQueueScheduler = nullptr;
468 FiberTask* workerTask = nullptr;
469 FiberTask* localReadyHead = nullptr;
470 FiberTask* localReadyTail = nullptr;
471 FiberTask* activeHead = nullptr;
472 FiberTask** localDeque = nullptr;
473 FiberAllocator* localDequeAllocator = nullptr;
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;
501
502 AlignedStorage<FiberContextStorageSize, FiberContextStorageAlignment> rootContextStorage;
503
504 [[nodiscard]] FiberContext& rootContext();
505};
506
507#if SC_PLATFORM_WINDOWS
508static constexpr int FiberWorkerThreadStorageSize = sizeof(void*);
509#else
510static constexpr int FiberWorkerThreadStorageSize = sizeof(void*) * 2;
511#endif
512static constexpr int FiberWorkerThreadStorageAlignment = alignof(void*);
513
515struct SC_FIBERS_EXPORT FiberWorkerThread
516{
519
520 FiberWorkerThread(const FiberWorkerThread&) = delete;
521 FiberWorkerThread& operator=(const FiberWorkerThread&) = delete;
522
523 [[nodiscard]] bool wasStarted() const;
524 [[nodiscard]] Result result() const;
525
526 private:
527 friend struct FiberWorkerPool;
528 friend struct FiberWorkerPoolThreadEntry;
529
530 AlignedStorage<FiberWorkerThreadStorageSize, FiberWorkerThreadStorageAlignment> threadStorage;
531
532 FiberWorkerPool* pool = nullptr;
533 size_t workerIndex = 0;
534 uint64_t affinityMask = 0;
535 uint8_t priority = 0;
536 Result threadResult = Result(true);
537 bool started = false;
538
539 FiberStackGrowthRuntime* stackGrowthRuntime = nullptr;
540 FiberStackGrowthThread stackGrowthThread;
541 Span<char> stackGrowthSignalStackStorage;
542
543 Result startThread();
544 Result joinThread();
545 Result runThreadEntry();
546 Result applyThreadPolicy();
547};
548
549enum class FiberWorkerThreadPriority : uint8_t
550{
551 Default,
552 Low,
553 Normal,
554 High,
555};
556
557struct SC_FIBERS_EXPORT FiberWorkerPoolOptions
558{
559 FiberAllocator* dequeAllocator = nullptr;
560 size_t dequeCapacityPerWorker = 0;
561 FiberAllocator* injectionAllocator = nullptr;
562 size_t injectionCapacity = 0;
563 size_t idleSpinAttempts = 32;
564 Span<const uint64_t> affinityMasks;
565 FiberWorkerThreadPriority threadPriority = FiberWorkerThreadPriority::Default;
567 FiberStackGrowthRuntime* stackGrowthRuntime = nullptr;
570};
571
572struct SC_FIBERS_EXPORT FiberWorkerDiagnostics
573{
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;
593};
594
595struct SC_FIBERS_EXPORT FiberWorkerPoolWakeDiagnostics
596{
598 size_t wakeNotifications = 0;
600 size_t wakeSignals = 0;
601};
602
603struct SC_FIBERS_EXPORT FiberSchedulerDiagnostics
604{
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;
618
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;
628};
629
630enum class FiberTraceEventType : uint8_t
631{
632 TaskStarted,
633 TaskYielded,
634 TaskWaiting,
635 TaskCompleted,
636};
637
638struct SC_FIBERS_EXPORT FiberTraceEvent
639{
640 FiberTraceEventType type = FiberTraceEventType::TaskStarted;
641 FiberScheduler* scheduler = nullptr;
642 FiberWorker* worker = nullptr;
643 FiberTask* task = nullptr;
644 size_t value = 0;
645};
646
647struct SC_FIBERS_EXPORT FiberTraceHooks
648{
649 using Callback = void (*)(void* userData, const FiberTraceEvent& event);
650
651 Callback callback = nullptr;
652 void* userData = nullptr;
653};
654
656struct SC_FIBERS_EXPORT FiberWorkerPool
657{
660
661 FiberWorkerPool(const FiberWorkerPool&) = delete;
662 FiberWorkerPool& operator=(const FiberWorkerPool&) = delete;
663
664 Result start(FiberScheduler& scheduler, Span<FiberWorker> workerStorage, Span<FiberWorkerThread> threadStorage);
665 Result start(FiberScheduler& scheduler, Span<FiberWorker> workerStorage, Span<FiberWorkerThread> threadStorage,
666 const FiberWorkerPoolOptions& options);
667 Result requestStop();
668 Result join();
669 Result shutdown();
670
671 [[nodiscard]] bool isRunning() const;
672 [[nodiscard]] size_t workerCount() const;
674 [[nodiscard]] size_t parkedWorkerCount() const;
677
679 {
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;
684
685 static constexpr size_t Alignment = alignof(void*);
686
687 using Object = FiberWorkerPoolWakeEvent;
688 };
689
690 using WakeEventOpaque = OpaqueObject<WakeEventDefinition>;
691
692 private:
693 friend struct FiberScheduler;
694 friend struct FiberWorkerThread;
695
696 FiberScheduler* poolScheduler = nullptr;
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;
705
706 void wakeOneWorker();
707 void wakeAllWorkers();
708 void resetWakeDiagnostics();
709 [[nodiscard]] bool waitForWork(uint32_t observedGeneration);
710 [[nodiscard]] uint32_t wakeGeneration() const;
711
712 Result workerMain(size_t workerIndex);
713};
714
716struct SC_FIBERS_EXPORT FiberCancellationTokenSource
717{
719
722
723 void requestCancel();
724 void reset();
725 Result check() const;
726
727 [[nodiscard]] bool isCancellationRequested() const;
728 [[nodiscard]] FiberCancellationToken token() const;
729
730 private:
731 friend struct FiberCancellationToken;
732 friend struct FiberJobScheduler;
733 friend struct FiberScheduler;
734
735 mutable volatile int32_t requested = 0;
736};
737
739struct SC_FIBERS_EXPORT FiberCancellationToken
740{
742
743 Result check() const;
744
745 [[nodiscard]] bool isValid() const;
746 [[nodiscard]] bool isCancellationRequested() const;
747
748 private:
749 friend struct FiberCancellationTokenSource;
750 friend struct FiberJobScheduler;
751 friend struct FiberScheduler;
752
753 explicit FiberCancellationToken(const FiberCancellationTokenSource& tokenSource);
754
755 const FiberCancellationTokenSource* source = nullptr;
756};
757
759enum class FiberJobStatus
760{
761 Invalid,
762 Ready,
763 Running,
764 Completed
765};
766
768struct SC_FIBERS_EXPORT FiberJobContext
769{
770 [[nodiscard]] FiberJobScheduler& scheduler() const;
771 [[nodiscard]] FiberJob& job() const;
772 [[nodiscard]] bool isCancellationRequested() const;
773 Result checkCancellation() const;
774
775 private:
776 friend struct FiberJobScheduler;
777
779
780 FiberJobScheduler* jobScheduler = nullptr;
781 FiberJob* currentJob = nullptr;
782};
783
785struct SC_FIBERS_EXPORT FiberJob
786{
787 using Procedure = Function<Result(FiberJobContext&)>;
788
789 FiberJob();
790 ~FiberJob();
791
792 FiberJob(const FiberJob&) = delete;
793 FiberJob& operator=(const FiberJob&) = delete;
794 FiberJob(FiberJob&&) = delete;
795 FiberJob& operator=(FiberJob&&) = delete;
796
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;
802
803 private:
804 friend struct FiberJobContext;
805 friend struct FiberJobGroup;
806 friend struct FiberJobPool;
807 friend struct FiberJobScheduler;
808
809 Procedure procedure;
810 FiberJobScheduler* ownerScheduler = nullptr;
811 FiberJobPool* ownerPool = nullptr;
812 FiberJob* nextAvailable = nullptr;
813 FiberJobGroup* originGroup = nullptr;
814 FiberJob* nextGroup = nullptr;
815 FiberCancellationToken cancellationToken;
816 FiberJobWorker* accountingWorker = nullptr;
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;
822};
823
824struct SC_FIBERS_EXPORT FiberJobWorkerDiagnostics
825{
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;
836};
837
838#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
839#pragma warning(push)
840#pragma warning(disable : 4324)
841#endif
843struct SC_FIBERS_EXPORT FiberJobWorker
844{
847
848 FiberJobWorker(const FiberJobWorker&) = delete;
849 FiberJobWorker& operator=(const FiberJobWorker&) = delete;
850
851 [[nodiscard]] bool isActive() const;
852 [[nodiscard]] FiberJobScheduler* scheduler();
853 [[nodiscard]] const FiberJobScheduler* scheduler() const;
854 [[nodiscard]] FiberJob* runningJob();
855 [[nodiscard]] const FiberJob* runningJob() const;
856
857 private:
858 friend struct FiberJobScheduler;
859 friend struct FiberJobWorkerPool;
860
861 Result begin(FiberJobScheduler& scheduler);
862 void end();
863
864 FiberJobScheduler* workerScheduler = nullptr;
865 FiberJobScheduler* localQueueScheduler = nullptr;
866 FiberJob* workerJob = nullptr;
867 FiberJob** localDeque = nullptr;
868 FiberAllocator* localDequeAllocator = nullptr;
869 size_t localDequeCapacity = 0;
870 size_t lastDequeCapacity = 0;
871 volatile size_t localDequeTop = 0;
872 volatile size_t localDequeBottom = 0;
873
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;
885
886 alignas(128) volatile size_t ownedReadyJobs = 0;
887 alignas(128) volatile size_t ownedActiveJobs = 0;
888
889 mutable volatile int32_t countActivationLock = 0;
890};
891#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
892#pragma warning(pop)
893#endif
894
899#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
900#pragma warning(push)
901#pragma warning(disable : 4324)
902#endif
903struct SC_FIBERS_EXPORT FiberJobScheduler
904{
907
908 FiberJobScheduler(const FiberJobScheduler&) = delete;
909 FiberJobScheduler& operator=(const FiberJobScheduler&) = delete;
910
911 Result create(Span<FiberJob*> readyStorage);
912 Result close();
913
914 Result createWorkerDeques(FiberAllocator& allocator, Span<FiberJobWorker> workers, size_t capacityPerWorker);
915 void releaseWorkerDeques(Span<FiberJobWorker> workers);
916
917 Result spawn(FiberJob& job, FiberJob::Procedure procedure);
918 Result spawn(FiberJob& job, FiberJob::Procedure procedure, FiberCancellationToken token);
920 Result spawn(Span<FiberJob> jobs, FiberJob::Procedure procedure);
921 Result spawn(Span<FiberJob> jobs, FiberJob::Procedure procedure, FiberCancellationToken token);
922 Result runOne(bool& outRanJob);
923 Result runOne(FiberJobWorker& worker, Span<FiberJobWorker> workerGroup, bool& outRanJob);
924 Result run();
925 Result run(FiberJobWorker& worker, Span<FiberJobWorker> workerGroup);
926 Result shutdown();
927
928 Result requestCancel(FiberJob& job);
929 Result requestCancel(FiberCancellationTokenSource& tokenSource);
930 Result requestCancelAll();
931
932 [[nodiscard]] bool isOpen() const;
934 [[nodiscard]] bool hasReadyJobs() const;
936 [[nodiscard]] bool hasActiveJobs() const;
937 [[nodiscard]] size_t capacity() const;
939 [[nodiscard]] size_t readyJobCount() const;
941 [[nodiscard]] size_t activeJobCount() const;
942 [[nodiscard]] FiberJob* currentJob();
943
946 void workerDiagnostics(const FiberJobWorker& worker, FiberJobWorkerDiagnostics& outDiagnostics) const;
947
948 private:
949 friend struct FiberJobContext;
950 friend struct FiberJob;
951 friend struct FiberJobWorkerPool;
952
953 Span<FiberJob*> queueStorage;
954 FiberJob* runningJob = nullptr;
955 size_t queueHead = 0;
956 size_t queueTail = 0;
957 size_t queueCount = 0;
958
959 alignas(128) volatile size_t readyJobs = 0;
960 alignas(128) volatile size_t activeJobs = 0;
961
962 mutable volatile int32_t countActivationLock = 0;
963
964 alignas(128) mutable volatile int32_t queueLock = 0;
965 volatile uint32_t cancelGeneration = 0;
966
967 FiberJobWorkerPool* workerPool = nullptr;
968
969 struct QueueLockGuard;
970 struct CountActivationLockGuard;
971
972 void initializeJobForSpawn(FiberJob& job, FiberJob::Procedure procedure, FiberCancellationToken token);
973 Result complete(FiberJob& job, Result result);
974 size_t confirmedJobCount(bool ready) const;
975 bool tryPushWorkerDeque(FiberJobWorker& worker, FiberJob& job);
976 FiberJob* popWorkerReady(FiberJobWorker& worker);
977 FiberJob* stealWorkerReady(FiberJobWorker& worker);
978 FiberJob* stealReady(FiberJobWorker& worker, Span<FiberJobWorker> workerGroup);
979 bool usesDistributedAccounting(const FiberJobWorker& worker) const;
980 bool isJobCancellationRequested(const FiberJob& job) const;
981 bool isWorkerStopRequested() const;
982};
983#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
984#pragma warning(pop)
985#endif
986
988struct SC_FIBERS_EXPORT FiberJobWorkerThread
989{
992
994 FiberJobWorkerThread& operator=(const FiberJobWorkerThread&) = delete;
995
996 [[nodiscard]] bool wasStarted() const;
997 [[nodiscard]] Result result() const;
998
999 private:
1000 friend struct FiberJobWorkerPool;
1001 friend struct FiberJobWorkerPoolThreadEntry;
1002
1003 AlignedStorage<FiberWorkerThreadStorageSize, FiberWorkerThreadStorageAlignment> threadStorage;
1004
1005 FiberJobWorkerPool* pool = nullptr;
1006 size_t workerIndex = 0;
1007 uint64_t affinityMask = 0;
1008 uint8_t priority = 0;
1009 Result threadResult = Result(true);
1010 bool started = false;
1011
1012 Result startThread();
1013 Result joinThread();
1014 Result runThreadEntry();
1015 Result applyThreadPolicy();
1016};
1017
1018struct SC_FIBERS_EXPORT FiberJobWorkerPoolOptions
1019{
1020 FiberAllocator* dequeAllocator = nullptr;
1021 size_t dequeCapacityPerWorker = 0;
1022 size_t idleSpinAttempts = 32;
1023
1025 bool keepAliveWhenIdle = false;
1026
1027 Span<const uint64_t> affinityMasks;
1028 FiberWorkerThreadPriority threadPriority = FiberWorkerThreadPriority::Default;
1029};
1030
1032struct SC_FIBERS_EXPORT FiberJobWorkerPool
1033{
1036
1037 FiberJobWorkerPool(const FiberJobWorkerPool&) = delete;
1038 FiberJobWorkerPool& operator=(const FiberJobWorkerPool&) = delete;
1039
1040 Result start(FiberJobScheduler& scheduler, Span<FiberJobWorker> workerStorage,
1041 Span<FiberJobWorkerThread> threadStorage, const FiberJobWorkerPoolOptions& options);
1043 Result waitIdle();
1045 Result requestStop();
1047 Result join();
1048 Result shutdown();
1049
1050 [[nodiscard]] bool isRunning() const;
1051 [[nodiscard]] size_t workerCount() const;
1052 [[nodiscard]] size_t parkedWorkerCount() const;
1053
1055 {
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;
1060
1061 static constexpr size_t Alignment = alignof(void*);
1062
1063 using Object = FiberWorkerPoolWakeEvent;
1064 };
1065
1066 using WakeEventOpaque = OpaqueObject<WakeEventDefinition>;
1067
1068 private:
1069 friend struct FiberJobScheduler;
1070 friend struct FiberJobWorkerThread;
1071
1072 FiberJobScheduler* poolScheduler = nullptr;
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;
1081
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;
1091
1092 Result workerMain(size_t workerIndex);
1093};
1094
1095struct SC_FIBERS_EXPORT FiberJobPoolDiagnostics
1096{
1097 size_t capacity = 0;
1098 size_t retainedJobs = 0;
1099 size_t availableJobs = 0;
1101 size_t peakRetainedJobs = 0;
1102};
1103
1105{
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*);
1111
1112 using Object = FiberJobClassInternal;
1113};
1114using FiberJobClassOpaque = OpaqueObject<FiberJobClassDefinition>;
1115
1116struct SC_FIBERS_EXPORT FiberJobClassOptions
1117{
1118 size_t maxJobs = 0;
1119};
1120
1121struct SC_FIBERS_EXPORT FiberJobClassDiagnostics
1122{
1123 size_t capacity = 0;
1124 bool bound = false;
1125};
1126
1128struct SC_FIBERS_EXPORT FiberJobClass
1129{
1130 FiberJobClass();
1132
1133 FiberJobClass(const FiberJobClass&) = delete;
1134 FiberJobClass& operator=(const FiberJobClass&) = delete;
1135 FiberJobClass(FiberJobClass&&) = delete;
1136 FiberJobClass& operator=(FiberJobClass&&) = delete;
1137
1138 [[nodiscard]] Result create(FiberAllocator& allocator, const FiberJobClassOptions& options);
1139 [[nodiscard]] Result validateClose() const;
1140 [[nodiscard]] Result close();
1141 void diagnostics(FiberJobClassDiagnostics& outDiagnostics) const;
1142
1143 [[nodiscard]] bool isOpen() const;
1144 [[nodiscard]] bool owns(const FiberJob& job) const;
1145 [[nodiscard]] size_t capacity() const;
1146
1147 private:
1148 friend struct FiberJobPool;
1149
1150 FiberJobClassOpaque internal;
1151};
1152
1154struct SC_FIBERS_EXPORT FiberJobPool
1155{
1156 FiberJobPool();
1157 ~FiberJobPool();
1158
1159 FiberJobPool(const FiberJobPool&) = delete;
1160 FiberJobPool& operator=(const FiberJobPool&) = delete;
1161
1162 Result create(Span<FiberJob> jobStorage);
1163 Result create(FiberJobClass& jobClass);
1164 Result close();
1165 Result spawn(FiberJobScheduler& scheduler, FiberJob::Procedure procedure, FiberJob*& outJob);
1166 Result spawn(FiberJobScheduler& scheduler, FiberJob::Procedure procedure, FiberCancellationToken token,
1167 FiberJob*& outJob);
1168 Result release(FiberJob& job);
1169
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;
1175 void diagnostics(FiberJobPoolDiagnostics& outDiagnostics) const;
1176
1177 private:
1178 friend struct FiberJobGroup;
1179
1180 Span<FiberJob> jobs;
1181 FiberJobClass* jobClass = nullptr;
1182 FiberJob* availableHead = nullptr;
1183 size_t retainedJobs = 0;
1184 size_t peakRetainedJobs = 0;
1185
1186 mutable volatile int32_t poolLock = 0;
1187
1188 Result acquire(FiberJob*& outJob);
1189 void releaseAcquired(FiberJob& job);
1190 void releaseAcquiredUnlocked(FiberJob& job);
1191 void recordPublished();
1192};
1193
1194struct SC_FIBERS_EXPORT FiberJobGroupError
1195{
1196 FiberJob* job = nullptr;
1197 Result result = Result(true);
1198};
1199
1201struct SC_FIBERS_EXPORT FiberJobGroup
1202{
1203 explicit FiberJobGroup(FiberJobScheduler& scheduler);
1205
1206 FiberJobGroup(const FiberJobGroup&) = delete;
1207 FiberJobGroup& operator=(const FiberJobGroup&) = delete;
1208
1209 Result spawn(FiberJobPool& pool, FiberJob::Procedure procedure, FiberJob** outJob = nullptr);
1210 Result spawn(FiberJobPool& pool, FiberJob::Procedure procedure, FiberCancellationToken token,
1211 FiberJob** outJob = nullptr);
1212 Result run();
1213 Result requestCancel();
1214 Result reset();
1215
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;
1220
1221 private:
1222 friend struct FiberJobScheduler;
1223
1224 FiberJobScheduler& jobScheduler;
1225 FiberJob* jobHead = nullptr;
1226 size_t pendingJobs = 0;
1227 size_t totalJobs = 0;
1228
1229 mutable volatile int32_t groupLock = 0;
1230
1231 Result prepareSpawn() const;
1232 void linkJob(FiberJob& job);
1233 void unlinkSpawnFailure(FiberJob& job);
1234 void complete(FiberJob& job);
1235};
1236
1238struct SC_FIBERS_EXPORT FiberTaskSpawnOptions
1239{
1240 FiberCancellationToken cancellationToken;
1241 FiberCounter* counter = nullptr;
1242 void* userData = nullptr;
1243 bool setUserData = false;
1244
1245 private:
1246 friend struct FiberTaskGroup;
1247 friend struct FiberScheduler;
1248 friend struct FiberTaskPool;
1249
1250 FiberTaskGroup* originGroup = nullptr;
1251 FiberTaskPool* originPool = nullptr;
1252 FiberTaskClass* originTaskClass = nullptr;
1253 FiberStackClass* originStackClass = nullptr;
1254};
1255
1256#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
1257#pragma warning(push)
1258#pragma warning(disable : 4324)
1259#endif
1260
1262struct SC_FIBERS_EXPORT FiberTask
1263{
1264 using Procedure = Function<Result(FiberScheduler&)>;
1265
1266 FiberTask();
1267 ~FiberTask();
1268
1269 FiberTask(const FiberTask&) = delete;
1270 FiberTask& operator=(const FiberTask&) = delete;
1271 FiberTask(FiberTask&&) = delete;
1272 FiberTask& operator=(FiberTask&&) = delete;
1273
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;
1283
1284 private:
1285 friend struct FiberTaskGroup;
1286 friend struct FiberTaskClassInternal;
1287 friend struct FiberTaskPool;
1288 friend struct FiberScheduler;
1289
1290 AlignedStorage<FiberContextStorageSize, FiberContextStorageAlignment> contextStorage;
1291
1292 Procedure procedure;
1293 FiberScheduler* scheduler = nullptr;
1294 FiberCounter* completionCounter = nullptr;
1295 FiberCancellationToken cancellationToken;
1296 FiberTask* nextReady = nullptr;
1297 FiberTask* previousReady = nullptr;
1298 FiberTask* nextWaiting = nullptr;
1299 FiberTask* nextActive = nullptr;
1300 FiberTask* previousActive = nullptr;
1301 FiberTask* nextGroup = nullptr;
1302 FiberTaskGroup* originGroup = nullptr;
1303 FiberCounter* waitingCounter = nullptr;
1304 FiberCounter* suspendCounter = nullptr;
1305 FiberTaskPool* originPool = nullptr;
1306 FiberTaskClass* originTaskClass = nullptr;
1307 FiberStackClass* originStackClass = nullptr;
1308 Span<char> originStackMemory;
1309 FiberWorker* preferredWorker = nullptr;
1310 FiberWorker* activeRegistryWorker = nullptr;
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;
1319
1320 [[nodiscard]] FiberContext& context();
1321 [[nodiscard]] const FiberContext& context() const;
1322};
1323
1325{
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*);
1331
1332 using Object = FiberTaskClassInternal;
1333};
1334using FiberTaskClassOpaque = OpaqueObject<FiberTaskClassDefinition>;
1335
1336struct SC_FIBERS_EXPORT FiberTaskClassOptions
1337{
1338 size_t maxTasks = 0;
1339};
1340
1341struct SC_FIBERS_EXPORT FiberTaskClassDiagnostics
1342{
1343 size_t capacity = 0;
1344 size_t activeTasks = 0;
1345 size_t availableTasks = 0;
1346 size_t peakActiveTasks = 0;
1347};
1348
1350struct SC_FIBERS_EXPORT FiberTaskClass
1351{
1354
1355 FiberTaskClass(const FiberTaskClass&) = delete;
1356 FiberTaskClass& operator=(const FiberTaskClass&) = delete;
1357 FiberTaskClass(FiberTaskClass&&) = delete;
1358 FiberTaskClass& operator=(FiberTaskClass&&) = delete;
1359
1360 [[nodiscard]] Result create(FiberAllocator& allocator, const FiberTaskClassOptions& options);
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();
1366 void diagnostics(FiberTaskClassDiagnostics& outDiagnostics) const;
1367
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;
1373
1374 private:
1375 friend struct FiberTaskPool;
1376
1377 FiberTaskClassOpaque internal;
1378};
1379
1381struct SC_FIBERS_EXPORT FiberCounter
1382{
1383 FiberCounter();
1384 ~FiberCounter();
1385
1386 FiberCounter(const FiberCounter&) = delete;
1387 FiberCounter& operator=(const FiberCounter&) = delete;
1388
1389 [[nodiscard]] size_t value() const;
1390
1391 private:
1392 friend struct FiberScheduler;
1393
1394 volatile size_t counterValue = 0;
1395
1396 FiberTask* waitingHead = nullptr;
1397 FiberTask* waitingTail = nullptr;
1398};
1399
1401struct SC_FIBERS_EXPORT FiberTaskGroupError
1402{
1403 FiberTask* task = nullptr;
1404 Result result = Result(true);
1405};
1406
1408struct SC_FIBERS_EXPORT FiberTaskGroup
1409{
1410 explicit FiberTaskGroup(FiberScheduler& scheduler);
1412
1413 FiberTaskGroup(const FiberTaskGroup&) = delete;
1414 FiberTaskGroup& operator=(const FiberTaskGroup&) = delete;
1415
1416 Result spawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure);
1417 Result spawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure, FiberCancellationToken token);
1418 Result spawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure,
1419 const FiberTaskSpawnOptions& options);
1420 Result spawn(FiberTaskPool& pool, FiberTask::Procedure procedure, FiberTask** outTask = nullptr);
1421 Result spawn(FiberTaskPool& pool, FiberTask::Procedure procedure, FiberCancellationToken token,
1422 FiberTask** outTask = nullptr);
1423 Result spawn(FiberTaskPool& pool, FiberTask::Procedure procedure, const FiberTaskSpawnOptions& options,
1424 FiberTask** outTask = nullptr);
1425 Result wait();
1426 Result waitAll(Result* outFirstError = nullptr);
1427 Result waitAllCancelOnParentCancel(Result* outFirstError = nullptr);
1428 Result waitCancelOnError(Result* outFirstError = nullptr);
1429 Result cancelAll();
1431 Result reset();
1432
1433 [[nodiscard]] size_t pending() const;
1434 [[nodiscard]] size_t countErrors() const;
1435 Result collectErrors(Span<FiberTaskGroupError> errors, size_t& outErrors) const;
1436
1437 private:
1438 friend struct FiberScheduler;
1439
1440 FiberScheduler& scheduler;
1441 FiberCounter counter;
1442 FiberTask* taskHead = nullptr;
1443
1444 Result prepareSpawn() const;
1445 void linkTask(FiberTask& task);
1446 Result findFirstError(Result* outFirstError) const;
1447};
1448
1450struct SC_FIBERS_EXPORT FiberTaskPoolDiagnostics
1451{
1452 size_t capacity = 0;
1453 size_t activeTasks = 0;
1454 size_t availableTasks = 0;
1455 bool classBacked = false;
1456
1457 FiberTaskClassDiagnostics taskClass;
1458 FiberStackClassDiagnostics stackClass;
1459};
1460
1461struct SC_FIBERS_EXPORT FiberTaskPool
1462{
1463 FiberTaskPool();
1464 FiberTaskPool(Span<FiberTask> taskStorage, Span<char> stackStorage, size_t stackSize);
1466
1467 FiberTaskPool(const FiberTaskPool&) = delete;
1468 FiberTaskPool& operator=(const FiberTaskPool&) = delete;
1469
1470 Result create(FiberTaskClass& taskClass, FiberStackClass& stackClass);
1471 Result close();
1472
1473 Result spawn(FiberScheduler& scheduler, FiberTask::Procedure procedure, FiberTask** outTask = nullptr,
1474 FiberCounter* counter = nullptr);
1475 Result spawn(FiberScheduler& scheduler, FiberTask::Procedure procedure, FiberCancellationToken token,
1476 FiberTask** outTask = nullptr, FiberCounter* counter = nullptr);
1477 Result spawn(FiberScheduler& scheduler, FiberTask::Procedure procedure, const FiberTaskSpawnOptions& options,
1478 FiberTask** outTask = nullptr);
1479
1480 [[nodiscard]] size_t capacity() const;
1481 [[nodiscard]] size_t activeCount() const;
1482 [[nodiscard]] size_t availableCount() const;
1483 [[nodiscard]] bool hasAvailableTask() const;
1484 void diagnostics(FiberTaskPoolDiagnostics& outDiagnostics) const;
1485 Result waitForSpawnCapacity(FiberScheduler& scheduler);
1486 Result waitForAvailableTask(FiberScheduler& scheduler);
1488 Result waitForAvailableTasks(FiberScheduler& scheduler, size_t minimumAvailable);
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;
1493
1494 private:
1495 friend struct FiberTaskGroup;
1496 friend struct FiberScheduler;
1497
1498 struct WaitNode
1499 {
1500 FiberCounter counter;
1501 WaitNode* next = nullptr;
1502
1503 size_t minimumAvailable = 1;
1504 bool notified = false;
1505 };
1506
1507 Span<FiberTask> tasks;
1508 Span<char> stacks;
1509 size_t stackSize = 0;
1510 size_t nextTask = 0;
1511
1512 FiberTaskClass* taskClass = nullptr;
1513 FiberStackClass* stackClass = nullptr;
1514
1515 WaitNode* availabilityWaitHead = nullptr;
1516 WaitNode* availabilityWaitTail = nullptr;
1517
1518 mutable volatile int32_t primitiveLock = 0;
1519
1520 Result stackAt(size_t stackIndex, FiberStack& outStack) const;
1521 void queueAvailabilityWaiter(WaitNode& node);
1522 FiberCounter* popAvailabilityWaiterForNotification();
1523 bool removeAvailabilityWaiter(WaitNode& node);
1524};
1525
1527struct SC_FIBERS_EXPORT FiberEvent
1528{
1529 explicit FiberEvent(bool signaled = false);
1530 ~FiberEvent();
1531
1532 FiberEvent(const FiberEvent&) = delete;
1533 FiberEvent& operator=(const FiberEvent&) = delete;
1534
1536 Result wait(FiberScheduler& scheduler);
1537 Result signal(FiberScheduler& scheduler);
1538 void reset();
1539
1540 [[nodiscard]] bool isSignaled() const;
1541
1542 private:
1543 struct WaitNode
1544 {
1545 FiberCounter counter;
1546 WaitNode* next = nullptr;
1547 bool notified = false;
1548 };
1549
1550 WaitNode* waitHead = nullptr;
1551 WaitNode* waitTail = nullptr;
1552 bool signaled = false;
1553 mutable volatile int32_t primitiveLock = 0;
1554
1555 void queueWaiter(WaitNode& node);
1556 bool removeWaiter(WaitNode& node);
1557};
1558
1560struct SC_FIBERS_EXPORT FiberAutoResetEvent
1561{
1562 explicit FiberAutoResetEvent(bool signaled = false);
1564
1566 FiberAutoResetEvent& operator=(const FiberAutoResetEvent&) = delete;
1567
1569 Result wait(FiberScheduler& scheduler);
1570 Result signal(FiberScheduler& scheduler);
1571 void reset();
1572
1573 [[nodiscard]] bool isSignaled() const;
1574
1575 private:
1576 struct WaitNode
1577 {
1578 FiberCounter counter;
1579 WaitNode* next = nullptr;
1580 bool notified = false;
1581 };
1582
1583 WaitNode* waitHead = nullptr;
1584 WaitNode* waitTail = nullptr;
1585 bool signaled = false;
1586 mutable volatile int32_t primitiveLock = 0;
1587
1588 void queueWaiter(WaitNode& node);
1589 bool popWaiter(WaitNode*& node);
1590 bool removeWaiter(WaitNode& node);
1591};
1592
1594struct SC_FIBERS_EXPORT FiberSemaphore
1595{
1596 explicit FiberSemaphore(size_t initialCount = 0);
1598
1599 FiberSemaphore(const FiberSemaphore&) = delete;
1600 FiberSemaphore& operator=(const FiberSemaphore&) = delete;
1601
1603 Result wait(FiberScheduler& scheduler);
1604 Result signal(FiberScheduler& scheduler, size_t count = 1);
1605
1606 [[nodiscard]] size_t available() const;
1607
1608 private:
1609 struct WaitNode
1610 {
1611 FiberCounter counter;
1612 WaitNode* next = nullptr;
1613 bool notified = false;
1614 };
1615
1616 WaitNode* waitHead = nullptr;
1617 WaitNode* waitTail = nullptr;
1618 size_t availableCount = 0;
1619 mutable volatile int32_t primitiveLock = 0;
1620
1621 void queueWaiter(WaitNode& node);
1622 WaitNode* popWaiter();
1623 bool removeWaiter(WaitNode& node);
1624};
1625
1627struct SC_FIBERS_EXPORT FiberMutex
1628{
1629 FiberMutex();
1630 ~FiberMutex();
1631
1632 FiberMutex(const FiberMutex&) = delete;
1633 FiberMutex& operator=(const FiberMutex&) = delete;
1634
1635 Result lock(FiberScheduler& scheduler);
1636 Result unlock(FiberScheduler& scheduler);
1637
1638 [[nodiscard]] bool isLocked() const;
1639 [[nodiscard]] bool isOwnedByCurrentTask(FiberScheduler& scheduler) const;
1640
1641 private:
1642 struct WaitNode
1643 {
1644 FiberCounter counter;
1645 WaitNode* next = nullptr;
1646 FiberTask* task = nullptr;
1647 bool notified = false;
1648 };
1649
1650 WaitNode* waitHead = nullptr;
1651 WaitNode* waitTail = nullptr;
1652 bool locked = false;
1653 FiberTask* owner = nullptr;
1654 mutable volatile int32_t primitiveLock = 0;
1655
1656 void queueWaiter(WaitNode& node);
1657 WaitNode* popWaiter();
1658 bool removeWaiter(WaitNode& node);
1659};
1660
1662struct SC_FIBERS_EXPORT FiberScheduler
1663{
1666
1667 FiberScheduler(const FiberScheduler&) = delete;
1668 FiberScheduler& operator=(const FiberScheduler&) = delete;
1669
1672 Result enableRuntimeOwnedStacks();
1673 [[nodiscard]] bool usesRuntimeOwnedStacks() const;
1674 [[nodiscard]] Result checkExecutionThread() const;
1675
1676 Result spawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure, FiberCounter* counter = nullptr);
1677 Result spawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure, FiberCancellationToken token,
1678 FiberCounter* counter = nullptr);
1679 Result spawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure,
1680 const FiberTaskSpawnOptions& options);
1681
1682 Result runOnce();
1683 Result runOnce(FiberWorker& worker);
1684 Result runOnce(FiberWorker& worker, Span<FiberWorker> workerGroup);
1685 Result runNoWait();
1686 Result runNoWait(FiberWorker& worker);
1687 Result runNoWait(FiberWorker& worker, Span<FiberWorker> workerGroup);
1688 Result runReadyFibers();
1689 Result runReadyFibers(FiberWorker& worker);
1690 Result runReadyFibers(FiberWorker& worker, Span<FiberWorker> workerGroup);
1691 Result run();
1692 Result run(FiberWorker& worker);
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);
1696 Result yield();
1697 Result shutdown();
1698 Result shutdown(FiberWorker& worker);
1699 Result shutdown(FiberWorker& worker, Span<FiberWorker> workerGroup);
1700
1701 Result requestCancel(FiberTask& task);
1702 Result requestCancel(FiberCancellationTokenSource& tokenSource);
1703 Result requestCancelAll();
1704
1705 void add(FiberCounter& counter);
1706 Result done(FiberCounter& counter);
1707 Result wait(FiberCounter& counter);
1708 Result waitUninterruptible(FiberCounter& counter);
1709
1710 void setTraceHooks(const FiberTraceHooks& hooks);
1711 void clearTraceHooks();
1712
1713 [[nodiscard]] FiberTask* currentTask();
1714 [[nodiscard]] const FiberTask* currentTask() const;
1715 [[nodiscard]] bool isCurrentTaskCancellationRequested() const;
1716
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;
1724 void schedulerDiagnostics(FiberSchedulerDiagnostics& diagnostics) const;
1725 void resetSchedulerDiagnostics();
1726 void workerDiagnostics(const FiberWorker& worker, FiberWorkerDiagnostics& diagnostics) const;
1727 void workerDiagnostics(Span<FiberWorker> workers, FiberWorkerDiagnostics& diagnostics) const;
1728
1729 void resetWorkerDiagnostics(FiberWorker& worker);
1730 void resetWorkerDiagnostics(Span<FiberWorker> workers);
1731
1732 private:
1733 friend struct FiberWorkerPool;
1734
1735 struct InjectionSlot;
1736
1737 FiberTask* readyHead = nullptr;
1738 FiberTask* readyTail = nullptr;
1739 FiberTask* activeHead = nullptr;
1740
1741 InjectionSlot* injectionQueue = nullptr;
1742 FiberAllocator* injectionAllocator = 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;
1751
1752 mutable volatile int32_t injectionLock = 0;
1753
1754 mutable size_t injectionLockAcquisitions = 0;
1755 mutable size_t injectionLockContentions = 0;
1756 mutable size_t injectionLockSpinRetries = 0;
1757 mutable size_t injectionLockPeakSpinRetries = 0;
1758
1759 FiberWorkerPool* workerPool = nullptr;
1760
1761 void* runtimeStackThread = nullptr;
1762
1763 volatile size_t readyFibers = 0;
1764 volatile size_t globalReadyFibers = 0;
1765 volatile size_t activeFibers = 0;
1766
1767 mutable volatile int32_t schedulerLock = 0;
1768
1769 mutable size_t schedulerLockAcquisitions = 0;
1770 mutable size_t schedulerLockContentions = 0;
1771 mutable size_t schedulerLockSpinRetries = 0;
1772 mutable size_t schedulerLockPeakSpinRetries = 0;
1773
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;
1779
1780 FiberTraceHooks traceHooks;
1781
1782 enum class LockCategory : uint8_t
1783 {
1784 Spawn,
1785 Ready,
1786 Synchronization,
1787 Completion,
1788 Control,
1789 };
1790
1791 struct LockGuard;
1792 struct InjectionLockGuard;
1793
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;
1799
1800 void addUnlocked(FiberCounter& counter);
1801 Result initializeTaskForSpawn(FiberTask& task, FiberStack& stack, FiberTask::Procedure procedure,
1802 const FiberTaskSpawnOptions& options);
1803 [[nodiscard]] bool canPublishOwnerSpawn(FiberWorker& worker, const FiberTaskSpawnOptions& options) const;
1804 [[nodiscard]] bool canPublishInjectionSpawn(const FiberTaskSpawnOptions& options) const;
1805 void linkWorkerActiveForSpawn(FiberTask& task, FiberWorker& worker);
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);
1816 void pushReadyUnlocked(FiberTask& task, FiberWorker* preferredWorker);
1817 [[nodiscard]] bool tryPushWorkerReadyDeque(FiberWorker& worker, FiberTask& task);
1818 void pushWorkerReadyUnlocked(FiberWorker& worker, FiberTask& task);
1819
1820 [[nodiscard]] FiberTask* popReadyUnlocked();
1821 [[nodiscard]] FiberTask* popReadyBatchUnlocked(FiberWorker& worker);
1822 [[nodiscard]] FiberTask* popInjectionBatch(FiberWorker& worker);
1823 [[nodiscard]] FiberTask* popReadyUnlocked(FiberWorker& worker, Span<FiberWorker> stealWorkers);
1824 [[nodiscard]] FiberTask* popWorkerReadyUnlocked(FiberWorker& worker);
1825 [[nodiscard]] FiberTask* stealWorkerReadyUnlocked(FiberWorker& worker);
1826 [[nodiscard]] FiberTask* stealReadyUnlocked(FiberWorker& worker, Span<FiberWorker> stealWorkers);
1827 Result runReadyTask(FiberTask& task);
1828 Result runReadyTask(FiberTask& task, FiberWorker& worker);
1829 [[nodiscard]] bool preparePreferredWorkerReadyPublish(FiberTask& task, FiberWorker& worker,
1830 FiberWorker*& outPreferredWorker);
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);
1836 void moveActiveToWorkerUnlocked(FiberTask& task, FiberWorker& worker);
1837 void adoptWorkerReadyUnlocked(FiberWorker& worker);
1838 void unlinkWorkerActive(FiberTask& task);
1839 void cancelWorkerActiveUnlocked(FiberWorker& worker, FiberCancellationTokenSource* tokenSource);
1840 bool removeCounterWaiterUnlocked(FiberCounter& counter, FiberTask& task);
1841 Result waitImpl(FiberCounter& counter, bool interruptible);
1842 Result doneUnlocked(FiberCounter& counter);
1843 void wakeCounterWaitersUnlocked(FiberCounter& counter);
1844
1845 static void taskEntry(void* userData);
1846};
1847
1848#if SC_PLATFORM_WINDOWS && (SC_COMPILER_MSVC || SC_COMPILER_CLANG_CL)
1849#pragma warning(pop)
1850#endif
1851} // namespace SC
Definition Fibers.h:339
Definition Fibers.h:317
Definition Fibers.h:333
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.
Definition Fibers.h:1105
Definition Fibers.h:1122
Definition Fibers.h:1117
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
Definition Fibers.h:1195
Retains one bounded wave of pooled FiberJob results for aggregate inspection.
Definition Fibers.h:1202
Definition Fibers.h:1096
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.
Definition Fibers.h:825
Definition Fibers.h:1019
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
Definition Fibers.h:604
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.
Definition Fibers.h:230
Definition Fibers.h:260
Definition Fibers.h:248
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.
Definition Fibers.h:1325
Definition Fibers.h:1342
Definition Fibers.h:1337
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
Definition Fibers.h:1462
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
Definition Fibers.h:639
Definition Fibers.h:648
Definition Fibers.h:211
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
Definition Fibers.h:573
Definition Fibers.h:558
Span< char > stackGrowthSignalStackStorage
POSIX requires at least workerCount * FiberStackGrowthSignalStackSize bytes; Windows ignores this spa...
Definition Fibers.h:569
Definition Fibers.h:596
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