Every public symbol exported by runloom, organised by module. This is a reference -- start with the guides if you're learning your way around.
The low-level scheduler API. Most user code calls runloom.fiber and
runloom.run; everything else is for advanced use.
Spawn a fiber running fn. Returns a G handle.
fn-- a zero-arg callable. Bind arguments withlambdaorfunctools.partial.stack_size-- optional per-call override (bytes). Bypasses the scheduler's calibrated default. See stack sizing.
Like go(fn) but with a contract: fn promises not to yield, sleep,
park, or do monkey-patched I/O. The scheduler skips per-g datastack
setup, saving 150–400 ns per spawn. Undefined behaviour if fn
yields. Use only for pure-compute callables.
Drive the scheduler until every fiber has finished. Returns the count of completed fibers.
Cooperatively yield. sched_yield is a vectorcall fastpath
singleton; sched_yield_classic is the equivalent PyCFunction (kept
for benchmarking, otherwise identical).
Park the current fiber until at least seconds have elapsed.
Other fibers run in the meantime.
Signal the scheduler to exit its drain loop at the next safe point.
Used internally by runloom.aio for early termination.
Drop everything queued in the scheduler (ready FIFO, sleep heap,
netpoll-parked). Returns (n_ready, n_sleep, n_parked). Used by
runloom.aio.run for cleanup between runs.
Park the current fiber until g.wake() is called on its handle.
Race-safe -- a wake that arrives before the park is consumed and the
park returns immediately. Use with current_g() to capture the
handle before parking.
Return a handle to the currently-running fiber, or None if
called from outside any fiber.
Current per-fiber default stack size, in bytes.
Override the default and freeze calibration. Clamped to
[16 KB, 8 MB]. Disables stack painting.
The currently-running fiber's stack high-water-mark in bytes
(page-granular, paint-free via mincore), or 0 outside a fiber or
where the backend has no introspectable stack (Windows Fibers). The read
half of the function-bound grow-down auto-sizer.
(On runloom, not runloom_c.) Toggle the function-bound stack grow-down
auto-sizer, which learns each runloom.fiber()-spawned function's real stack need
and reserves only that. On by default, active under M:N (run(n>1)) only;
single-thread run(1) keeps the fixed default. Also disabled by
RUNLOOM_GROW_DOWN=0 in the environment. A per-call runloom.fiber(fn, stack_size=N) pin always wins, and grow-down defers to the opt-in
enable_stack_autosize() when that is explicitly enabled. See
docs/stack-sizing.md.
Construct a channel of the given buffer capacity. Chan(0) is
unbuffered (rendezvous). See Channels.
Methods:
send(value)-- block until the value fits, then enqueue. RaisesValueErroron closed channel.recv() → (value, ok)-- block for a value. Returns(None, False)after the channel is closed and drained.try_send(value) → bool-- non-blocking send;Falseif the buffer is full.try_recv() → (value, ok) | None-- non-blocking;Noneif buffer empty.close()-- wake every parked sender (they raise) and receiver (they get(None, False)).__iter__()-- yields values until the channel closes.
Multi-way wait. Each case is ("recv", chan) or ("send", chan, value).
- Returns
(idx, payload)for a fired case wherepayloadis(value, ok)for recv orNonefor send. - Returns
-1(bare integer) ifdefault=Trueand no case is ready.
Park the current fiber until fd is ready. events is a
bitmask: 1 = read, 2 = write. Returns the ready bitmask.
timeout_ms=-1 for no timeout; 0 to poll without parking.
Cooperative read/write on an fd. Park on wait_fd when EAGAIN.
TCP-specific fastpaths. sock is a Python socket.socket (or its
fileno).
File I/O. On Linux 5.1+ with iouring_available(), dispatched
through io_uring. Elsewhere dispatched through a worker thread.
True if the kernel supports io_uring (Linux 5.1+).
See Parallelism.
mn_init(n=0)-- startnhub threads (defaults tocpu_count).mn_fiber(fn) → G-- spawn on a round-robin hub.mn_run() → int-- wait for all hubs to drain.mn_fini()-- tear down the pool.
See Preemption.
preempt_init(quantum_us=10000)-- start the per-thread quantum timer.preempt_fini()-- stop the timer.
Pre-allocate n fiber stacks so the first n spawns skip mmap.
Active context-switch backend: "fcontext-asm", "fibers", or
"ucontext".
Active netpoll: "epoll", "kqueue", "wsapoll", "iocp", or
"select".
Snapshot of scheduler counters. Keys: ready, sleeping,
netpoll_parked, completed, running, stack_size_default,
stack_hwm, stack_completed, stack_calibrated, stack_painting,
backend, netpoll. Cheap; safe to poll periodically.
A Go-style fiber dump -- which fibers exist, what each is blocked
on, and where in your code. See the Debugging guide for
the full picture (and the friendlier runloom.inspect wrappers).
One dict per live fiber: id, state (running / runnable /
io-wait / sleep / chan-wait / park / ...), blocked_on, fd +
events (when io-wait), wake_in (when sleep), age, refcount,
noyield, owner. Cheap; safe from a watchdog.
Number of live fibers.
One dict per M:N hub — the per-hub view: id, state (detached /
attached / suspended), running_g (goid being resumed, or None),
dwell_ms (how long that resume has run), pending, preempt_requested,
instrumented, and blocked_at (best-effort Python call site of a
DETACHED-wedged hub's blocking call). Lock-free atomic reads; [] when the M:N
scheduler isn't running. The friendly wrapper runloom.inspect.hubs() adds a
stack_cmd (py-spy dump --pid <PID>) per row, and runloom.inspect.print_hubs()
renders the table — see debugging.md.
Best-effort reconstructed Python stack of one fiber (deepest first).
Full stack under the single-thread scheduler (runloom.aio) and per-g-tstate
M:N; withheld under default M:N (no safe way to freeze a hub-resumable
fiber).
Write an async-signal-safe structural dump (state histogram + per-fiber
line, no Python objects) to fd. The SIGQUIT path -- usable from a signal
handler and when the interpreter is wedged.
Track each fiber's park time so fibers()/dumps report age. Off
by default (one clock read per park); also via RUNLOOM_INTROSPECT_TIME=1.
Install a raw-C signal handler that dumps all fibers to stderr -- Go's
GOTRACEBACK / kill -QUIT. Also via RUNLOOM_TRACEBACK=1. POSIX only.
Reset the runtime to a clean single-process state in a forked child
(abandons the dead hub/offload threads, re-inits inherited locks, gives the
child its own netpoll fd). Registered automatically as an
os.register_at_fork(after_in_child=...) handler; see the Debugging
guide.
Deadlock detection: when the single-thread scheduler quiesces with
fibers still blocked on channels/parks, mode 0=off, 1=warn (print the
dump, default), 2=raise RuntimeError. Also RUNLOOM_DEADLOCK=off|warn|raise.
count_deadlocked() is the current chan/park-blocked count.
Backpressure: cap the live-fiber count (0 = unlimited). Over the cap,
spawn raises RuntimeError. Also RUNLOOM_MAX_GOROUTINES. Zero hot-path cost
when unset.
Park-age tracking (enables the age field + runloom.inspect.leaked()).
Exposed as friendlier wrappers on runloom.inspect (also as raw runloom_c
functions). See the Debugging guide
and Stack sizing.
inspect.install_crash_handler(level=None, file=None) / uninstall_crash_handler() / crash_handler_installed() → bool
Install a fatal-signal handler (SIGSEGV/SIGBUS/...) that, on a crash, classifies
the fault against the per-fiber guard pages -- a fiber stack overflow is
named and distinguished from a wild pointer -- and dumps the live-fiber
registry, then chains to the default handler. level:
on/all/backtrace/pystack/wait/gdb/off (default from RUNLOOM_CRASH).
file also appends the report there. POSIX has the rich path; Windows uses a
Vectored Exception Handler.
Per-fiber-kind stack profiler. While on, each kind's real C-stack
high-water mark is measured; stack_advice() returns {kind, samples, max_hwm, reserved, suggested} per kind so you can right-size stack_size=. Advisory
only -- it never changes a stack size. Off by default (zero cost).
Adaptive auto-sizer: each fiber kind starts large and, once measured, its
later fibers start at the learned size ("start large, learn down").
In-memory only -- never persisted. prescan=True also runs the cold-start
optimizer (a deep-frame kind like Decimal starts big enough to survive its
first run). An explicit stack_size= always wins. Also RUNLOOM_STACK_AUTOSIZE=1.
Per-OS-thread setup/teardown. Called automatically; only invoke manually if you're embedding runloom in a non-main thread.
Goroutine handle. Attributes:
done--Trueonce the fiber has returned.result-- return value (orNoneuntil done).error-- exception object if the fiber raised, elseNone.wake()-- re-queue a parked fiber; race-safe withpark_self().stack(limit=None)-- return a list of(filename, lineno, name)frames for the fiber's current Python stack.
Lower-level coroutine handle. Most users won't construct these
directly; G wraps a Coro plus scheduler metadata.
Top-level package. Re-exports a Go-style API from runloom.runtime
(the original Python-only scheduler, kept for backward compatibility).
import runloom
runloom.fiber(fn) # spawn (uses the C scheduler under the hood)
runloom.yield_now() # cooperative yield (give other fibers a turn)
runloom.sleep(seconds) # cooperative sleep
runloom.run(n, main_fn=None) # THE entry point. run main_fn with n hubs:
# n=1 single-thread, n>1 M:N parallel across n
# cores (needs 3.13t + GIL off; n>1 under the GIL
# raises). main_fn optional -> drain-only.
# Collapses mn_init/mn_fiber/mn_run/mn_fini.
runloom.current() → Goroutine
runloom.backend() → strFor new code, prefer runloom_c (faster) or runloom.sync (richer API).
Runtime introspection -- the friendly wrappers over the fiber
registry. fibers(stacks=), count(), stack(id), format(stacks=)
(a human dump as a string), dump(file=, stacks=), enable_timestamps(),
install_dump_signal(), leaked(min_age, states) / watch_leaks(...)
(leak detection), set_deadlock_mode("off"/"warn"/"raise"),
set_max_fibers(n) / live_fibers() (backpressure). See the
Debugging guide.
import runloom
print(gi.format(stacks=True)) # which fibers, and where they're stuck
gi.install_dump_signal() # kill -QUIT <pid> -> dumpAsyncio bridge. See runloom.aio.
runloom.aio.run(coro) # equivalent of asyncio.run
runloom.aio.install() # set RunloomEventLoopPolicy globally
runloom.aio.open_connection(host, port) # async (reader, writer)
runloom.aio.start_server(cb, host, port) # async server with serve_forever()Classes:
RunloomEventLoop-- drop-inasyncio.AbstractEventLoopbacked by runloom's scheduler.RunloomEventLoopPolicy-- setsRunloomEventLoopas the default loop.RunloomFuture-- duck-typed Future with synchronous done-callback dispatch.RunloomTask--asyncio.Taskreplacement that drives the coroutine inside a fiber.StreamReader/StreamWriter-- asyncio-compatible stream interface, backed bywait_fd.DatagramTransport-- UDP transport forloop.create_datagram_endpoint.
No-async/await facade. See Sync API.
runloom.sync.fiber(fn, *args, **kwargs) # spawn with args
runloom.sync.run(main_fn=None) # drive scheduler
runloom.sync.sleep(seconds)
runloom.sync.yield_now()
runloom.sync.current() → G
runloom.sync.Chan # re-export of runloom.Chan
runloom.sync.select # re-export of runloom.select
runloom.sync.park / wake # park_self + wake helpers
runloom.sync.tcp_connect(host, port) → Socket
runloom.sync.tcp_listen(host, port, *, backlog=128) → Socket
runloom.sync.udp_endpoint(local_addr=None, remote_addr=None) → SocketSynchronisation primitives matching asyncio.*:
runloom.sync.Lock-- cooperative mutex.runloom.sync.Event-- set/clear/wait.runloom.sync.Condition-- waiter + notifier on a lock.runloom.sync.Semaphore-- bounded counting semaphore.
Wrapper around socket.socket whose blocking methods (connect,
accept, recv, send, sendall, recv_into, recvfrom, sendto)
park cooperatively on wait_fd. Standard socket.socket attributes
(setsockopt, fileno, getsockname, close, etc.) pass through.
Go-style timers and tickers.
Cooperative sleep. Alias for runloom.sched_sleep.
Returns a channel that will receive the current time after seconds.
Equivalent of Go's time.After.
import runloom
after = t.After(1.0)
# ... do work ...
after.recv() # blocks until the timer firesSingle-shot timer. Methods:
Timer.C-- channel that fires once.Timer.Stop()-- cancel; returnsTrueif cancelled before firing.Timer.Reset(seconds)-- rearm.
Recurring ticker. Methods:
Ticker.C-- channel that fires everyseconds.Ticker.Stop()-- stop emitting.
Shorthand for NewTicker(seconds).C when you don't need to stop it
(the ticker leaks -- only use for program-lifetime tickers).
Stdlib monkey-patching. See Monkey-patching.
Apply patches. Default: all categories enabled. Opt out:
runloom.monkey.patch(threading=False, dns=False)Categories: socket, time, os, select, stdio, ssl,
subprocess, threading, queue, dns.
Reverse patches. Without args, reverses everything applied.
Available even without patch():
CoLock,CoRLock-- cooperative mutexes.CoEvent-- set/wait.CoCondition--waitreleases the lock cooperatively.CoSemaphore,CoBoundedSemaphore-- counting semaphores.
These implement the threading.* interface but park fibers
instead of OS threads. Useful when you want sync primitives but
don't want to install the full monkey patch.