Skip to content

Commit cc35433

Browse files
committed
std: ignore EINTR error during syscalls if possible
1 parent 9ca7738 commit cc35433

File tree

9 files changed

+163
-20
lines changed

9 files changed

+163
-20
lines changed

std/internal/os/proc_posix.jule

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2025 The Jule Programming Language.
2+
// Use of this source code is governed by a BSD 3-Clause
3+
// license that can be found in the LICENSE file.
4+
5+
#build unix || windows
6+
7+
use "std/sys"
8+
9+
// Implementation adopted from the Go programming language.
10+
//
11+
// It makes a function call and repeats it if it returns an
12+
// EINTR error. This appears to be required even though we install all
13+
// signal handlers with SA_RESTART: see Go's #22838, #38033, #38836, #40846.
14+
// Also #20400 and #36644 are issues in which a signal handler is
15+
// installed without setting SA_RESTART. None of these are the common case,
16+
// but there are enough of them that it seems that we can't avoid
17+
// an EINTR loop.
18+
fn ignoringEINTR(f: fn()!)! {
19+
for {
20+
f() else {
21+
if error == sys::EINTR {
22+
continue
23+
}
24+
error(error)
25+
}
26+
break
27+
}
28+
}
29+
30+
// Implementation adopted from the Go programming language.
31+
//
32+
// This is ignoringEINTR, but returning an additional value.
33+
fn ignoringEINTR2[T](f: fn()!: T)!: T {
34+
for {
35+
mut v := f() else {
36+
if error == sys::EINTR {
37+
continue
38+
}
39+
error(error)
40+
}
41+
ret v
42+
}
43+
}

std/internal/os/proc_unix.jule

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ use "std/unsafe"
77

88
fn Getwd()!: str {
99
let mut buf: [sys::PATH_MAX]byte
10-
n := sys::Getcwd(unsafe::Slice(&buf[0], len(buf), len(buf))) else { error(error) }
10+
mut sbuf := unsafe::Slice(&buf[0], len(buf), len(buf))
11+
n := ignoringEINTR2(fn()!: int {
12+
ret sys::Getcwd(sbuf) else { error(error) }
13+
}) else { error(error) }
1114
ret unsafe::StrFromBytes(buf[:n])
1215
}
1316

