* ext/socket: Avoid redundant fcntl/fstat syscalls for cloexec
sockets. Patch by Eric Wong. [ruby-core:59429] [Feature #9330] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44728 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
fbf4850cab
commit
965b947fff
@ -1,3 +1,9 @@
|
|||||||
|
Tue Jan 28 23:36:01 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* ext/socket: Avoid redundant fcntl/fstat syscalls for cloexec
|
||||||
|
sockets.
|
||||||
|
Patch by Eric Wong. [ruby-core:59429] [Feature #9330]
|
||||||
|
|
||||||
Tue Jan 28 20:51:07 2014 Tanaka Akira <akr@fsij.org>
|
Tue Jan 28 20:51:07 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* process.c (READ_FROM_CHILD): Apply the last hunk of
|
* process.c (READ_FROM_CHILD): Apply the last hunk of
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
int rsock_cmsg_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
|
||||||
|
|
||||||
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
|
#if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
|
||||||
static VALUE rb_cAncillaryData;
|
static VALUE rb_cAncillaryData;
|
||||||
|
|
||||||
@ -1416,7 +1418,7 @@ discard_cmsg(struct cmsghdr *cmh, char *msg_end, int msg_peek_p)
|
|||||||
int *end = (int *)((char *)cmh + cmh->cmsg_len);
|
int *end = (int *)((char *)cmh + cmh->cmsg_len);
|
||||||
while ((char *)fdp + sizeof(int) <= (char *)end &&
|
while ((char *)fdp + sizeof(int) <= (char *)end &&
|
||||||
(char *)fdp + sizeof(int) <= msg_end) {
|
(char *)fdp + sizeof(int) <= msg_end) {
|
||||||
rb_fd_fix_cloexec(*fdp);
|
rb_update_max_fd(*fdp);
|
||||||
close(*fdp);
|
close(*fdp);
|
||||||
fdp++;
|
fdp++;
|
||||||
}
|
}
|
||||||
@ -1459,7 +1461,11 @@ make_io_for_unix_rights(VALUE ctl, struct cmsghdr *cmh, char *msg_end)
|
|||||||
VALUE io;
|
VALUE io;
|
||||||
if (fstat(fd, &stbuf) == -1)
|
if (fstat(fd, &stbuf) == -1)
|
||||||
rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
|
rb_raise(rb_eSocket, "invalid fd in SCM_RIGHTS");
|
||||||
rb_fd_fix_cloexec(fd);
|
rb_update_max_fd(fd);
|
||||||
|
if (rsock_cmsg_cloexec_state < 0)
|
||||||
|
rsock_cmsg_cloexec_state = rsock_detect_cloexec(fd);
|
||||||
|
if (rsock_cmsg_cloexec_state == 0 || fd <= 2)
|
||||||
|
rb_maygvl_fd_fix_cloexec(fd);
|
||||||
if (S_ISSOCK(stbuf.st_mode))
|
if (S_ISSOCK(stbuf.st_mode))
|
||||||
io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
|
io = rsock_init_sock(rb_obj_alloc(rb_cSocket), fd);
|
||||||
else
|
else
|
||||||
|
@ -249,24 +249,55 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
|
|||||||
return rb_assoc_new(str, addr);
|
return rb_assoc_new(str, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* returns true if SOCK_CLOEXEC is supported */
|
||||||
|
int rsock_detect_cloexec(int fd)
|
||||||
|
{
|
||||||
|
#ifdef SOCK_CLOEXEC
|
||||||
|
int flags = fcntl(fd, F_GETFD);
|
||||||
|
|
||||||
|
if (flags == -1)
|
||||||
|
rb_bug("rsock_detect_cloexec: fcntl(%d, F_GETFD) failed: %s", fd, strerror(errno));
|
||||||
|
|
||||||
|
if (flags & FD_CLOEXEC)
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rsock_socket0(int domain, int type, int proto)
|
rsock_socket0(int domain, int type, int proto)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef SOCK_CLOEXEC
|
#ifdef SOCK_CLOEXEC
|
||||||
static int try_sock_cloexec = 1;
|
static int cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
|
||||||
if (try_sock_cloexec) {
|
|
||||||
|
if (cloexec_state > 0) { /* common path, if SOCK_CLOEXEC is defined */
|
||||||
ret = socket(domain, type|SOCK_CLOEXEC, proto);
|
ret = socket(domain, type|SOCK_CLOEXEC, proto);
|
||||||
if (ret == -1 && errno == EINVAL) {
|
if (ret >= 0) {
|
||||||
|
if (ret <= 2)
|
||||||
|
goto fix_cloexec;
|
||||||
|
goto update_max_fd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (cloexec_state < 0) { /* usually runs once only for detection */
|
||||||
|
ret = socket(domain, type|SOCK_CLOEXEC, proto);
|
||||||
|
if (ret >= 0) {
|
||||||
|
cloexec_state = rsock_detect_cloexec(ret);
|
||||||
|
if (cloexec_state == 0 || ret <= 2)
|
||||||
|
goto fix_cloexec;
|
||||||
|
goto update_max_fd;
|
||||||
|
}
|
||||||
|
else if (ret == -1 && errno == EINVAL) {
|
||||||
/* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
|
/* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
|
||||||
ret = socket(domain, type, proto);
|
ret = socket(domain, type, proto);
|
||||||
if (ret != -1) {
|
if (ret != -1) {
|
||||||
try_sock_cloexec = 0;
|
cloexec_state = 0;
|
||||||
|
/* fall through to fix_cloexec */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else { /* cloexec_state == 0 */
|
||||||
ret = socket(domain, type, proto);
|
ret = socket(domain, type, proto);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -274,11 +305,12 @@ rsock_socket0(int domain, int type, int proto)
|
|||||||
#endif
|
#endif
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
fix_cloexec:
|
||||||
rb_fd_fix_cloexec(ret);
|
rb_maygvl_fd_fix_cloexec(ret);
|
||||||
|
update_max_fd:
|
||||||
|
rb_update_max_fd(ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -226,6 +226,7 @@ typedef union {
|
|||||||
#define INET_SOCKS 2
|
#define INET_SOCKS 2
|
||||||
|
|
||||||
extern int rsock_do_not_reverse_lookup;
|
extern int rsock_do_not_reverse_lookup;
|
||||||
|
extern int rsock_cmsg_cloexec_state;
|
||||||
#define FMODE_NOREVLOOKUP 0x100
|
#define FMODE_NOREVLOOKUP 0x100
|
||||||
|
|
||||||
extern VALUE rb_cBasicSocket;
|
extern VALUE rb_cBasicSocket;
|
||||||
@ -304,6 +305,7 @@ socklen_t rsock_unix_sockaddr_len(VALUE path);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int rsock_socket(int domain, int type, int proto);
|
int rsock_socket(int domain, int type, int proto);
|
||||||
|
int rsock_detect_cloexec(int fd);
|
||||||
VALUE rsock_init_sock(VALUE sock, int fd);
|
VALUE rsock_init_sock(VALUE sock, int fd);
|
||||||
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
|
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
|
||||||
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type);
|
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type);
|
||||||
|
@ -174,10 +174,24 @@ rsock_socketpair0(int domain, int type, int protocol, int sv[2])
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
#ifdef SOCK_CLOEXEC
|
#ifdef SOCK_CLOEXEC
|
||||||
static int try_sock_cloexec = 1;
|
static int cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */
|
||||||
if (try_sock_cloexec) {
|
|
||||||
|
if (cloexec_state > 0) { /* common path, if SOCK_CLOEXEC is defined */
|
||||||
ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
|
ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
|
||||||
if (ret == -1 && errno == EINVAL) {
|
if (ret == 0 && (sv[0] <= 2 || sv[1] <= 2)) {
|
||||||
|
goto fix_cloexec; /* highly unlikely */
|
||||||
|
}
|
||||||
|
goto update_max_fd;
|
||||||
|
}
|
||||||
|
else if (cloexec_state < 0) { /* usually runs once only for detection */
|
||||||
|
ret = socketpair(domain, type|SOCK_CLOEXEC, protocol, sv);
|
||||||
|
if (ret == 0) {
|
||||||
|
cloexec_state = rsock_detect_cloexec(sv[0]);
|
||||||
|
if ((cloexec_state == 0) || (sv[0] <= 2 || sv[1] <= 2))
|
||||||
|
goto fix_cloexec;
|
||||||
|
goto update_max_fd;
|
||||||
|
}
|
||||||
|
else if (ret == -1 && errno == EINVAL) {
|
||||||
/* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
|
/* SOCK_CLOEXEC is available since Linux 2.6.27. Linux 2.6.18 fails with EINVAL */
|
||||||
ret = socketpair(domain, type, protocol, sv);
|
ret = socketpair(domain, type, protocol, sv);
|
||||||
if (ret != -1) {
|
if (ret != -1) {
|
||||||
@ -185,11 +199,11 @@ rsock_socketpair0(int domain, int type, int protocol, int sv[2])
|
|||||||
* So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC.
|
* So disable SOCK_CLOEXEC only if socketpair() succeeds without SOCK_CLOEXEC.
|
||||||
* Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL.
|
* Ex. Socket.pair(:UNIX, 0xff) fails with EINVAL.
|
||||||
*/
|
*/
|
||||||
try_sock_cloexec = 0;
|
cloexec_state = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else { /* cloexec_state == 0 */
|
||||||
ret = socketpair(domain, type, protocol, sv);
|
ret = socketpair(domain, type, protocol, sv);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -200,8 +214,13 @@ rsock_socketpair0(int domain, int type, int protocol, int sv[2])
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_fd_fix_cloexec(sv[0]);
|
fix_cloexec:
|
||||||
rb_fd_fix_cloexec(sv[1]);
|
rb_maygvl_fd_fix_cloexec(sv[0]);
|
||||||
|
rb_maygvl_fd_fix_cloexec(sv[1]);
|
||||||
|
|
||||||
|
update_max_fd:
|
||||||
|
rb_update_max_fd(sv[0]);
|
||||||
|
rb_update_max_fd(sv[1]);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -267,8 +286,6 @@ rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass)
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
rb_sys_fail("socketpair(2)");
|
rb_sys_fail("socketpair(2)");
|
||||||
}
|
}
|
||||||
rb_fd_fix_cloexec(sp[0]);
|
|
||||||
rb_fd_fix_cloexec(sp[1]);
|
|
||||||
|
|
||||||
s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
|
s1 = rsock_init_sock(rb_obj_alloc(klass), sp[0]);
|
||||||
s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
|
s2 = rsock_init_sock(rb_obj_alloc(klass), sp[1]);
|
||||||
|
@ -389,7 +389,13 @@ unix_recv_io(int argc, VALUE *argv, VALUE sock)
|
|||||||
#if FD_PASSING_BY_MSG_CONTROL
|
#if FD_PASSING_BY_MSG_CONTROL
|
||||||
memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
|
memcpy(&fd, CMSG_DATA(&cmsg.hdr), sizeof(int));
|
||||||
#endif
|
#endif
|
||||||
rb_fd_fix_cloexec(fd);
|
|
||||||
|
rb_update_max_fd(fd);
|
||||||
|
|
||||||
|
if (rsock_cmsg_cloexec_state < 0)
|
||||||
|
rsock_cmsg_cloexec_state = rsock_detect_cloexec(fd);
|
||||||
|
if (rsock_cmsg_cloexec_state == 0 || fd <= 2)
|
||||||
|
rb_maygvl_fd_fix_cloexec(fd);
|
||||||
|
|
||||||
if (klass == Qnil)
|
if (klass == Qnil)
|
||||||
return INT2FIX(fd);
|
return INT2FIX(fd);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user