Skip to content

docs(r23): Boost.Fiber — example 54 + chapter 54 (Compendium: C++ Concurrency) - #23

Merged
patterncatalyst merged 1 commit into
mainfrom
docs/r23-ch54-boost-fiber
Aug 20, 2026
Merged

patterncatalyst merged 1 commit into
mainfrom
docs/r23-ch54-boost-fiber

Conversation

@patterncatalyst

Copy link
Copy Markdown
Owner

Sixth chapter of Part 14, and the stackful counterpart to ch53.

ch53 measured a stackless coroutine frame at 32 bytes and noted in passing that co_await only works inside a coroutine body. ch54 is about what a real stack costs — and what that restriction is worth escaping.

The memory trilogy completes

Three instruments, three chapters, one ordering:

paused computation bytes instrument chapter
thread 8388608 pthread_getattr_np ch50
fiber 131072 stack_traits::default_size() ch54
coroutine frame 32 operator new in promise_type ch53

8 MiB → 128 KiB → 32 bytes. Both ratios (64 fibers per thread stack, 4096 frames per fiber stack) are computed in the program from those measured numbers rather than written into the prose. Nothing here is quoted.

The ordering falls out of one structural fact: a fiber costs more than a frame because it has a stack, and less than a thread because the kernel never sees it — no task_struct, no tid, nothing in /proc/<pid>/task/.

What the stack buys, demonstrated rather than described

deep: yielded_at_depth=6 resumed_at_depth=6 same=yes

A fiber suspends from inside an ordinary non-coroutine function six frames deep and resumes at the same depth. A stackless coroutine cannot express this at any price — co_await colours every frame in the suspend path, and the colour propagates through third-party functions you cannot edit.

128 KiB buys the right to suspend anywhere; 32 bytes restricts you to functions marked in advance.

The guard page, both directions

fixedsize_stack(64 KiB) returns exactly 65536. protected_fixedsize_stack(64 KiB) returns 69632 — exactly one page more, mapped PROT_NONE. The delta is gated against page_size() rather than a hardcoded 4096.

Recursing 60× past that stack: exit 139 (SIGSEGV) on the guard page, instead of corrupting the next mapping.

Two gate-design details worth flagging:

  • The gate asserts the exit signal only. What a process prints after running off its stack is undefined — ch49's rule about never gating on the output of UB.
  • It explicitly rejects exit 124. That is what timeout(1) returns when it kills something, and a hung run must not pass a test that means "faulted promptly".

The scheduler is a choice

Same 16 fibers, same work, one line apart:

roundrobin:  fibers=16 distinct_tids=1
sharedwork:  fibers=16 worker_threads=4 distinct_tids=4

That is ch49's grid selected by one use_scheduling_algorithm call — where ch44's Go runtime decides for you and mostly won't be argued with. Neither answer is right: round_robin means a fiber's data is only ever touched by one thread, which removes an entire category of synchronization. Sign gated (> 1, never == 4) with a bounded retry; measured 4 of 4 across five runs.

-O0, deliberately, and documented

At -O2 the recursion can become a loop and never touch the guard page — guard-overflow would exit 0 and quietly stop proving anything. That's ch49's optimizer lesson one layer down, and the reason is in CMakeLists.txt rather than left implicit.

Verification

Fedora 44, system Boost 1.90.0 — no Conan, no network — g++ 16.1.1, clang 22.1.8, local and unprivileged:

  • LSP_LANG=cpp lua verify.lua → PASS 32 / FAIL 0, with the migration, fault, and clang gates all running for real
  • python3 scripts/test-all-examples.py --only 54-boost-fiber → 1 passed
  • python3 scripts/validate.py → OK
  • Banned-words clean; 19/19 chapter code blocks verbatim; all 7 Chapter N cross-references resolve

One correction before shipping: fiber_specific_ptr is in <boost/fiber/fss.hpp>, not the path I first wrote. Verified by grep. All three named-but-unexercised APIs were confirmed present on this host, and the footer says they are named rather than gated.

Two diagrams (Fig 54.1 three ways to pause, Fig 54.2 the scheduler is a choice).

…currency)

Sixth chapter of Part 14, and the stackful counterpart to ch53.

ch53 measured a stackless coroutine frame at 32 bytes and noted in passing
that co_await only works inside a coroutine body. ch54 is about what a real
stack costs and what that restriction is worth escaping.

The memory trilogy, three instruments across three chapters:

  thread            8388608 B   pthread_getattr_np           (ch50)
  fiber              131072 B   stack_traits::default_size() (ch54)
  coroutine frame         32 B   operator new in promise     (ch53)

8 MiB -> 128 KiB -> 32 bytes. Both ratios (64, 4096) computed in the
program from those measured numbers, never quoted.

What the stack buys, demonstrated rather than described: a fiber suspends
from inside an ORDINARY non-coroutine function six frames deep and resumes
at the same depth. A stackless coroutine cannot express this at any price —
co_await colours every frame in the suspend path.

The guard page, both directions: protected_fixedsize_stack costs exactly one
page more than fixedsize_stack (delta gated against page_size(), not a
hardcoded 4096), and recursing 60x past a 64 KiB stack dies with exit 139
(SIGSEGV) rather than corrupting the next mapping. The gate asserts the exit
SIGNAL only — output after a stack overflow is undefined — and explicitly
rejects 124, since a hung run must not pass a test for faulting promptly.

The scheduler is a choice: the same 16 fibers report distinct_tids=1 under
the default round_robin and 4 under shared_work, one call to
use_scheduling_algorithm apart. That is ch49's grid selected by a line,
where ch44's Go runtime decides for you.

The TU is compiled -O0 deliberately and the reason is in CMakeLists.txt: at
-O2 the recursion can become a loop and never touch the guard page, which
would make guard-overflow exit 0 and quietly stop proving anything. ch49's
optimizer lesson, one layer down.

Two diagrams (Fig 54.1 three ways to pause, Fig 54.2 the scheduler is a
choice).

System Boost 1.90.0 — no Conan, no network. Verified on the Fedora 44 host:
verify.lua PASS 32 / FAIL 0 with the migration, fault, and clang gates all
running for real; runner 1 passed; validate.py OK.
@patterncatalyst
patterncatalyst merged commit 7f4ad53 into main Aug 20, 2026
8 checks passed
@patterncatalyst
patterncatalyst deleted the docs/r23-ch54-boost-fiber branch August 20, 2026 17:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant