mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 22:05:48 +08:00
src/fiber.c, not used yet: a fiber runs a function on a stack of its own, yielding back to the thread which resumed it, for a thread to serve many clients with code written as if each had a thread. The switch is our own on x86-64 (System V), aarch64, i386, arm (ARM or Thumb code, with or without a floating point unit) and mips o32 (with soft, 32 or 64 bit floating point registers, position independent or not), Windows' fibers on Windows. It saves the registers a function has to keep and swaps the stack. Elsewhere there are no fibers (WITH_FIBERS is not defined), nor where x86-64 Linux checks returns against a shadow stack, which fiberusable() tells: each client has a thread there. Stacks are mapped with a guard page below them. A fiber whose function returned is started again with another, its stack kept. Switches are annotated for AddressSanitizer. tests/fibertest.c tests them: yielding and resuming, the integer and floating point registers a function keeps across switches both ways, a thousand fibers resumed at random each keeping its stack, recursion deep in a stack, fibers sleeping on the event loop's timers. The units case, which was the loop case, runs it with looptest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
33 lines
1.3 KiB
Python
33 lines
1.3 KiB
Python
"""The event loop and fibers on their own: tests/looptest.c and
|
|
tests/fibertest.c, built by CMake next to the 3proxy binary, each run with
|
|
a few seeds. Skipped where they were not built (the Makefiles do not build
|
|
them)."""
|
|
|
|
import os
|
|
import subprocess
|
|
|
|
|
|
def run(t):
|
|
here = os.path.dirname(os.path.abspath(t.binary))
|
|
for unit in ("looptest", "fibertest"):
|
|
path = os.path.join(here, unit + (".exe" if os.name == "nt" else ""))
|
|
if not os.path.exists(path):
|
|
t.skip(f"{unit} is built by CMake only")
|
|
continue
|
|
for seed in ("1", "2", "3"):
|
|
try:
|
|
done = subprocess.run([path, seed], stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT, timeout=120)
|
|
except subprocess.TimeoutExpired:
|
|
t.fail(f"{unit} {seed} finishes")
|
|
continue
|
|
out = done.stdout.decode(errors="replace")
|
|
for line in out.splitlines():
|
|
if line.startswith("ok "):
|
|
t.ok(f"{unit} {seed}: {line[3:]}")
|
|
elif line.startswith("FAIL "):
|
|
label, _, what = line[5:].partition(": ")
|
|
t.fail(f"{unit} {seed}: {label}", actual=what)
|
|
if done.returncode and "FAIL " not in out:
|
|
t.fail(f"{unit} {seed} exits cleanly", 0, done.returncode)
|