agentmux_srv/proc_name.rs
1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! The name `ps`, `top` and desktop system monitors show for this process on
5//! Linux.
6//!
7//! The kernel keeps a 15-byte process name (`comm`), cut from the file name.
8//! srv ships as `agentmux-srv-<version>-linux.x64`, so without this it shows
9//! as `agentmux-srv-0.`, a name that changes with every release. Each role srv
10//! runs in sets a stable name instead
11//! (docs/reports/REPORT_PROCESS_ICONS_NAMES_AND_LABELS_2026_10_10.md ยง8.2).
12//!
13//! Only the calling thread is renamed, and the main thread's name is the
14//! process's, so call this from the main thread. Elsewhere it does nothing:
15//! Windows takes the name from the exe's version resource (`build.rs`), and
16//! macOS has no equivalent call.
17
18/// The backend itself.
19pub const MAIN: &str = "agentmux-srv";
20
21/// The child srv re-runs itself as to parse one attached document
22/// (`backend::attachments::extract`).
23pub const DOC_CHILD: &str = "agentmux-srvdoc";
24
25/// Set this thread's name. Longer than 15 bytes is cut by the kernel.
26pub fn set(name: &str) {
27 #[cfg(target_os = "linux")]
28 {
29 if let Ok(c) = std::ffi::CString::new(name) {
30 // SAFETY: PR_SET_NAME reads a NUL-terminated string, copying at
31 // most 16 bytes; `c` outlives the call.
32 unsafe {
33 libc::prctl(libc::PR_SET_NAME, c.as_ptr() as libc::c_ulong, 0, 0, 0);
34 }
35 }
36 }
37 #[cfg(not(target_os = "linux"))]
38 let _ = name;
39}
40
41#[cfg(all(test, target_os = "linux"))]
42mod tests {
43 use super::*;
44
45 fn own_thread_name() -> String {
46 std::fs::read_to_string("/proc/thread-self/comm").unwrap().trim_end().to_string()
47 }
48
49 // A spawned thread, so renaming it can't affect the test harness.
50 #[test]
51 fn sets_the_names_srv_uses() {
52 std::thread::spawn(|| {
53 for name in [MAIN, DOC_CHILD] {
54 assert!(name.len() <= 15, "{name} would be cut by the kernel");
55 set(name);
56 assert_eq!(own_thread_name(), name);
57 }
58 })
59 .join()
60 .unwrap();
61 }
62
63 #[test]
64 fn a_long_name_is_cut_to_fifteen_bytes() {
65 std::thread::spawn(|| {
66 set("agentmux-srv-0.59.18-linux.x64");
67 assert_eq!(own_thread_name(), "agentmux-srv-0.");
68 })
69 .join()
70 .unwrap();
71 }
72}