std/internal/poll/fd_darwin.jule renamed to std/internal/poll/fd_fsync_darwin.jule

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@ impl FD {
99
// on OS X, SYS_FSYNC doesn't fully flush contents to disk.
1010
// See the man page for fsync on OS X.
1111
fn Fsync(mut self)! {
12-
sys::Fcntl(int(self.File), sys::F_FULLFSYNC, 0) else {
13-
// There are scenarios such as SMB mounts where fcntl will fail
14-
// with ENOTSUP. In those cases fallback to fsync.
15-
if error != sys::ENOTSUP {
16-
error(error)
12+
fd := int(self.File)
13+
ignoringEINTR(fn()! {
14+
sys::Fcntl(fd, sys::F_FULLFSYNC, 0) else {
15+
// There are scenarios such as SMB mounts where fcntl will fail
16+
// with ENOTSUP. In those cases fallback to fsync.
17+
if error != sys::ENOTSUP {
18+
error(error)
19+
}
20+
sys::Fsync(fd) else { error(error) }
1721
}
18-
sys::Fsync(int(self.File)) else { error(error) }
19-
}
22+
}) else { error(error) }
2023
}
2124
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2025 The Jule Programming Language.
2+
// Use of this source code is governed by a BSD 3-Clause
3+
// license that can be found in the LICENSE file.
4+
5+
#build linux
6+
7+
use "std/sys"
8+
9+
impl FD {
10+
// Wraps sys::Fsync.
11+
fn Fsync(mut self)! {
12+
fd := int(self.File)
13+
ignoringEINTR(fn()! {
14+
sys::Fsync(fd) else { error(error) }
15+
}) else { error(error) }
16+
}
17+
}

std/internal/poll/fd_posix.jule

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,42 @@
22
// Use of this source code is governed by a BSD 3-Clause
33
// license that can be found in the LICENSE file.
44

5-
#build linux
5+
#build unix || windows
66

77
use "std/sys"
88

9-
impl FD {
10-
// Wraps sys::Fsync.
11-
fn Fsync(mut self)! {
12-
sys::Fsync(int(self.File)) else { error(error) }
9+
// Implementation adopted from the Go programming language.
10+
//
11+
// It makes a function call and repeats it if it returns an
12+
// EINTR error. This appears to be required even though we install all
13+
// signal handlers with SA_RESTART: see Go's #22838, #38033, #38836, #40846.
14+
// Also #20400 and #36644 are issues in which a signal handler is
15+
// installed without setting SA_RESTART. None of these are the common case,
16+
// but there are enough of them that it seems that we can't avoid
17+
// an EINTR loop.
18+
fn ignoringEINTR(f: fn()!)! {
19+
for {
20+
f() else {
21+
if error == sys::EINTR {
22+
continue
23+
}
24+
error(error)
25+
}
26+
break
27+
}
28+
}
29+
30+
// Implementation adopted from the Go programming language.
31+
//
32+
// This is ignoringEINTR, but returning an additional value.
33+
fn ignoringEINTR2[T](f: fn()!: T)!: T {
34+
for {
35+
mut v := f() else {
36+
if error == sys::EINTR {
37+
continue
38+
}
39+
error(error)
40+
}
41+
ret v
1342
}
1443
}

std/os/cmd_unix.jule

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,12 @@ impl Cmd {
108108
}
109109

110110
fn wait(self)!: int {
111-
mut stat := i32(0)
112-
sys::Waitpid(self.attrs.pid, stat, 0) else { error(error) }
111+
pid := self.attrs.pid
112+
stat := ignoringEINTR2(fn()!: i32 {
113+
mut stat := i32(0)
114+
sys::Waitpid(pid, stat, 0) else { error(error) }
115+
ret stat
116+
}) else { error(error) }
113117
self.attrs.pid = invalidPid
114118
ret cpp.WEXITSTATUS(stat)
115119
}

std/os/dir_unix.jule

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ fn mkdir(path: str)! {
3232
// NOTICE
3333
// Also can has EMLINK error-code.
3434
// Make sure this situation should documented or not.
35-
sys::Mkdir(path, 0700) else { error(error) }
35+
ignoringEINTR(fn()! {
36+
sys::Mkdir(path, 0700) else { error(error) }
37+
}) else { error(error) }
3638
}
3739

3840
fn rmdir(path: str)! {

std/os/file_posix.jule

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,40 @@ fn syscallMode(i: FileMode): (o: u32) {
1919
o |= sys::S_ISVTX
2020
}
2121
ret
22+
}
23+
24+
// Implementation adopted from the Go programming language.
25+
//
26+
// It makes a function call and repeats it if it returns an
27+
// EINTR error. This appears to be required even though we install all
28+
// signal handlers with SA_RESTART: see Go's #22838, #38033, #38836, #40846.
29+
// Also #20400 and #36644 are issues in which a signal handler is
30+
// installed without setting SA_RESTART. None of these are the common case,
31+
// but there are enough of them that it seems that we can't avoid
32+
// an EINTR loop.
33+
fn ignoringEINTR(f: fn()!)! {
34+
for {
35+
f() else {
36+
if error == sys::EINTR {
37+
continue
38+
}
39+
error(error)
40+
}
41+
break
42+
}
43+
}
44+
45+
// Implementation adopted from the Go programming language.
46+
//
47+
// This is ignoringEINTR, but returning an additional value.
48+
fn ignoringEINTR2[T](f: fn()!: T)!: T {
49+
for {
50+
mut v := f() else {
51+
if error == sys::EINTR {
52+
continue
53+
}
54+
error(error)
55+
}
56+
ret v
57+
}
2258
}

std/os/stat_unix.jule

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@ fn stat(path: str)!: FileInfo {
88
if path == "" {
99
error(sys::ENOENT)
1010
}
11-
mut handle := sys::SysStat{}
12-
sys::Stat(path, handle) else { error(error) }
11+
handle := ignoringEINTR2(fn()!: sys::SysStat {
12+
mut handle := sys::SysStat{}
13+
sys::Stat(path, handle) else { error(error) }
14+
ret handle
15+
}) else { error(error) }
1316
mut stat := FileInfo{}
1417
fillFileStatFromSys(stat, handle)
1518
stat.sys = handle
@@ -20,8 +23,11 @@ fn lstat(path: str)!: FileInfo {
2023
if path == "" {
2124
error(sys::ENOENT)
2225
}
23-
mut handle := sys::SysStat{}
24-
sys::Lstat(path, handle) else { error(error) }
26+
handle := ignoringEINTR2(fn()!: sys::SysStat {
27+
mut handle := sys::SysStat{}
28+
sys::Lstat(path, handle) else { error(error) }
29+
ret handle
30+
}) else { error(error) }
2531
mut stat := FileInfo{}
2632
fillFileStatFromSys(stat, handle)
2733
stat.sys = handle

0 commit comments

Comments
 (0)