Skip to content

Commit 65b3d80

Browse files
klim-ivIgor
authored andcommitted
take into account the num of processes by ulimit
due to ulimit restrictions is not used in std::thread upears crashed like this one: thread 'main' panicked at .../.cargo/registry/.../rayon-core-1.12.1/src/registry.rs:168:10: The global thread pool has not been initialized.: ThreadPoolBuildError { kind: IOError(Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }) } resolve #143635
1 parent 1b0bc59 commit 65b3d80

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

library/std/src/sys/pal/unix/thread.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::sys::weak::dlsym;
77
use crate::sys::weak::weak;
88
use crate::sys::{os, stack_overflow};
99
use crate::time::{Duration, Instant};
10-
use crate::{cmp, io, ptr};
10+
use crate::{cmp, fs, io, ptr};
1111
#[cfg(not(any(
1212
target_os = "l4re",
1313
target_os = "vxworks",
@@ -405,6 +405,41 @@ fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_W
405405
result
406406
}
407407

408+
fn count_user_threads() -> Result<usize, io::Error> {
409+
let current_uid = unsafe { libc::getuid() };
410+
let mut thread_count = 0;
411+
412+
for entry in fs::read_dir("/proc")? {
413+
let entry = entry?;
414+
let pid = entry.file_name().to_string_lossy().to_string();
415+
416+
if let Ok(_pid_num) = pid.parse::<u32>() {
417+
let status_path = format!("/proc/{}/status", pid);
418+
419+
if let Ok(status) = fs::read_to_string(status_path) {
420+
let mut uid: Option<libc::uid_t> = None;
421+
let mut threads: Option<usize> = None;
422+
423+
for line in status.lines() {
424+
if line.starts_with("Uid:") {
425+
uid = line.split_whitespace().nth(1).and_then(|s| s.parse().ok());
426+
} else if line.starts_with("Threads:") {
427+
threads = line.split_whitespace().nth(1).and_then(|s| s.parse().ok());
428+
}
429+
}
430+
431+
if let (Some(uid), Some(t)) = (uid, threads) {
432+
if uid == current_uid {
433+
thread_count += t;
434+
}
435+
}
436+
}
437+
}
438+
}
439+
440+
Ok(thread_count)
441+
}
442+
408443
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
409444
cfg_if::cfg_if! {
410445
if #[cfg(any(
@@ -420,6 +455,7 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
420455
#[allow(unused_assignments)]
421456
#[allow(unused_mut)]
422457
let mut quota = usize::MAX;
458+
let mut ulimit = libc::rlim_t::MAX;
423459

424460
#[cfg(any(target_os = "android", target_os = "linux"))]
425461
{
@@ -439,14 +475,30 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
439475
}
440476
}
441477
}
478+
479+
let mut r: libc::rlimit = unsafe { mem::zeroed() };
480+
unsafe {
481+
if libc::getrlimit(libc::RLIMIT_NPROC, &mut r) == 0 {
482+
match r.rlim_cur {
483+
libc::RLIM_INFINITY => ulimit = libc::rlim_t::MAX,
484+
soft_limit => {
485+
ulimit = match count_user_threads() {
486+
Ok(t) => soft_limit - t as libc::rlim_t,
487+
_ => 1
488+
}
489+
}
490+
}
491+
}
492+
}
442493
}
494+
443495
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
444496
-1 => Err(io::Error::last_os_error()),
445497
0 => Err(io::Error::UNKNOWN_THREAD_COUNT),
446498
cpus => {
447499
let count = cpus as usize;
448500
// Cover the unusual situation where we were able to get the quota but not the affinity mask
449-
let count = count.min(quota);
501+
let count = count.min(quota.min(ulimit.try_into().unwrap_or(usize::MAX)));
450502
Ok(unsafe { NonZero::new_unchecked(count) })
451503
}
452504
}

library/std/src/thread/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2012,6 +2012,9 @@ fn _assert_sync_and_send() {
20122012
/// which may take time on systems with large numbers of mountpoints.
20132013
/// (This does not apply to cgroup v2, or to processes not in a
20142014
/// cgroup.)
2015+
/// - If was set _ulimit_ restrictions for maximum number of processes that can be
2016+
/// created for the real user ID (`ulimit -u`), then result will be arithmetic difference
2017+
/// of _soft-limit_ and number working threads at the moment
20152018
///
20162019
/// On all targets:
20172020
/// - It may overcount the amount of parallelism available when running in a VM

0 commit comments

Comments
 (0)