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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//! Running work where the OS can account for it separately.
//!
//! # What went wrong
//!
//! A daemon started from a terminal inherits that terminal's cgroup, and so
//! does everything it starts. On a systemd desktop that cgroup is a transient
//! scope belonging to the terminal — `app-ghostty-surface-…scope` — and
//! `systemd-oomd` watches cgroups, not processes: when memory ran short during
//! a `cargo build` the scope was the worst offender at 21.8 GB, so oomd killed
//! processes in it. The build was in it. So was the daemon. So was the
//! terminal.
//!
//! The daemon did not use that memory. It was standing next to something that
//! did, and to the OS they were one thing.
//!
//! # What a terminal does differently
//!
//! Nothing — and that is the point. A build typed into a terminal is in that
//! terminal's scope too, so it can be killed the same way; it just takes down
//! a shell rather than a long-lived server that every other surface depends
//! on. And each terminal window gets its own scope, so one runaway build never
//! reaches the next window.
//!
//! # What this does
//!
//! Puts the daemon in a scope of its own, marked so that the OS's memory
//! reaper prefers anything else — a server holding no memory of its own should
//! not be collateral for a compiler that does.
//!
//! Where none of this exists — macOS, a machine without systemd, a session
//! with no bus — the command is run exactly as before. The protection is an
//! improvement where it is available, never a requirement.
use OnceLock;
/// Properties for the daemon's own scope.
///
/// `ManagedOOMPreference=avoid` asks systemd's reaper to look elsewhere first.
/// It is a preference, not immunity — nothing can promise a process survives
/// an out-of-memory — but the daemon is exactly the process that should be
/// last, since it uses almost nothing and everything else is reachable through
/// it.
pub const DAEMON_PROPERTIES: & = &;
/// Whether this machine can put a command in its own scope.
///
/// Probed once, by running one, because every part of the answer can be false
/// on a machine that otherwise looks right: `systemd-run` present but no user
/// session, a session but no bus address in this process's environment, a
/// container with cgroups it may not write. Asking is one short-lived process
/// per daemon; guessing from `$XDG_RUNTIME_DIR` was wrong on the first machine
/// it would have been tried on.
/// The argv that runs `argv` inside its own scope, or None to run it as it is.
///
/// `unit` names the scope, so `systemctl --user status` and a cgroup listing
/// say what the thing IS rather than `run-p12345`. Names are made safe here
/// rather than trusted: a unit name with a slash in it is refused by systemd
/// at spawn time, which would turn a naming mistake into a daemon that will
/// not start.
/// A short, stable tag for one workspace, so its daemon's scope is named for
/// the tree it serves rather than for a pid.
///
/// `systemctl --user status` and a cgroup listing are read by somebody trying
/// to work out what is using a machine; `wsb-daemon-machinefabric` answers
/// that and `run-p31034` does not.
/// A systemd unit name: letters, digits, dashes and underscores.
/// The unit systemd will know a scope by, given the tag it was wrapped with.