[ruby-core:118996] [Ruby master Bug#20708] EINTR while opening fifo isn't retried

Issue #20708 has been reported by martin.dorey@hds.com (Martin Dorey). ---------------------------------------- Bug #20708: EINTR while opening fifo isn't retried https://bugs.ruby-lang.org/issues/20708 * Author: martin.dorey@hds.com (Martin Dorey) * Status: Open * ruby -v: ruby 3.4.0dev (2024-08-30T20:36:28Z master eef2121cf3) [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I don't think this should fail: ``` martind@stormy:~/download/ruby$ rm -f /tmp/badger && mkfifo /tmp/badger && timeout 2 ./ruby --disable-gems -we 'fork() {}; IO.read("/tmp/badger")' -e:1:in 'IO.read': Interrupted system call @ rb_sysopen - /tmp/badger (Errno::EINTR) from -e:1:in '<main>' martind@stormy:~/download/ruby$ ``` The behavior changed with 2.6.0-preview3 compared to 2.6.0-preview2: ``` martind@stormy:~/download/ruby-2.6.0-preview2$ rm -f /tmp/badger && mkfifo /tmp/badger && timeout 2 ./ruby --disable-gems -we 'fork() {}; IO.read("/tmp/badger")' martind@stormy:~/download/ruby-2.6.0-preview3$ rm -f /tmp/badger && mkfifo /tmp/badger && timeout 2 ./ruby --disable-gems -we 'fork() {}; IO.read("/tmp/badger")' Traceback (most recent call last): 1: from -e:1:in `<main>' -e:1:in `read': Interrupted system call @ rb_sysopen - /tmp/badger (Errno::EINTR) martind@stormy:~/download/ruby-2.6.0-preview3$ ``` I don't know what the consequences would be, so I don't mean this as a serious suggestion: ``` martind@stormy:~/download/ruby$ git diff diff --git a/io.c b/io.c index 54b60b7357..590e8d11d7 100644 --- a/io.c +++ b/io.c @@ -6956,7 +6956,10 @@ sysopen_func(void *ptr) static inline int rb_sysopen_internal(struct sysopen_struct *data) { - int fd = IO_WITHOUT_GVL_INT(sysopen_func, data); + int fd; + do { + fd = IO_WITHOUT_GVL_INT(sysopen_func, data); + } while (fd < 0 && errno == EINTR); if (0 <= fd) rb_update_max_fd(fd); return fd; martind@stormy:~/download/ruby$ ``` ... but it fixes this particular test case, for me, with today's Ruby from github. There were negligible differences between 2.6.0-preview{2,3} in io.c but the SIGCHLD handling was changed. The test case is reliable for me on at least: Linux stormy 4.19.0-26-amd64 #1 SMP Debian 4.19.304-1 (2024-01-09) x86_64 GNU/Linux Linux moritz 5.10.0-14-amd64 #1 SMP Debian 5.10.113-1 (2022-04-29) x86_64 GNU/Linux I hope it's independent of the kernel, as: https://man7.org/linux/man-pages/man7/signal.7.html ... teaches:
otherwise the call fails with the error EINTR: ... • open(2), if it can block (e.g., when opening a FIFO; see fifo(7)).

Issue #20708 has been updated by nobu (Nobuyoshi Nakada). https://github.com/ruby/ruby/pull/11537 ---------------------------------------- Bug #20708: EINTR while opening fifo isn't retried https://bugs.ruby-lang.org/issues/20708#change-109609 * Author: martin.dorey@hds.com (Martin Dorey) * Status: Open * ruby -v: ruby 3.4.0dev (2024-08-30T20:36:28Z master eef2121cf3) [x86_64-linux] * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I don't think this should fail: ``` martind@stormy:~/download/ruby$ rm -f /tmp/badger && mkfifo /tmp/badger && timeout 2 ./ruby --disable-gems -we 'fork() {}; IO.read("/tmp/badger")' -e:1:in 'IO.read': Interrupted system call @ rb_sysopen - /tmp/badger (Errno::EINTR) from -e:1:in '<main>' martind@stormy:~/download/ruby$ ``` The behavior changed with 2.6.0-preview3 compared to 2.6.0-preview2: ``` martind@stormy:~/download/ruby-2.6.0-preview2$ rm -f /tmp/badger && mkfifo /tmp/badger && timeout 2 ./ruby --disable-gems -we 'fork() {}; IO.read("/tmp/badger")' martind@stormy:~/download/ruby-2.6.0-preview3$ rm -f /tmp/badger && mkfifo /tmp/badger && timeout 2 ./ruby --disable-gems -we 'fork() {}; IO.read("/tmp/badger")' Traceback (most recent call last): 1: from -e:1:in `<main>' -e:1:in `read': Interrupted system call @ rb_sysopen - /tmp/badger (Errno::EINTR) martind@stormy:~/download/ruby-2.6.0-preview3$ ``` I don't know what the consequences would be, so I don't mean this as a serious suggestion: ``` martind@stormy:~/download/ruby$ git diff diff --git a/io.c b/io.c index 54b60b7357..590e8d11d7 100644 --- a/io.c +++ b/io.c @@ -6956,7 +6956,10 @@ sysopen_func(void *ptr) static inline int rb_sysopen_internal(struct sysopen_struct *data) { - int fd = IO_WITHOUT_GVL_INT(sysopen_func, data); + int fd; + do { + fd = IO_WITHOUT_GVL_INT(sysopen_func, data); + } while (fd < 0 && errno == EINTR); if (0 <= fd) rb_update_max_fd(fd); return fd; martind@stormy:~/download/ruby$ ``` ... but it fixes this particular test case, for me, with today's Ruby from github. There were negligible differences between 2.6.0-preview{2,3} in io.c but the SIGCHLD handling was changed. The test case is reliable for me on at least: Linux stormy 4.19.0-26-amd64 #1 SMP Debian 4.19.304-1 (2024-01-09) x86_64 GNU/Linux Linux moritz 5.10.0-14-amd64 #1 SMP Debian 5.10.113-1 (2022-04-29) x86_64 GNU/Linux I hope it's independent of the kernel, as: https://man7.org/linux/man-pages/man7/signal.7.html ... teaches:
otherwise the call fails with the error EINTR: ... • open(2), if it can block (e.g., when opening a FIFO; see fifo(7)).
participants (2)
-
martin.dorey@hds.com (Martin Dorey)
-
nobu (Nobuyoshi Nakada)