summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
authorakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-01-18 13:28:35 +0000
committerakr <akr@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-01-18 13:28:35 +0000
commitf962eba5f430200d42def2756ac4af2512acdfce (patch)
tree31cd5fa07ba6e31693ceb46f7d2121997cab20c4 /io.c
parent7efaa4f5d07ebc100a1bbfb34bfd9ea23a4ac2f2 (diff)
* io.c: Test O_CLOEXEC only once.
Patch by Eric Wong. [ruby-core:59419] [Feature #9328] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44640 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'io.c')
-rw-r--r--io.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/io.c b/io.c
index 6511793c55..5d66bdf4b0 100644
--- a/io.c
+++ b/io.c
@@ -228,10 +228,29 @@ rb_fd_fix_cloexec(int fd)
rb_update_max_fd(fd);
}
+/* this is only called once */
+static int
+rb_fix_detect_o_cloexec(int fd)
+{
+#ifdef O_CLOEXEC
+ int flags = fcntl(fd, F_GETFD);
+
+ if (flags == -1)
+ rb_bug("rb_fix_detect_o_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
+
+ if (flags & FD_CLOEXEC)
+ return 1;
+#endif /* fall through if O_CLOEXEC does not work: */
+ rb_maygvl_fd_fix_cloexec(fd);
+ return 0;
+}
+
int
rb_cloexec_open(const char *pathname, int flags, mode_t mode)
{
int ret;
+ static int o_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
+
#ifdef O_CLOEXEC
/* O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
flags |= O_CLOEXEC;
@@ -240,7 +259,13 @@ rb_cloexec_open(const char *pathname, int flags, mode_t mode)
#endif
ret = open(pathname, flags, mode);
if (ret == -1) return -1;
- rb_maygvl_fd_fix_cloexec(ret);
+ if (ret <= 2 || o_cloexec_state == 0) {
+ rb_maygvl_fd_fix_cloexec(ret);
+ } else if (o_cloexec_state > 0) {
+ return ret;
+ } else {
+ o_cloexec_state = rb_fix_detect_o_cloexec(ret);
+ }
return ret;
}