Skip to content

Commit 8b64351

Browse files
committed
pgrep: Support -w option
Unlike pidof's similar option, the pgrep version will run the match predicates against every thread of the system and printing matching tids (unlike pidof which will run match predicates on every process of the system and then list every thread of every matched process).
1 parent 0fac169 commit 8b64351

File tree

4 files changed

+49
-4
lines changed

4 files changed

+49
-4
lines changed

src/uu/pgrep/src/pgrep.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ const USAGE: &str = help_usage!("pgrep.md");
2828
#[uucore::main]
2929
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
3030
let matches = uu_app().try_get_matches_from(args)?;
31-
let settings = process_matcher::get_match_settings(&matches)?;
31+
let mut settings = process_matcher::get_match_settings(&matches)?;
32+
settings.threads = matches.get_flag("lightweight");
3233

3334
// Collect pids
3435
let pids = process_matcher::find_matching_pids(&settings);
@@ -82,7 +83,7 @@ pub fn uu_app() -> Command {
8283
.hide_default_value(true),
8384
arg!(-l --"list-name" "list PID and process name"),
8485
arg!(-a --"list-full" "list PID and full command line"),
85-
// arg!(-w --lightweight "list all TID"),
86+
arg!(-w --lightweight "list all TID"),
8687
])
8788
.args(process_matcher::clap_args(
8889
"Name of the program to find the PID of",

src/uu/pgrep/src/process.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6+
use regex::Regex;
67
use std::hash::Hash;
8+
use std::sync::LazyLock;
79
use std::{
810
collections::HashMap,
911
fmt::{self, Display, Formatter},
@@ -460,6 +462,22 @@ pub fn walk_process() -> impl Iterator<Item = ProcessInformation> {
460462
.flat_map(ProcessInformation::try_from)
461463
}
462464

465+
static THREAD_REGEX: LazyLock<Regex> = LazyLock::new(|| {
466+
Regex::new(r"^/proc/[0-9]+$|^/proc/[0-9]+/task$|^/proc/[0-9]+/task/[0-9]+$").unwrap()
467+
});
468+
469+
pub fn walk_threads() -> impl Iterator<Item = ProcessInformation> {
470+
WalkDir::new("/proc/")
471+
.min_depth(1)
472+
.max_depth(3)
473+
.follow_links(false)
474+
.into_iter()
475+
.filter_entry(|e| THREAD_REGEX.is_match(e.path().as_os_str().to_string_lossy().as_ref()))
476+
.flatten()
477+
.filter(|it| it.path().as_os_str().to_string_lossy().contains("/task/"))
478+
.flat_map(ProcessInformation::try_from)
479+
}
480+
463481
#[cfg(test)]
464482
mod tests {
465483
use super::*;

src/uu/pgrep/src/process_matcher.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use uucore::{
2121

2222
use uucore::error::{UResult, USimpleError};
2323

24-
use crate::process::{walk_process, ProcessInformation, Teletype};
24+
use crate::process::{walk_process, walk_threads, ProcessInformation, Teletype};
2525

2626
pub struct Settings {
2727
pub regex: Regex,
@@ -44,6 +44,7 @@ pub struct Settings {
4444
pub gid: Option<HashSet<u32>>,
4545
pub pgroup: Option<HashSet<u64>>,
4646
pub session: Option<HashSet<u64>>,
47+
pub threads: bool,
4748
}
4849

4950
pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
@@ -100,6 +101,7 @@ pub fn get_match_settings(matches: &ArgMatches) -> UResult<Settings> {
100101
})
101102
.collect()
102103
}),
104+
threads: false,
103105
};
104106

105107
if !settings.newest
@@ -194,8 +196,14 @@ fn collect_matched_pids(settings: &Settings) -> Vec<ProcessInformation> {
194196
let filtered: Vec<ProcessInformation> = {
195197
let mut tmp_vec = Vec::new();
196198

199+
let pids = if settings.threads {
200+
walk_threads().collect::<Vec<_>>()
201+
} else {
202+
walk_process().collect::<Vec<_>>()
203+
};
197204
let our_pid = std::process::id() as usize;
198-
for mut pid in walk_process().collect::<Vec<_>>() {
205+
206+
for mut pid in pids {
199207
if pid.pid == our_pid {
200208
continue;
201209
}

tests/by-util/test_pgrep.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,3 +478,21 @@ fn test_session() {
478478
fn test_nonexisting_session() {
479479
new_ucmd!().arg("--session=9999999999").fails();
480480
}
481+
482+
#[test]
483+
#[cfg(target_os = "linux")]
484+
fn test_threads() {
485+
std::thread::Builder::new()
486+
.name("PgrepTest".to_owned())
487+
.spawn(|| {
488+
let thread_tid = unsafe { uucore::libc::gettid() };
489+
new_ucmd!()
490+
.arg("-w")
491+
.arg("PgrepTest")
492+
.succeeds()
493+
.stdout_contains(thread_tid.to_string());
494+
})
495+
.unwrap()
496+
.join()
497+
.unwrap();
498+
}

0 commit comments

Comments
 (0)