Skip to content

Commit 16f4d5c

Browse files
committed
pidof: Support '-t' flag
This flag makes pidof print thread ids of threads belonging to the matching processes.
1 parent f934fa5 commit 16f4d5c

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

src/uu/pgrep/src/process.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,8 @@ pub struct ProcessInformation {
186186
cached_stat: Option<Rc<Vec<String>>>,
187187

188188
cached_start_time: Option<u64>,
189+
190+
cached_thread_ids: Option<Rc<Vec<usize>>>,
189191
}
190192

191193
impl ProcessInformation {
@@ -328,6 +330,31 @@ impl ProcessInformation {
328330

329331
Teletype::Unknown
330332
}
333+
334+
pub fn thread_ids(&mut self) -> Rc<Vec<usize>> {
335+
if let Some(c) = &self.cached_thread_ids {
336+
return Rc::clone(c);
337+
}
338+
339+
let tids_dir = format!("/proc/{}/task", self.pid);
340+
let result = Rc::new(
341+
WalkDir::new(tids_dir)
342+
.min_depth(1)
343+
.max_depth(1)
344+
.follow_links(false)
345+
.into_iter()
346+
.flatten()
347+
.flat_map(|it| {
348+
it.path()
349+
.file_name()
350+
.map(|it| it.to_str().unwrap().parse::<usize>().unwrap())
351+
})
352+
.collect::<Vec<_>>(),
353+
);
354+
355+
self.cached_thread_ids = Some(Rc::clone(&result));
356+
Rc::clone(&result)
357+
}
331358
}
332359
impl TryFrom<DirEntry> for ProcessInformation {
333360
type Error = io::Error;
@@ -446,6 +473,26 @@ mod tests {
446473
assert!(result.contains(&pid_entry.tty()));
447474
}
448475

476+
#[test]
477+
#[cfg(target_os = "linux")]
478+
fn test_thread_ids() {
479+
let main_tid = unsafe { uucore::libc::gettid() };
480+
std::thread::spawn(move || {
481+
let mut pid_entry = ProcessInformation::try_new(
482+
PathBuf::from_str(&format!("/proc/{}", current_pid())).unwrap(),
483+
)
484+
.unwrap();
485+
let thread_ids = pid_entry.thread_ids();
486+
487+
assert!(thread_ids.contains(&(main_tid as usize)));
488+
489+
let new_thread_tid = unsafe { uucore::libc::gettid() };
490+
assert!(thread_ids.contains(&(new_thread_tid as usize)));
491+
})
492+
.join()
493+
.unwrap();
494+
}
495+
449496
#[test]
450497
fn test_stat_split() {
451498
let case = "32 (idle_inject/3) S 2 0 0 0 -1 69238848 0 0 0 0 0 0 0 0 -51 0 1 0 34 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 3 50 1 0 0 0 0 0 0 0 0 0 0 0";

src/uu/pidof/src/pidof.rs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,23 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
2525
};
2626

2727
let collected = collect_matched_pids(&matches);
28+
let to_print = if matches.get_flag("t") {
29+
collected
30+
.into_iter()
31+
.flat_map(|mut it| (*it.thread_ids()).clone())
32+
.collect::<Vec<_>>()
33+
} else {
34+
collected.into_iter().map(|it| it.pid).collect::<Vec<_>>()
35+
};
2836

29-
if collected.is_empty() {
37+
if to_print.is_empty() {
3038
uucore::error::set_exit_code(1);
3139
return Ok(());
3240
};
3341

34-
let output = collected
42+
let output = to_print
3543
.into_iter()
36-
.map(|it| it.pid.to_string())
44+
.map(|it| it.to_string())
3745
.collect::<Vec<_>>()
3846
.join(arg_separator);
3947

@@ -164,6 +172,13 @@ pub fn uu_app() -> Command {
164172
.help("Only return one PID")
165173
.action(ArgAction::SetTrue),
166174
)
175+
.arg(
176+
Arg::new("t")
177+
.short('t')
178+
.long("lightweight")
179+
.help("Show thread ids instead of process ids")
180+
.action(ArgAction::SetTrue),
181+
)
167182
// .arg(
168183
// Arg::new("x")
169184
// .short('x')

tests/by-util/test_pidof.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,27 @@ fn test_separator() {
8181
.stdout_matches(re);
8282
}
8383
}
84+
85+
#[test]
86+
#[cfg(target_os = "linux")]
87+
fn test_threads() {
88+
let main_tid = unsafe { uucore::libc::gettid() };
89+
std::thread::spawn(move || {
90+
let argv0 = std::env::args().next().unwrap();
91+
let our_name = std::path::Path::new(argv0.as_str())
92+
.file_name()
93+
.unwrap()
94+
.to_str()
95+
.unwrap();
96+
97+
let new_thread_tid = unsafe { uucore::libc::gettid() };
98+
new_ucmd!()
99+
.arg("-t")
100+
.arg(our_name)
101+
.succeeds()
102+
.stdout_contains(main_tid.to_string())
103+
.stdout_contains(new_thread_tid.to_string());
104+
})
105+
.join()
106+
.unwrap();
107+
}

0 commit comments

Comments
 (0)