ReleaseMicrosoftMicrosoftpublished Jun 6, 2026seen 4d

microsoft/bocpy v0.9.0

microsoft/bocpy

Open original ↗

Captured source

source ↗
published Jun 6, 2026seen 4dcaptured 10hhttp 200method plain

v0.9.0 - Main Pinned Cowns

Repository: microsoft/bocpy

Tag: v0.9.0

Published: 2026-06-06T11:21:36Z

Prerelease: no

Release notes: Main-pinned cowns — a new PinnedCown subclass holds its value as a plain PyObject * on the main interpreter, never round-tripped through XIData. Behaviors whose request set contains any pinned cown are routed by the scheduler to a single-consumer main-thread queue and drained by the new pump entry point (or implicitly by wait, which auto-pumps when pinned cowns exist). Designed for objects that cannot survive cross-interpreter shipping — pyglet shapes, Tk widgets, GPU contexts, open file handles, ctypes pointers. The companion examples/boids.py rewrite demonstrates the coarse-grained pinned-dispatch pattern: per-cell physics stays on workers, and one @when(PinnedCown) per frame batches the write-back into main-thread matrices. Also in this release: quiesce, a non-tearing-down checkpoint primitive.

New Features

  • quiesce(timeout=None, *, stats=False, noticeboard=False)** —

blocks until every in-flight behavior completes, without tearing down workers or the noticeboard thread. Implemented via a new terminator_seed_inc peer of terminator_seed_dec (Pyrona-style seed-up / seed-down pairing) so quiescence becomes a *checkpoint* rather than a shutdown. Useful for parallel-search patterns that need to inspect a best-so-far cown between rounds and for tests that must read a worker-produced send queue before its producer interpreter is destroyed. The stats and noticeboard flags mirror wait: returns None by default, a per-worker stats list[dict] when stats=True, a noticeboard dict[str, Any] when noticeboard=True, or a WaitResult when both are set. Raises TimeoutError if quiescence is not reached within timeout. Exported from bocpy.__all__.

  • `PinnedCown(Cown[T])` — a cown whose value lives

permanently on the main interpreter. Constructible only from the main interpreter (raises RuntimeError from workers); the value is never picklable, never reified twice, and never reconstructed in a worker. The capsule *handle* remains a first-class cross-interpreter shareable — workers may hold it, embed it in a regular Cown value graph, and place it in noticeboard entries, but only the main thread may acquire the value. See the new pinned_cowns page for the full contract and the coarse-grained-dispatch pattern.

  • `pump(deadline_ms=None, max_behaviors=None, raise_on_error=False)`

— drains the main-thread queue of behaviors whose request sets contain a PinnedCown. Call from your event loop's idle / on-tick hook (pyglet schedule_interval, Tk after, asyncio task, …); script-mode programs need not call it explicitly because wait pumps internally. Non-preemptive: deadline_ms gates *starting* the next behavior, not interrupting one already running. Body exceptions default to landing on the result cown's .exception; raise_on_error=True re-raises the first body exception after drain. Returns a new PumpResult NamedTuple (executed, deadline_reached, raised).

  • `set_pump_watchdog(warn_ms=1000, raise_ms=None, on_starve=None)`

— configure the pinned-queue starvation watchdog. Both thresholds gate on queue-non-empty time, not raw last-pump time, so programs running only unpinned work never trip them. Default is warn-only; users opt into fail-fast via an explicit raise_ms so interactive debugger sessions are not wedged by a breakpoint.

  • `set_wait_pump_poll(ms=50)` — set the poll cadence for

wait's auto-pump loop. Re-read every iteration so a concurrent call updates the active wait immediately.

  • `bocpy.PumpResult` — three-field NamedTuple returned by

pump. executed counts pinned behaviors whose lifecycle completed (including acquire-failure paths whose MCS chain still drained). deadline_reached is True only when the deadline_ms budget tripped before the queue drained. raised counts only body exceptions captured to a result cown (cleanup-path failures use PyErr_WriteUnraisable and do not count). Exported from bocpy.__all__.

  • Coarse-grained pinned-dispatch `examples/boids.py` — the

per-cell send("update") / main-thread receive("update") barrier is replaced by per-cell physics on workers plus one pinned @when per frame that captures every per-cell result cown together with the two main-thread PinnedCown matrices and performs the batched write-back. Same visual output, fully worker-parallel per-cell work, single main-thread touchpoint.

Public C ABI

  • `bocpy_main_interpid()` — new static inline helper in

returning PyInterpreterState_GetID( PyInterpreterState_Main()) pre-typed as int_least64_t to match bocpy_interpid for owner-field equality checks. Safe to call from a worker sub-interpreter for diagnostic / assert use. Additive — existing consumers recompile unchanged; BOCPY_ABI is unchanged at 1. The templates/c_abi_consumer bocpy~= pin moves to ~=0.9` to signal the new ABI surface it was authored against.

Improvements

  • `@when` loop-variable snapshot via default arg — the

transpiler now accepts def b(c, i=i) as an explicit loop-snapshot idiom in addition to the existing implicit form (just reference the loop variable in the body). Trailing positional parameters beyond the cown count are also auto-captured by name (def b(c, factor) captures factor).

  • `@when` alias decorators — the transpiler now recognises

from bocpy import when as boc_when and import bocpy [as alias] followed by @bocpy.when(...) or @alias.when(...), provided the aliasing import is at module level. Previously only the bare @when form was detected.

  • `Behaviors.start()` compiles the export module on main

the transpiler's rewritten module is now also instantiated as an in-memory types.ModuleType on the main thread (plus a linecache entry for traceback fidelity) so pump can resolve __behavior__N the same way workers do via their bootstrap.

  • Scheduler-owned behavior pre-headerbq_node and the

new pinned OR-fold byte moved out of the opaque BOCBehavior into a scheduler-owned boc_behavior_prehdr_t allocated immediately before each behavior (CPython _PyGC_Head style). boc_sched.c no longer needs any knowledge of BOCBehavior's internal layout; layout drift between the scheduler and its users is impossible by construction.

  • `terminator_wait_pumpable` — new entry in

boc_terminator.{c,h}

Excerpt shown — open the source for the full document.

Notability

notability 3.0/10

Routine library release by Microsoft.