diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-16 23:34:37 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-16 23:34:37 +0000 |
commit | bb6dfab2a8a798f68c7935596ec03855106d7fd4 (patch) | |
tree | 55697363b52d70a126ee6e6d1148cd5752674bef /ext/socket/socket.c | |
parent | b272f94f9e5afc9070c3fcc170da7d2e1aebe99a (diff) |
socket: Socket#connect_nonblock avoids arg parsing with C API
* ext/socket/socket.c (sock_connect_nonblock):
avoid argument parsing in C.
[ruby-core:71439] [Feature #11339]
* ext/socket/lib/socket.rb (Socket#connect_nonblock):
new wrapper for private method, move RDoc
target 0: a (ruby 2.3.0dev (2015-11-12 trunk 52540) [x86_64-linux])
target 1: b (ruby 2.3.0dev (2015-11-12 avoid-kwarg-capi 52540) [x86_64-linux]
-----------------------------------------------------------
connect_nonblock
require 'tempfile'
require 'socket'
require 'io/wait'
nr = 500000
Tempfile.create(%w(connect_nonblock .sock)) do |tmp|
path = tmp.path
File.unlink(path)
s = UNIXServer.new(path)
addr = Socket.sockaddr_un(path).freeze
nr.times do
c = Socket.new(Socket::AF_UNIX, Socket::SOCK_STREAM)
while c.connect_nonblock(addr, exception: false) == :wait_writable
c.wait_writable
end
s.accept.close
c.close
end
end
-----------------------------------------------------------
raw data:
[["connect_nonblock",
[[4.014209181070328,
3.8479955345392227,
3.981342639774084,
4.471840236335993,
3.7867715656757355],
[3.639054525643587,
3.58337214961648,
3.525284394621849,
3.52646067738533,
3.511393066495657]]]]
Elapsed time: 37.889623996 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
connect_nonblock 3.787 3.511
Speedup ratio: compare with the result of `a' (greater is better)
name b
connect_nonblock 1.078
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52600 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext/socket/socket.c')
-rw-r--r-- | ext/socket/socket.c | 65 |
1 files changed, 10 insertions, 55 deletions
diff --git a/ext/socket/socket.c b/ext/socket/socket.c index 1a3320dbe5..a410625537 100644 --- a/ext/socket/socket.c +++ b/ext/socket/socket.c @@ -10,7 +10,7 @@ #include "rubysocket.h" -static VALUE sym_exception, sym_wait_writable; +static VALUE sym_wait_writable; static VALUE sock_s_unpack_sockaddr_in(VALUE, VALUE); @@ -439,62 +439,14 @@ sock_connect(VALUE sock, VALUE addr) return INT2FIX(n); } -/* - * call-seq: - * socket.connect_nonblock(remote_sockaddr, [options]) => 0 - * - * Requests a connection to be made on the given +remote_sockaddr+ after - * O_NONBLOCK is set for the underlying file descriptor. - * Returns 0 if successful, otherwise an exception is raised. - * - * === Parameter - * * +remote_sockaddr+ - the +struct+ sockaddr contained in a string or Addrinfo object - * - * === Example: - * # Pull down Google's web page - * require 'socket' - * include Socket::Constants - * socket = Socket.new(AF_INET, SOCK_STREAM, 0) - * sockaddr = Socket.sockaddr_in(80, 'www.google.com') - * begin # emulate blocking connect - * socket.connect_nonblock(sockaddr) - * rescue IO::WaitWritable - * IO.select(nil, [socket]) # wait 3-way handshake completion - * begin - * socket.connect_nonblock(sockaddr) # check connection failure - * rescue Errno::EISCONN - * end - * end - * socket.write("GET / HTTP/1.0\r\n\r\n") - * results = socket.read - * - * Refer to Socket#connect for the exceptions that may be thrown if the call - * to _connect_nonblock_ fails. - * - * Socket#connect_nonblock may raise any error corresponding to connect(2) failure, - * including Errno::EINPROGRESS. - * - * If the exception is Errno::EINPROGRESS, - * it is extended by IO::WaitWritable. - * So IO::WaitWritable can be used to rescue the exceptions for retrying connect_nonblock. - * - * By specifying `exception: false`, the options hash allows you to indicate - * that connect_nonblock should not raise an IO::WaitWritable exception, but - * return the symbol :wait_writable instead. - * - * === See - * * Socket#connect - */ +/* :nodoc: */ static VALUE -sock_connect_nonblock(int argc, VALUE *argv, VALUE sock) +sock_connect_nonblock(VALUE sock, VALUE addr, VALUE ex) { - VALUE addr; - VALUE opts = Qnil; VALUE rai; rb_io_t *fptr; int n; - rb_scan_args(argc, argv, "1:", &addr, &opts); SockAddrStringValueWithAddrinfo(addr, rai); addr = rb_str_new4(addr); GetOpenFile(sock, fptr); @@ -502,13 +454,13 @@ sock_connect_nonblock(int argc, VALUE *argv, VALUE sock) n = connect(fptr->fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr)); if (n < 0) { if (errno == EINPROGRESS) { - if (rsock_opt_false_p(opts, sym_exception)) { + if (ex == Qfalse) { return sym_wait_writable; } rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "connect(2) would block"); } if (errno == EISCONN) { - if (rsock_opt_false_p(opts, sym_exception)) { + if (ex == Qfalse) { return INT2FIX(0); } } @@ -2113,7 +2065,11 @@ Init_socket(void) rb_define_method(rb_cSocket, "initialize", sock_initialize, -1); rb_define_method(rb_cSocket, "connect", sock_connect, 1); - rb_define_method(rb_cSocket, "connect_nonblock", sock_connect_nonblock, -1); + + /* for ext/socket/lib/socket.rb use only: */ + rb_define_private_method(rb_cSocket, + "__connect_nonblock", sock_connect_nonblock, 2); + rb_define_method(rb_cSocket, "bind", sock_bind, 1); rb_define_method(rb_cSocket, "listen", rsock_sock_listen, 1); rb_define_method(rb_cSocket, "accept", sock_accept, 0); @@ -2147,6 +2103,5 @@ Init_socket(void) rb_define_singleton_method(rb_cSocket, "ip_address_list", socket_s_ip_address_list, 0); #undef rb_intern - sym_exception = ID2SYM(rb_intern("exception")); sym_wait_writable = ID2SYM(rb_intern("wait_writable")); } |