libdispatch now builds locally against the staged custom libthr and runs in
the bhyve guest through both a basic dispatch probe and a pressured dispatch
probe.
This is no longer just a source-level or link-level milestone. The guest now proves both real dispatch execution on top of the TWQ path and real pressure feedback affecting default worker concurrency.
The staged libthr surface was extended so libdispatch can enter its real
pthread workqueue path without dragging in unrelated Darwin subsystems.
Important additions:
/usr/src/include/pthread/qos.h/usr/src/include/pthread/qos_private.h/usr/src/include/pthread/workqueue_private.h/usr/src/lib/libthr/thread/thr_workq.c/usr/src/lib/libthr/pthread.map
What was added:
_pthread_qos_class_encode()_pthread_qos_class_decode()_pthread_qos_class_encode_workqueue()_pthread_set_properties_self()pthread_qos_max_parallelism()pthread_time_constraint_max_parallelism()qos_class_main()qos_class_self()pthread_set_qos_class_self_np()- direct override entry points used by dispatch, currently as controlled stubs
This keeps the userland contract dispatch expects while still avoiding Mach, launchd, workloops, or direct kevent workqueue delivery.
The local dispatch checkout under ../nx/swift-corelibs-libdispatch had two
build issues for this use case:
cmake/config.h.inemitted valuelessHAVE_*macros for:HAVE__PTHREAD_WORKQUEUE_INIT,HAVE_PTHREAD_WORKQUEUE_H,HAVE_PTHREAD_WORKQUEUE_PRIVATE_H, andHAVE_PTHREAD_QOS_Hsrc/voucher_internal.hlacked a no-voucher_voucher_release_no_dispose()stub in the disabled-mach-voucher path
Those were fixed locally so the dispatch tree can be rebuilt reproducibly against the staged custom pthread surface.
New script:
scripts/libdispatch/prepare-stage.sh
This script now:
- configures the local
swift-corelibs-libdispatchtree with external pthread workqueues enabled - points the build at the staged custom
libthr - uses the staged pthread private headers
- builds
libdispatch.so - stages
libdispatch.soandlibBlocksRuntime.sointo../artifacts/libdispatch-stage
New probe:
csrc/twq_dispatch_probe.c
What it does:
- exposes a
basicmode:- loads
dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0) - submits a burst of default-QoS async tasks
- waits with a timeout
- reports requested tasks, started tasks, completed tasks, unique worker
threads, peak concurrency, main-thread callback count, and
_pthread_workqueue_supported()feature bits
- loads
- exposes a
pressuremode:- starts a user-interactive worker that blocks long enough to overlap lower QoS work
- submits a matching default-QoS burst while that higher-priority worker is active
- reports default-task completion, high-priority-task completion, unique worker threads, and peak default concurrency under pressure
New harness pieces:
scripts/bhyve/stage-guest.shelixir/lib/twq_test/zig.exelixir/lib/twq_test/vm.exelixir/test/twq_test/vm_integration_test.exs
What changed:
- the host now stages
libdispatch.so,libBlocksRuntime.so, and the new dispatch probe into the guest - the guest runs the dispatch probe with:
LD_LIBRARY_PATH=/root/twq-dispatch:/root/twq-lib - the guest now captures separate TWQ snapshots around both:
- the basic dispatch workload
- the pressured dispatch workload
- ExUnit now asserts all of the following:
- successful basic dispatch execution
- successful pressured dispatch execution
- counter deltas proving the real TWQ path was exercised
- peak default concurrency is lower under pressure than in the basic case
- the default bucket requests more work than the kernel admits under the pressured workload
Passed:
scripts/libdispatch/prepare-stage.sh- manual build of
../artifacts/zig/prefix/bin/twq-dispatch-probe cd elixir && make test
Passed:
cd elixir && env PATH="/usr/local/lib/erlang28/bin:$PATH" TWQ_RUN_VM_INTEGRATION=1 mix test test/twq_test/vm_integration_test.exs
The guest serial log showed:
- basic dispatch probe output:
_pthread_workqueue_supported()reported19- requested
8tasks - started
8 - completed
8 - used
4unique worker threads - peak in-flight default concurrency was
4 - main-thread callbacks stayed at
0
- basic dispatch TWQ deltas:
kern.twq.init_count: 4 -> 5kern.twq.setup_dispatch_count: 4 -> 5kern.twq.reqthreads_count: 8 -> 23kern.twq.thread_enter_count: 3 -> 8
- pressured dispatch probe output:
- requested default work
8 - requested high-priority blockers
1 - completed default work
8 - completed high-priority blockers
1 - used
4unique worker threads - peak default concurrency dropped to
3 - main-thread callbacks stayed at
0
- requested default work
- pressured dispatch TWQ deltas:
kern.twq.init_count: 5 -> 6kern.twq.setup_dispatch_count: 5 -> 6kern.twq.reqthreads_count: 23 -> 38kern.twq.thread_enter_count: 8 -> 13kern.twq.switch_block_count: 12 -> 21kern.twq.switch_unblock_count: 12 -> 21- the default bucket in
bucket_req_totalgrew more than the default bucket inbucket_admit_total
Those deltas are the important proof:
- dispatch initialized the real workqueue path
- dispatch requested additional workers through TWQ
- worker threads actually entered the kernel-tracked path
- the pressured workload exercised real TWQ pressure accounting rather than a blind pthread-pool fallback
- this was not a silent fallback to the generic pthread pool
This milestone is now complete enough for its intended purpose.
What is now true:
libdispatchbuilds and runs in the guest against the staged customlibthr- the guest proves real TWQ activity under both basic and pressured dispatch workloads
- silent fallback is actively checked and ruled out for these workloads
- TWQ pressure now has visible behavioral effect on default dispatch concurrency in the guest
The next high-value step is M11: validate against the local Apple tree and use the macOS lane for canonical behavior comparison when needed.