Skip to content

Commit 24e029f

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 24e029f

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

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

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
use crate::ffi::CStr;
2+
#[cfg(any(target_os = "android", target_os = "linux"))]
3+
use crate::fs;
24
use crate::mem::{self, ManuallyDrop};
35
use crate::num::NonZero;
46
#[cfg(all(target_os = "linux", target_env = "gnu"))]
@@ -405,6 +407,42 @@ fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_W
405407
result
406408
}
407409

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

462+
#[allow(unused_assignments)]
463+
#[allow(unused_mut)]
464+
let mut ulimit = libc::rlim_t::MAX;
465+
424466
#[cfg(any(target_os = "android", target_os = "linux"))]
425467
{
426468
quota = cgroups::quota().max(1);
@@ -439,14 +481,30 @@ pub fn available_parallelism() -> io::Result<NonZero<usize>> {
439481
}
440482
}
441483
}
484+
485+
let mut r: libc::rlimit = unsafe { mem::zeroed() };
486+
unsafe {
487+
if libc::getrlimit(libc::RLIMIT_NPROC, &mut r) == 0 {
488+
match r.rlim_cur {
489+
libc::RLIM_INFINITY => ulimit = libc::rlim_t::MAX,
490+
soft_limit => {
491+
ulimit = match count_user_threads() {
492+
Ok(t) => if soft_limit > t as libc::rlim_t {soft_limit - t as libc::rlim_t} else { 1 },
493+
_ => 1
494+
}
495+
}
496+
}
497+
}
498+
}
442499
}
500+
443501
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
444502
-1 => Err(io::Error::last_os_error()),
445503
0 => Err(io::Error::UNKNOWN_THREAD_COUNT),
446504
cpus => {
447505
let count = cpus as usize;
448506
// Cover the unusual situation where we were able to get the quota but not the affinity mask
449-
let count = count.min(quota);
507+
let count = count.min(quota.min(ulimit.try_into().unwrap_or(usize::MAX)));
450508
Ok(unsafe { NonZero::new_unchecked(count) })
451509
}
452510
}

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)