* [PATCH] socket: Socket#connect_nonblock avoids arg parsing with C API
@ 2015-11-12 21:21 Eric Wong
0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2015-11-12 21:21 UTC (permalink / raw)
To: spew
* 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
---
benchmark/bm_connect_nonblock.rb | 18 ++++++++++++
ext/socket/lib/socket.rb | 47 ++++++++++++++++++++++++++++++
ext/socket/socket.c | 62 ++++++----------------------------------
3 files changed, 74 insertions(+), 53 deletions(-)
create mode 100644 benchmark/bm_connect_nonblock.rb
diff --git a/benchmark/bm_connect_nonblock.rb b/benchmark/bm_connect_nonblock.rb
new file mode 100644
index 0000000..8a4428c
--- /dev/null
+++ b/benchmark/bm_connect_nonblock.rb
@@ -0,0 +1,18 @@
+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
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 915eb96..1f55323 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -978,6 +978,53 @@ class Socket < BasicSocket
}
end
+ # 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
+ def connect_nonblock(addr, exception: true)
+ __connect_nonblock(addr, exception)
+ end
end
class UDPSocket < IPSocket
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 1a3320d..58776bd 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -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);
--
EW
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2015-11-12 21:21 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-12 21:21 [PATCH] socket: Socket#connect_nonblock avoids arg parsing with C API Eric Wong
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).