Enter inherited netns during child bootstrap
Consume an optional child-owned `(fd, inode)` capability before multiprocessing or Trio child bootstrap begins runtime setup. Deats, - enter the netns before Trio patching and actor construction - close the inherited FD before actor runtime startup - preserve entry errors when descriptor cleanup also fails - reject malformed FD values without closing unrelated descriptors - cover multiprocessing and Trio ordering with real stand-in FDs Prompt-IO: ai/prompt-io/opencode/20260828T012205Z_9ae7cd86_prompt_io.md (this patch was generated in some part by `opencode` using `gpt-5.6-sol` (`openai`))
parent
6e338a1173
commit
7dfefddae3
|
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
model: gpt-5.6-sol
|
||||
service: opencode
|
||||
session: wg-netns-bootstrap-entry
|
||||
timestamp: 2026-08-28T01:22:05Z
|
||||
git_ref: 9ae7cd86
|
||||
scope: code
|
||||
substantive: true
|
||||
raw_file: 20260828T012205Z_9ae7cd86_prompt_io.raw.md
|
||||
---
|
||||
|
||||
## Prompt
|
||||
|
||||
After completing and auditing the stacked rebase, the human approved
|
||||
the next WireGuard Layer C slice: integrate the verified network
|
||||
namespace entry primitive into child spawn bootstrap.
|
||||
|
||||
## Response summary
|
||||
|
||||
Wire an optional child-owned namespace FD and expected inode into both
|
||||
child entrypoints. Keep namespace entry and FD closure synchronous and
|
||||
ordered before actor runtime initialization, while deliberately
|
||||
deferring backend FD transport and public API plumbing.
|
||||
|
||||
## Files changed
|
||||
|
||||
- `tractor/spawn/_entry.py` - enter and release an optional inherited
|
||||
namespace capability before multiprocessing child runtime startup.
|
||||
- `tractor/_child.py` - consume the capability at the start of the
|
||||
Trio child bootloader, before patching or actor construction.
|
||||
- `tests/test_netns_spawn.py` - prove entry ordering, failure isolation,
|
||||
and exact FD ownership for both child entrypoints.
|
||||
|
||||
## Human edits
|
||||
|
||||
The human selected spawn-time namespace integration as the next work
|
||||
slice and authorized implementation. No direct manual source edits
|
||||
were observed during generation.
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
model: gpt-5.6-sol
|
||||
service: opencode
|
||||
timestamp: 2026-08-28T01:22:05Z
|
||||
git_ref: 9ae7cd86
|
||||
diff_cmd: git diff HEAD~1..HEAD
|
||||
---
|
||||
|
||||
# Raw output - enter inherited netns during child bootstrap
|
||||
|
||||
The human asked to continue the WireGuard Layer C implementation after
|
||||
the rebased branch landed the verified `spawn._netns.enter_netns()`
|
||||
primitive.
|
||||
|
||||
## Generated code
|
||||
|
||||
> `git diff HEAD~1..HEAD -- tractor/_child.py tractor/spawn/_entry.py tests/test_netns_spawn.py`
|
||||
|
||||
Add one optional atomic `(namespace_fd, expected_inode)` bootstrap
|
||||
capability to the multiprocessing entrypoint and Trio child bootloader.
|
||||
Enter and verify the namespace before Trio patching, actor construction,
|
||||
runtime state, logging, Trio startup, parent connection, sockets, or
|
||||
worker threads, then close the child-owned inherited FD before
|
||||
continuing.
|
||||
|
||||
Add privilege-free direct-entrypoint tests using real stand-in FDs and
|
||||
a fake namespace syscall boundary. Cover helper-level no-op behavior,
|
||||
successful entry ordering, exact FD closure, malformed-FD isolation,
|
||||
primary-error preservation, and failure cleanup for both child
|
||||
bootstrap paths.
|
||||
|
||||
## Scope boundary
|
||||
|
||||
This increment does not transfer FDs through spawn backends or expose a
|
||||
public actor API. Backend-specific FD duplication, bootstrap failure
|
||||
reporting, and root-process namespace entry remain follow-up work.
|
||||
|
|
@ -4,13 +4,37 @@ Pre-runtime Linux network-namespace entry validation.
|
|||
'''
|
||||
from __future__ import annotations
|
||||
|
||||
import errno
|
||||
from functools import partial
|
||||
import os
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from typing import BinaryIO
|
||||
from typing import (
|
||||
Any,
|
||||
BinaryIO,
|
||||
)
|
||||
|
||||
import pytest
|
||||
|
||||
from tractor.spawn import _netns
|
||||
from tractor import _child
|
||||
from tractor.devx import _proctitle
|
||||
from tractor.spawn import (
|
||||
_entry,
|
||||
_netns,
|
||||
_spawn,
|
||||
)
|
||||
from tractor.trionics import patches
|
||||
|
||||
|
||||
def _assert_fd_closed(namespace_fd: int) -> None:
|
||||
'''
|
||||
Assert that bootstrap consumed its child-owned descriptor.
|
||||
|
||||
'''
|
||||
with pytest.raises(OSError) as exc_info:
|
||||
os.fstat(namespace_fd)
|
||||
|
||||
assert exc_info.value.errno == errno.EBADF
|
||||
|
||||
|
||||
def test_enter_netns_rejects_mismatched_inherited_fd(
|
||||
|
|
@ -140,3 +164,416 @@ def test_enter_netns_rejects_wrong_post_entry_namespace(
|
|||
# Deliberately differ from `fake_stat()`'s inode + 1.
|
||||
inode,
|
||||
)
|
||||
|
||||
|
||||
def test_empty_netns_bootstrap_is_a_noop(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
'''
|
||||
Ordinary child startup must not attempt namespace entry.
|
||||
|
||||
Leave the optional capability unset and arm `enter_netns()` as a
|
||||
failure sentinel. The bootstrap boundary must return without any
|
||||
syscall or descriptor ownership work for existing spawn callers.
|
||||
|
||||
'''
|
||||
def fail_enter_netns(namespace_fd: int, inode: int) -> int:
|
||||
'''
|
||||
Reject namespace entry without an explicit capability.
|
||||
|
||||
'''
|
||||
raise AssertionError('empty bootstrap attempted netns entry')
|
||||
|
||||
monkeypatch.setattr(_entry, 'enter_netns', fail_enter_netns)
|
||||
|
||||
assert _entry._consume_netns_bootstrap(None) is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize('namespace_fd', (-1, True, '1'))
|
||||
def test_invalid_netns_fd_is_never_closed(
|
||||
namespace_fd: object,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
'''
|
||||
Invalid descriptor values must not reach the OS close boundary.
|
||||
|
||||
Feed negative, boolean, and non-integer values through the atomic
|
||||
capability. Preserve the namespace primitive's validation error
|
||||
without letting `bool` alias stdout or allowing cleanup to mask the
|
||||
primary failure.
|
||||
|
||||
'''
|
||||
entry_error = ValueError('invalid netns capability')
|
||||
|
||||
def fail_enter_netns(namespace_fd: int, inode: int) -> int:
|
||||
'''
|
||||
Raise the primary namespace bootstrap error.
|
||||
|
||||
'''
|
||||
raise entry_error
|
||||
|
||||
def fail_close(inherited_fd: int) -> None:
|
||||
'''
|
||||
Reject cleanup for a value that cannot be an owned FD.
|
||||
|
||||
'''
|
||||
raise AssertionError('invalid namespace FD reached close')
|
||||
|
||||
monkeypatch.setattr(_entry, 'enter_netns', fail_enter_netns)
|
||||
monkeypatch.setattr(
|
||||
_entry,
|
||||
'os',
|
||||
SimpleNamespace(close=fail_close),
|
||||
)
|
||||
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
_entry._consume_netns_bootstrap(
|
||||
(namespace_fd, 1), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
assert exc_info.value is entry_error
|
||||
|
||||
|
||||
def test_netns_entry_error_survives_close_failure(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
'''
|
||||
Descriptor cleanup must not mask the primary bootstrap failure.
|
||||
|
||||
Raise a unique entry error for an oversized positive integer whose
|
||||
cleanup also raises `OverflowError`. The entry error must escape
|
||||
with cleanup context attached instead of being replaced by the
|
||||
close failure.
|
||||
|
||||
'''
|
||||
namespace_fd: int = 1 << 100
|
||||
entry_error = ValueError('invalid netns capability')
|
||||
|
||||
def fail_enter_netns(inherited_fd: int, inode: int) -> int:
|
||||
'''
|
||||
Raise the primary namespace bootstrap error.
|
||||
|
||||
'''
|
||||
assert inherited_fd == namespace_fd
|
||||
raise entry_error
|
||||
|
||||
monkeypatch.setattr(_entry, 'enter_netns', fail_enter_netns)
|
||||
|
||||
with pytest.raises(ValueError) as exc_info:
|
||||
_entry._consume_netns_bootstrap((namespace_fd, 1))
|
||||
|
||||
assert exc_info.value is entry_error
|
||||
assert entry_error.__notes__
|
||||
assert 'close inherited namespace FD' in entry_error.__notes__[0]
|
||||
assert 'OverflowError' in entry_error.__notes__[0]
|
||||
|
||||
|
||||
@pytest.mark.parametrize('backend', ('mp', 'trio'))
|
||||
def test_child_entry_consumes_netns_before_runtime(
|
||||
backend: str,
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
'''
|
||||
Child bootstrap must enter its netns before runtime side effects.
|
||||
|
||||
Give each child entrypoint an exclusively owned stand-in FD. Fake
|
||||
only namespace entry and every later bootstrap boundary, requiring
|
||||
the FD to remain open during entry but be closed before actor state,
|
||||
logging, multiprocessing setup, frame hiding, or `trio.run()`.
|
||||
This proves verified entry and capability release are one
|
||||
synchronous prefix of both child startup paths.
|
||||
|
||||
'''
|
||||
token_path: Path = tmp_path / f'{backend}-netns'
|
||||
token_path.touch()
|
||||
namespace_fd: int = os.open(token_path, os.O_RDONLY)
|
||||
expected_inode: int = os.fstat(namespace_fd).st_ino
|
||||
events: list[str] = []
|
||||
|
||||
def fake_enter_netns(
|
||||
inherited_fd: int,
|
||||
inode: int,
|
||||
) -> int:
|
||||
'''
|
||||
Record verified entry while the capability remains open.
|
||||
|
||||
'''
|
||||
assert os.fstat(inherited_fd).st_ino == expected_inode
|
||||
assert inherited_fd == namespace_fd
|
||||
assert inode == expected_inode
|
||||
events.append('enter-netns')
|
||||
return inode
|
||||
|
||||
def record(
|
||||
event: str,
|
||||
*args: object,
|
||||
**kwargs: object,
|
||||
) -> None:
|
||||
'''
|
||||
Record one post-entry operation after proving FD release.
|
||||
|
||||
'''
|
||||
_assert_fd_closed(namespace_fd)
|
||||
events.append(event)
|
||||
|
||||
class ActorSpy:
|
||||
'''
|
||||
Record multiprocessing actor-state initialization.
|
||||
|
||||
'''
|
||||
loglevel = None
|
||||
uid = ('netns-child', 'test')
|
||||
_infected_aio = False
|
||||
|
||||
def __setattr__(
|
||||
self,
|
||||
name: str,
|
||||
value: object,
|
||||
) -> None:
|
||||
'''
|
||||
Observe the first multiprocessing entrypoint mutation.
|
||||
|
||||
'''
|
||||
if name == '_forkserver_info':
|
||||
record('forkserver-info')
|
||||
object.__setattr__(self, name, value)
|
||||
|
||||
class StateSpy:
|
||||
'''
|
||||
Record actor publication into runtime-global state.
|
||||
|
||||
'''
|
||||
def __setattr__(
|
||||
self,
|
||||
name: str,
|
||||
value: object,
|
||||
) -> None:
|
||||
'''
|
||||
Observe `_state._current_actor` publication.
|
||||
|
||||
'''
|
||||
record('runtime-state')
|
||||
object.__setattr__(self, name, value)
|
||||
|
||||
def fake_current_process() -> str:
|
||||
'''
|
||||
Return one display value for multiprocessing startup logging.
|
||||
|
||||
'''
|
||||
return 'fake-child-process'
|
||||
|
||||
def fake_start_method(start_method: str) -> SimpleNamespace:
|
||||
'''
|
||||
Record multiprocessing setup after namespace entry.
|
||||
|
||||
'''
|
||||
record('start-method')
|
||||
return SimpleNamespace(
|
||||
current_process=fake_current_process,
|
||||
)
|
||||
|
||||
def fake_actor(**kwargs: object) -> ActorSpy:
|
||||
'''
|
||||
Record Trio child actor construction after namespace entry.
|
||||
|
||||
'''
|
||||
record('actor-construction')
|
||||
return ActorSpy()
|
||||
|
||||
monkeypatch.setattr(_entry, 'enter_netns', fake_enter_netns)
|
||||
monkeypatch.setattr(_entry, '_state', StateSpy())
|
||||
monkeypatch.setattr(
|
||||
_entry._frame_stack,
|
||||
'hide_runtime_frames',
|
||||
partial(record, 'hide-frames'),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
_entry.trio,
|
||||
'run',
|
||||
partial(record, 'trio-run'),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
_entry,
|
||||
'log',
|
||||
SimpleNamespace(
|
||||
info=partial(record, 'log'),
|
||||
cancel=partial(record, 'log'),
|
||||
error=partial(record, 'log'),
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
_spawn,
|
||||
'try_set_start_method',
|
||||
fake_start_method,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
patches,
|
||||
'apply_all',
|
||||
partial(record, 'trio-patches'),
|
||||
)
|
||||
monkeypatch.setattr(_child, 'Actor', fake_actor)
|
||||
monkeypatch.setattr(
|
||||
_proctitle,
|
||||
'set_actor_proctitle',
|
||||
partial(record, 'proctitle'),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
_child,
|
||||
'_trio_main',
|
||||
partial(record, 'trio-main'),
|
||||
)
|
||||
|
||||
actor: Any = ActorSpy()
|
||||
bootstrap: tuple[int, int] = (
|
||||
namespace_fd,
|
||||
expected_inode,
|
||||
)
|
||||
if backend == 'mp':
|
||||
_entry._mp_main(
|
||||
actor,
|
||||
[],
|
||||
(None, None, None, None, None),
|
||||
'mp_spawn',
|
||||
netns_bootstrap=bootstrap,
|
||||
)
|
||||
first_runtime_event: str = 'forkserver-info'
|
||||
terminal_event: str = 'trio-run'
|
||||
else:
|
||||
_child._actor_child_main(
|
||||
uid=actor.uid,
|
||||
loglevel=actor.loglevel,
|
||||
parent_addr=None,
|
||||
infect_asyncio=False,
|
||||
netns_bootstrap=bootstrap,
|
||||
)
|
||||
first_runtime_event = 'trio-patches'
|
||||
terminal_event = 'trio-main'
|
||||
|
||||
assert events[:2] == [
|
||||
'enter-netns',
|
||||
first_runtime_event,
|
||||
]
|
||||
assert events.count(terminal_event) == 1
|
||||
_assert_fd_closed(namespace_fd)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('backend', ('mp', 'trio'))
|
||||
def test_child_entry_failure_closes_netns_fd_before_runtime(
|
||||
backend: str,
|
||||
tmp_path: Path,
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
'''
|
||||
Failed namespace entry must close its FD and abort child startup.
|
||||
|
||||
Raise a unique error from the namespace boundary while a real
|
||||
stand-in FD is open. Arm each entrypoint's first later operation as
|
||||
a failure sentinel, then prove the original error escapes, the
|
||||
descriptor is closed, and no actor, multiprocessing, frame, or
|
||||
Trio runtime initialization begins.
|
||||
|
||||
'''
|
||||
token_path: Path = tmp_path / f'{backend}-failed-netns'
|
||||
token_path.touch()
|
||||
namespace_fd: int = os.open(token_path, os.O_RDONLY)
|
||||
expected_inode: int = os.fstat(namespace_fd).st_ino
|
||||
entry_error = RuntimeError('netns entry failed')
|
||||
events: list[str] = []
|
||||
|
||||
def fail_enter_netns(
|
||||
inherited_fd: int,
|
||||
inode: int,
|
||||
) -> int:
|
||||
'''
|
||||
Fail entry while proving the child-owned FD is still open.
|
||||
|
||||
'''
|
||||
assert os.fstat(inherited_fd).st_ino == expected_inode
|
||||
assert inherited_fd == namespace_fd
|
||||
assert inode == expected_inode
|
||||
events.append('enter-netns')
|
||||
raise entry_error
|
||||
|
||||
def fail_after_entry(*args: object, **kwargs: object) -> None:
|
||||
'''
|
||||
Reject any runtime operation after failed namespace entry.
|
||||
|
||||
'''
|
||||
raise AssertionError('child runtime started after netns failure')
|
||||
|
||||
class ActorSpy:
|
||||
'''
|
||||
Reject multiprocessing actor-state initialization.
|
||||
|
||||
'''
|
||||
loglevel = None
|
||||
uid = ('failed-netns-child', 'test')
|
||||
|
||||
def __setattr__(
|
||||
self,
|
||||
name: str,
|
||||
value: object,
|
||||
) -> None:
|
||||
'''
|
||||
Reject the first multiprocessing entrypoint mutation.
|
||||
|
||||
'''
|
||||
if name == '_forkserver_info':
|
||||
fail_after_entry()
|
||||
object.__setattr__(self, name, value)
|
||||
|
||||
monkeypatch.setattr(_entry, 'enter_netns', fail_enter_netns)
|
||||
monkeypatch.setattr(
|
||||
_entry._frame_stack,
|
||||
'hide_runtime_frames',
|
||||
fail_after_entry,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
_spawn,
|
||||
'try_set_start_method',
|
||||
fail_after_entry,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
patches,
|
||||
'apply_all',
|
||||
fail_after_entry,
|
||||
)
|
||||
monkeypatch.setattr(_child, 'Actor', fail_after_entry)
|
||||
monkeypatch.setattr(
|
||||
_proctitle,
|
||||
'set_actor_proctitle',
|
||||
fail_after_entry,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
_child,
|
||||
'_trio_main',
|
||||
fail_after_entry,
|
||||
)
|
||||
|
||||
actor: Any = ActorSpy()
|
||||
bootstrap: tuple[int, int] = (
|
||||
namespace_fd,
|
||||
expected_inode,
|
||||
)
|
||||
with pytest.raises(RuntimeError) as exc_info:
|
||||
if backend == 'mp':
|
||||
_entry._mp_main(
|
||||
actor,
|
||||
[],
|
||||
(None, None, None, None, None),
|
||||
'mp_spawn',
|
||||
netns_bootstrap=bootstrap,
|
||||
)
|
||||
else:
|
||||
_child._actor_child_main(
|
||||
uid=actor.uid,
|
||||
loglevel=actor.loglevel,
|
||||
parent_addr=None,
|
||||
infect_asyncio=False,
|
||||
netns_bootstrap=bootstrap,
|
||||
)
|
||||
|
||||
assert exc_info.value is entry_error
|
||||
assert events == ['enter-netns']
|
||||
_assert_fd_closed(namespace_fd)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,10 @@ from ast import literal_eval
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from .runtime._runtime import Actor
|
||||
from .spawn._entry import _trio_main
|
||||
from .spawn._entry import (
|
||||
_consume_netns_bootstrap,
|
||||
_trio_main,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .discovery._addr import UnwrappedAddress
|
||||
|
|
@ -52,6 +55,7 @@ def _actor_child_main(
|
|||
parent_addr: UnwrappedAddress | None,
|
||||
infect_asyncio: bool,
|
||||
spawn_method: SpawnMethodKey = 'trio',
|
||||
netns_bootstrap: tuple[int, int]|None = None,
|
||||
|
||||
) -> None:
|
||||
'''
|
||||
|
|
@ -62,7 +66,13 @@ def _actor_child_main(
|
|||
invokes this from inside a fresh `concurrent.interpreters`
|
||||
sub-interpreter via `Interpreter.call()`.
|
||||
|
||||
Consume `netns_bootstrap` before Trio patching, actor construction,
|
||||
process-title setup, or actor-runtime entry. The spawn backend must
|
||||
supply an exclusively child-owned FD duplicate.
|
||||
|
||||
'''
|
||||
_consume_netns_bootstrap(netns_bootstrap)
|
||||
|
||||
# Apply defensive monkey-patches for upstream `trio`
|
||||
# bugs we've encountered while running tractor — see
|
||||
# `tractor.trionics.patches` for the catalog +
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ Sub-process entry points.
|
|||
from __future__ import annotations
|
||||
from functools import partial
|
||||
import multiprocessing as mp
|
||||
import os
|
||||
from typing import (
|
||||
Any,
|
||||
TYPE_CHECKING,
|
||||
|
|
@ -48,6 +49,7 @@ from ..runtime._runtime import (
|
|||
async_main,
|
||||
Actor,
|
||||
)
|
||||
from ._netns import enter_netns
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._spawn import SpawnMethodKey
|
||||
|
|
@ -56,6 +58,54 @@ if TYPE_CHECKING:
|
|||
log = get_logger()
|
||||
|
||||
|
||||
def _consume_netns_bootstrap(
|
||||
netns_bootstrap: tuple[int, int]|None,
|
||||
) -> int|None:
|
||||
'''
|
||||
Enter and release one child-owned network namespace capability.
|
||||
|
||||
The FD must be an exclusively child-owned backend duplicate. It is
|
||||
closed whether namespace entry succeeds or fails, before any actor
|
||||
runtime setup can continue.
|
||||
|
||||
'''
|
||||
if netns_bootstrap is None:
|
||||
return None
|
||||
|
||||
namespace_fd: int
|
||||
expected_inode: int
|
||||
namespace_fd, expected_inode = netns_bootstrap
|
||||
if (
|
||||
type(namespace_fd) is not int
|
||||
or
|
||||
namespace_fd < 0
|
||||
):
|
||||
# Let `enter_netns()` report its precise validation error, but
|
||||
# never pass bool/non-int/negative values to `os.close()`.
|
||||
return enter_netns(
|
||||
namespace_fd,
|
||||
expected_inode,
|
||||
)
|
||||
|
||||
try:
|
||||
entered_inode: int = enter_netns(
|
||||
namespace_fd,
|
||||
expected_inode,
|
||||
)
|
||||
except BaseException as entry_error:
|
||||
try:
|
||||
os.close(namespace_fd)
|
||||
except Exception as close_error:
|
||||
entry_error.add_note(
|
||||
f'Also failed to close inherited namespace FD '
|
||||
f'{namespace_fd}: {close_error!r}'
|
||||
)
|
||||
raise
|
||||
else:
|
||||
os.close(namespace_fd)
|
||||
return entered_inode
|
||||
|
||||
|
||||
def _mp_main(
|
||||
|
||||
actor: Actor,
|
||||
|
|
@ -64,12 +114,18 @@ def _mp_main(
|
|||
start_method: SpawnMethodKey,
|
||||
parent_addr: UnwrappedAddress | None = None,
|
||||
infect_asyncio: bool = False,
|
||||
netns_bootstrap: tuple[int, int]|None = None,
|
||||
|
||||
) -> None:
|
||||
'''
|
||||
The routine called *after fork* which invokes a fresh `trio.run()`
|
||||
|
||||
Consume `netns_bootstrap` before multiprocessing or actor-runtime
|
||||
setup. The spawn backend must supply a child-owned FD duplicate.
|
||||
|
||||
'''
|
||||
_consume_netns_bootstrap(netns_bootstrap)
|
||||
|
||||
actor._forkserver_info = forkserver_info
|
||||
from ._spawn import try_set_start_method
|
||||
spawn_ctx: mp.context.BaseContext = try_set_start_method(start_method)
|
||||
|
|
|
|||
Loading…
Reference in New Issue