1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//! **One world has one engine** (DESIGN §8.5, §16.2; bl-1d9b) — the exclusion,
//! taken before the engine consumes anything and released when it drops.
//!
//! A second `yog` booted on a world the first still holds used to print its
//! bind refusal and **carry on**. It had no listener, so no seat could reach
//! it, but it still drained the world's `gestures/` inbox and still held its
//! own [`Slots`](crate::registry::mailbox) — its own `seq`, its own `live` map,
//! its own presence map. Two consumers on one inbox is two mailboxes minting
//! into one `inv-N` namespace: a routed tool call answered `no invocation
//! "inv-5" is in flight` when the handle missed, and — the reason this is a p1
//! — handed back **another invocation's capture** when it collided. Presence
//! forked the same way: one engine answered "not connected right now" while the
//! other, one second later, answered "connected right now", and both sentences
//! reached one model.
//!
//! **Why a lock and not the bind.** The bind is the natural exclusion and it
//! cannot be this one: a self-provisioned box's `wire/address` says
//! `127.0.0.1:0` (REMOTE §8, bl-dc14 — so two engines in two *worlds* never
//! contend for a process-global port), and two `:0` binds both succeed on
//! different kernel-chosen ports. Recording a concrete port at mint time would
//! make the bind exclusive again and would put a listener in the ephemeral
//! range, where a boot that finds its own port taken by some outbound
//! connection is an engine that will not start for a reason no operator can
//! see. The lock states the invariant directly, at the one place it means
//! something — the world — and is independent of whether a wire exists at all.
//!
//! **Why an advisory file lock and not a pid file.** The lock is held by an
//! open file description, so the kernel releases it when this process ends **by
//! any means** — a clean drop, a `SIGKILL`, an OOM. There is no stale record to
//! reap, no liveness probe, and nothing to get wrong about a pid that has been
//! reused. The lock file itself is a durable artifact of no interest: its
//! *content* is never read, only the lock on it.
//!
//! **The one window it cannot close, stated rather than papered over.** An open
//! file description is shared with every `fork`, so a child forked while this
//! descriptor was open holds the lock too, until it closes it — which its own
//! `exec` does, since std opens with `O_CLOEXEC`. The window is therefore
//! fork-to-exec, microseconds, and it can only ever *delay* a next engine, never
//! admit a second one. Nothing in production is inside it: a restart is a new
//! process launched long after the old one's children have exec'd. The suite
//! sees it, because it forks continuously, and `engine::tests` waits it out
//! rather than pretending it is not there.
use ;
use Path;
/// The lock file's leaf, under the yog state root (§5.2) beside `ui.json` and
/// `ops.jsonl` — yog's own artifacts, which is what this is.
pub const LOCK: &str = "engine.lock";
/// The held exclusion. Owns the open file; dropping it closes the descriptor,
/// which is what releases the lock — the §7.2 shutdown shape with nothing to
/// signal and nothing to join.
pub
/// Claim this world for this engine, or say who has it.
///
/// The refusal names the file, because that is the one place an operator can
/// look to see the fact: `fuser`/`lsof` on it names the holding process, and
/// nothing yog could write there would be more current than the lock itself.
pub