Skip to main content

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}