Skip to content

Commit 64b98a4

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 64b98a4

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

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

Lines changed: 58 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,42 @@ fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_W
405405
result
406406
}
407407

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

460+
#[allow(unused_assignments)]
461+
#[allow(unused_mut)]
462+
let mut ulimit = libc::rlim_t::MAX;
463+
424464
#[cfg(any(target_os = "android", target_os = "linux"))]
425465
{
426466
quota = cgroups::quota().max(1);
@@ -439,14 +479,30 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
439479
}
440480
}
441481
}
482+
483+
let mut r: libc::rlimit = unsafe { mem::zeroed() };
484+
unsafe {
485+
if libc::getrlimit(libc::RLIMIT_NPROC, &mut r) == 0 {
486+
match r.rlim_cur {
487+
libc::RLIM_INFINITY => ulimit = libc::rlim_t::MAX,
488+
soft_limit => {
489+
ulimit = match count_user_threads() {
490+
Ok(t) => if soft_limit > t as libc::rlim_t {soft_limit - t as libc::rlim_t} else { 1 },
491+
_ => 1
492+
}
493+
}
494+
}
495+
}
496+
}
442497
}
498+
443499
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
444500
-1 => Err(io::Error::last_os_error()),
445501
0 => Err(io::Error::UNKNOWN_THREAD_COUNT),
446502
cpus => {
447503
let count = cpus as usize;
448504
// Cover the unusual situation where we were able to get the quota but not the affinity mask
449-
let count = count.min(quota);
505+
let count = count.min(quota.min(ulimit.try_into().unwrap_or(usize::MAX)));
450506
Ok(unsafe { NonZero::new_unchecked(count) })
451507
}
452508
}

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)