Skip to content

Commit d3465a8

Browse files
committed
keep using poll as fast path and only use fcntl as fallback
this minimizes the amount of syscalls performed during startup
1 parent e0a53ed commit d3465a8

File tree

2 files changed

+65
-19
lines changed

2 files changed

+65
-19
lines changed

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@
239239
#![feature(dropck_eyepatch)]
240240
#![feature(exhaustive_patterns)]
241241
#![feature(intra_doc_pointers)]
242+
#![feature(label_break_value)]
242243
#![feature(lang_items)]
243244
#![feature(let_chains)]
244245
#![feature(linkage)]

library/std/src/sys/unix/mod.rs

+64-19
Original file line numberDiff line numberDiff line change
@@ -67,25 +67,70 @@ pub unsafe fn init(argc: isize, argv: *const *const u8) {
6767
args::init(argc, argv);
6868

6969
unsafe fn sanitize_standard_fds() {
70-
cfg_if::cfg_if! {
71-
if #[cfg(not(any(
72-
// The standard fds are always available in Miri.
73-
miri,
74-
target_os = "emscripten",
75-
target_os = "fuchsia",
76-
target_os = "vxworks",
77-
target_os = "l4re",
78-
)))] {
79-
use crate::sys::os::errno;
80-
for fd in 0..3 {
81-
if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
82-
if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
83-
// If the stream is closed but we failed to reopen it, abort the
84-
// process. Otherwise we wouldn't preserve the safety of
85-
// operations on the corresponding Rust object Stdin, Stdout, or
86-
// Stderr.
87-
libc::abort();
88-
}
70+
// fast path with a single syscall for systems with poll()
71+
#[cfg(not(any(
72+
miri,
73+
target_os = "emscripten",
74+
target_os = "fuchsia",
75+
target_os = "vxworks",
76+
// The poll on Darwin doesn't set POLLNVAL for closed fds.
77+
target_os = "macos",
78+
target_os = "ios",
79+
target_os = "redox",
80+
target_os = "l4re",
81+
)))]
82+
'poll: {
83+
use crate::sys::os::errno;
84+
let pfds: &mut [_] = &mut [
85+
libc::pollfd { fd: 0, events: 0, revents: 0 },
86+
libc::pollfd { fd: 1, events: 0, revents: 0 },
87+
libc::pollfd { fd: 2, events: 0, revents: 0 },
88+
];
89+
90+
while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 {
91+
if errno() == libc::EINTR {
92+
continue;
93+
}
94+
if errno() == libc::EINVAL {
95+
// RLIMIT_NOFILE may be preventing use of poll()
96+
break 'poll;
97+
}
98+
libc::abort();
99+
}
100+
for pfd in pfds {
101+
if pfd.revents & libc::POLLNVAL == 0 {
102+
continue;
103+
}
104+
if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
105+
// If the stream is closed but we failed to reopen it, abort the
106+
// process. Otherwise we wouldn't preserve the safety of
107+
// operations on the corresponding Rust object Stdin, Stdout, or
108+
// Stderr.
109+
libc::abort();
110+
}
111+
}
112+
return;
113+
}
114+
115+
// fallback in case poll isn't available or limited by RLIMIT_NOFILE
116+
#[cfg(not(any(
117+
// The standard fds are always available in Miri.
118+
miri,
119+
target_os = "emscripten",
120+
target_os = "fuchsia",
121+
target_os = "vxworks",
122+
target_os = "l4re",
123+
)))]
124+
{
125+
use crate::sys::os::errno;
126+
for fd in 0..3 {
127+
if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF {
128+
if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 {
129+
// If the stream is closed but we failed to reopen it, abort the
130+
// process. Otherwise we wouldn't preserve the safety of
131+
// operations on the corresponding Rust object Stdin, Stdout, or
132+
// Stderr.
133+
libc::abort();
89134
}
90135
}
91136
}

0 commit comments

Comments
 (0)