dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH] socket: avoid arg parsing in rsock_s_recvfrom_nonblock
@ 2015-11-12  9:41 Eric Wong
  0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2015-11-12  9:41 UTC (permalink / raw)
  To: spew

* ext/socket/init.c (rsock_s_recvfrom_nonblock):
  avoid arg parsing with C API
  [ruby-core:71439] [Feature #11339]
* ext/socket/basicsocket.c (bsock_recv_nonblock):
  adjust for above change, make private
* ext/socket/socket.c (sock_recvfrom_nonblock): ditto
* ext/socket/udpsocket.c (udp_recvfrom_nonblock): ditto
* ext/socket/lib/socket.rb (BasicSocket#recv_nonblock):
  new wrapper for private method, move RDoc
  (Socket#recvfrom_nonblock): ditto
  (UDPSocket#recvfrom_nonblock): ditto
---
 benchmark/bm_recv_nonblock.rb |  11 +++
 ext/socket/basicsocket.c      |  60 ++-------------
 ext/socket/init.c             |  13 +---
 ext/socket/lib/socket.rb      | 171 ++++++++++++++++++++++++++++++++++++++++++
 ext/socket/rubysocket.h       |   3 +-
 ext/socket/socket.c           |  72 ++----------------
 ext/socket/udpsocket.c        |  63 ++--------------
 7 files changed, 210 insertions(+), 183 deletions(-)
 create mode 100644 benchmark/bm_recv_nonblock.rb

diff --git a/benchmark/bm_recv_nonblock.rb b/benchmark/bm_recv_nonblock.rb
new file mode 100644
index 0000000..4d68e93
--- /dev/null
+++ b/benchmark/bm_recv_nonblock.rb
@@ -0,0 +1,11 @@
+require 'socket'
+nr = 1000000
+msg = 'hello world'
+buf = ''
+size = msg.bytesize
+UNIXSocket.pair(:SEQPACKET) do |a, b|
+  nr.times do
+    a.sendmsg(msg)
+    b.recv_nonblock(size, 0, buf, exception: false)
+  end
+end
diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c
index e5597f0..6bf10e8 100644
--- a/ext/socket/basicsocket.c
+++ b/ext/socket/basicsocket.c
@@ -643,59 +643,11 @@ bsock_recv(int argc, VALUE *argv, VALUE sock)
     return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
 }
 
-/*
- * call-seq:
- * 	basicsocket.recv_nonblock(maxlen [, flags [, options ]) => mesg
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The result, _mesg_, is the data received.
- *
- * When recvfrom(2) returns 0, Socket#recv_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- * * +options+ - keyword hash, supporting `exception: false`
- *
- * === Example
- * 	serv = TCPServer.new("127.0.0.1", 0)
- * 	af, port, host, addr = serv.addr
- * 	c = TCPSocket.new(addr, port)
- * 	s = serv.accept
- * 	c.send "aaa", 0
- * 	begin # emulate blocking recv.
- * 	  p s.recv_nonblock(10) #=> "aaa"
- * 	rescue IO::WaitReadable
- * 	  IO.select([s])
- * 	  retry
- * 	end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recv_nonblock_ fails.
- *
- * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that recv_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- *
- * === See
- * * Socket#recvfrom
- */
-
+/* :nodoc: */
 static VALUE
-bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
+bsock_recv_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
 {
-    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
+    return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_RECV);
 }
 
 /*
@@ -764,10 +716,14 @@ rsock_init_basicsocket(void)
     rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
     rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
     rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
-    rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
+
     rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
     rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
 
+    /* for ext/socket/lib/socket.rb use only: */
+    rb_define_private_method(rb_cBasicSocket,
+			     "__recv_nonblock", bsock_recv_nonblock, 4);
+
     rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
     rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
     rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 1710129..350ba65 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -200,24 +200,19 @@ rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
 }
 
 VALUE
-rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
+rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+			  VALUE ex, enum sock_recv_type from)
 {
     rb_io_t *fptr;
-    VALUE str;
     union_sockaddr buf;
     socklen_t alen = (socklen_t)sizeof buf;
-    VALUE len, flg;
     long buflen;
     long slen;
     int fd, flags;
     VALUE addr = Qnil;
-    VALUE opts = Qnil;
     socklen_t len0;
 
-    rb_scan_args(argc, argv, "12:", &len, &flg, &str, &opts);
-
-    if (flg == Qnil) flags = 0;
-    else             flags = NUM2INT(flg);
+    flags = NUM2INT(flg);
     buflen = NUM2INT(len);
     str = rsock_strbuf(str, buflen);
 
@@ -249,7 +244,7 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
 	  case EWOULDBLOCK:
 #endif
-            if (rsock_opt_false_p(opts, sym_exception))
+            if (ex == Qfalse)
 		return sym_wait_readable;
             rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
 	}
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 7c66e8f..915eb96 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -272,6 +272,56 @@ class BasicSocket < IO
     end
     addr
   end
+
+  # call-seq:
+  # 	basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
+  #
+  # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+  # O_NONBLOCK is set for the underlying file descriptor.
+  # _flags_ is zero or more of the +MSG_+ options.
+  # The result, _mesg_, is the data received.
+  #
+  # When recvfrom(2) returns 0, Socket#recv_nonblock returns
+  # an empty string as data.
+  # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+  #
+  # === Parameters
+  # * +maxlen+ - the number of bytes to receive from the socket
+  # * +flags+ - zero or more of the +MSG_+ options
+  # * +options+ - keyword hash, supporting `exception: false`
+  #
+  # === Example
+  # 	serv = TCPServer.new("127.0.0.1", 0)
+  # 	af, port, host, addr = serv.addr
+  # 	c = TCPSocket.new(addr, port)
+  # 	s = serv.accept
+  # 	c.send "aaa", 0
+  # 	begin # emulate blocking recv.
+  # 	  p s.recv_nonblock(10) #=> "aaa"
+  # 	rescue IO::WaitReadable
+  # 	  IO.select([s])
+  # 	  retry
+  # 	end
+  #
+  # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+  # to _recv_nonblock_ fails.
+  #
+  # BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
+  # including Errno::EWOULDBLOCK.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitReadable.
+  # So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
+  #
+  # By specifying `exception: false`, the options hash allows you to indicate
+  # that recv_nonblock should not raise an IO::WaitWritable exception, but
+  # return the symbol :wait_writable instead.
+  #
+  # === See
+  # * Socket#recvfrom
+  def recv_nonblock(len, flag = 0, str = nil, exception: true)
+    __recv_nonblock(len, flag, str, exception)
+  end
 end
 
 class Socket < BasicSocket
@@ -282,6 +332,70 @@ class Socket < BasicSocket
     end
   end
 
+  # call-seq:
+  #   socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
+  #   socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
+  #
+  # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+  # O_NONBLOCK is set for the underlying file descriptor.
+  # _flags_ is zero or more of the +MSG_+ options.
+  # The first element of the results, _mesg_, is the data received.
+  # The second element, _sender_addrinfo_, contains protocol-specific address
+  # information of the sender.
+  #
+  # When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
+  # an empty string as data.
+  # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+  #
+  # === Parameters
+  # * +maxlen+ - the maximum number of bytes to receive from the socket
+  # * +flags+ - zero or more of the +MSG_+ options
+  #
+  # === Example
+  #   # In one file, start this first
+  #   require 'socket'
+  #   include Socket::Constants
+  #   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+  #   sockaddr = Socket.sockaddr_in(2200, 'localhost')
+  #   socket.bind(sockaddr)
+  #   socket.listen(5)
+  #   client, client_addrinfo = socket.accept
+  #   begin # emulate blocking recvfrom
+  #     pair = client.recvfrom_nonblock(20)
+  #   rescue IO::WaitReadable
+  #     IO.select([client])
+  #     retry
+  #   end
+  #   data = pair[0].chomp
+  #   puts "I only received 20 bytes '#{data}'"
+  #   sleep 1
+  #   socket.close
+  #
+  #   # In another file, start this second
+  #   require 'socket'
+  #   include Socket::Constants
+  #   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+  #   sockaddr = Socket.sockaddr_in(2200, 'localhost')
+  #   socket.connect(sockaddr)
+  #   socket.puts "Watch this get cut short!"
+  #   socket.close
+  #
+  # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+  # to _recvfrom_nonblock_ fails.
+  #
+  # Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+  # including Errno::EWOULDBLOCK.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitReadable.
+  # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+  #
+  # === See
+  # * Socket#recvfrom
+  def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+    __recvfrom_nonblock(len, flag, str, exception)
+  end
+
   # :call-seq:
   #   Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
   #   Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
@@ -866,3 +980,60 @@ class Socket < BasicSocket
 
 end
 
+class UDPSocket < IPSocket
+
+  # call-seq:
+  #   udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
+  #
+  # Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
+  # O_NONBLOCK is set for the underlying file descriptor.
+  # If _maxlen_ is omitted, its default value is 65536.
+  # _flags_ is zero or more of the +MSG_+ options.
+  # The first element of the results, _mesg_, is the data received.
+  # The second element, _sender_inet_addr_, is an array to represent the sender address.
+  #
+  # When recvfrom(2) returns 0,
+  # Socket#recvfrom_nonblock returns an empty string as data.
+  # It means an empty packet.
+  #
+  # === Parameters
+  # * +maxlen+ - the number of bytes to receive from the socket
+  # * +flags+ - zero or more of the +MSG_+ options
+  # * +options+ - keyword hash, supporting `exception: false`
+  #
+  # === Example
+  # 	require 'socket'
+  # 	s1 = UDPSocket.new
+  # 	s1.bind("127.0.0.1", 0)
+  # 	s2 = UDPSocket.new
+  # 	s2.bind("127.0.0.1", 0)
+  # 	s2.connect(*s1.addr.values_at(3,1))
+  # 	s1.connect(*s2.addr.values_at(3,1))
+  # 	s1.send "aaa", 0
+  # 	begin # emulate blocking recvfrom
+  # 	  p s2.recvfrom_nonblock(10)  #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
+  # 	rescue IO::WaitReadable
+  # 	  IO.select([s2])
+  # 	  retry
+  # 	end
+  #
+  # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+  # to _recvfrom_nonblock_ fails.
+  #
+  # UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+  # including Errno::EWOULDBLOCK.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitReadable.
+  # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+  #
+  # By specifying `exception: false`, the options hash allows you to indicate
+  # that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
+  # return the symbol :wait_writable instead.
+  #
+  # === See
+  # * Socket#recvfrom
+  def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+    __recvfrom_nonblock(len, flag, str, exception)
+  end
+end
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 601667d..9fa16ec 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -347,7 +347,8 @@ enum sock_recv_type {
     RECV_SOCKET                 /* Socket#recvfrom */
 };
 
-VALUE rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
+VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+			        VALUE ex, enum sock_recv_type from);
 VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
 
 int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 779398c..1a3320d 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -813,72 +813,11 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock)
     return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
 }
 
-/*
- * call-seq:
- *   socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
- *   socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_addrinfo_, contains protocol-specific address
- * information of the sender.
- *
- * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the maximum number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- *
- * === Example
- *   # In one file, start this first
- *   require 'socket'
- *   include Socket::Constants
- *   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- *   sockaddr = Socket.sockaddr_in(2200, 'localhost')
- *   socket.bind(sockaddr)
- *   socket.listen(5)
- *   client, client_addrinfo = socket.accept
- *   begin # emulate blocking recvfrom
- *     pair = client.recvfrom_nonblock(20)
- *   rescue IO::WaitReadable
- *     IO.select([client])
- *     retry
- *   end
- *   data = pair[0].chomp
- *   puts "I only received 20 bytes '#{data}'"
- *   sleep 1
- *   socket.close
- *
- *   # In another file, start this second
- *   require 'socket'
- *   include Socket::Constants
- *   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- *   sockaddr = Socket.sockaddr_in(2200, 'localhost')
- *   socket.connect(sockaddr)
- *   socket.puts "Watch this get cut short!"
- *   socket.close
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
 static VALUE
-sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+sock_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
 {
-    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
+    return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_SOCKET);
 }
 
 /*
@@ -2182,7 +2121,10 @@ Init_socket(void)
     rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
 
     rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
-    rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
+
+    /* for ext/socket/lib/socket.rb use only: */
+    rb_define_private_method(rb_cSocket,
+			     "__recvfrom_nonblock", sock_recvfrom_nonblock, 4);
 
     rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1);
     rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1);
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index d55ddfe..7b7b34f 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -214,63 +214,11 @@ udp_send(int argc, VALUE *argv, VALUE sock)
     return ret;
 }
 
-/*
- * call-seq:
- *   udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
- *
- * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * If _maxlen_ is omitted, its default value is 65536.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_inet_addr_, is an array to represent the sender address.
- *
- * When recvfrom(2) returns 0,
- * Socket#recvfrom_nonblock returns an empty string as data.
- * It means an empty packet.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- * * +options+ - keyword hash, supporting `exception: false`
- *
- * === Example
- * 	require 'socket'
- * 	s1 = UDPSocket.new
- * 	s1.bind("127.0.0.1", 0)
- * 	s2 = UDPSocket.new
- * 	s2.bind("127.0.0.1", 0)
- * 	s2.connect(*s1.addr.values_at(3,1))
- * 	s1.connect(*s2.addr.values_at(3,1))
- * 	s1.send "aaa", 0
- * 	begin # emulate blocking recvfrom
- * 	  p s2.recvfrom_nonblock(10)  #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
- * 	rescue IO::WaitReadable
- * 	  IO.select([s2])
- * 	  retry
- * 	end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
 static VALUE
-udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
 {
-    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
+    return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
 }
 
 void
@@ -287,5 +235,8 @@ rsock_init_udpsocket(void)
     rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
     rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
     rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
-    rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
+
+    /* for ext/socket/lib/socket.rb use only: */
+    rb_define_private_method(rb_cUDPSocket,
+			     "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
 }
-- 
EW


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* [PATCH] socket: avoid arg parsing in rsock_s_recvfrom_nonblock
@ 2015-11-12  9:48 Eric Wong
  0 siblings, 0 replies; 2+ messages in thread
From: Eric Wong @ 2015-11-12  9:48 UTC (permalink / raw)
  To: spew

* ext/socket/init.c (rsock_s_recvfrom_nonblock):
  avoid arg parsing with C API
  [ruby-core:71439] [Feature #11339]
* ext/socket/basicsocket.c (bsock_recv_nonblock):
  adjust for above change, make private
* ext/socket/socket.c (sock_recvfrom_nonblock): ditto
* ext/socket/udpsocket.c (udp_recvfrom_nonblock): ditto
* ext/socket/lib/socket.rb (BasicSocket#recv_nonblock):
  new wrapper for private method, move RDoc
  (Socket#recvfrom_nonblock): ditto
  (UDPSocket#recvfrom_nonblock): ditto

Note, not adding bm_recv_nonblock.rb to benchmark/ directory
since it is non-portable.  It is only in this commit message.

Benchmark results + code
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]

-----------------------------------------------------------
recv_nonblock

require 'socket'
nr = 1000000
msg = 'hello world'
buf = ''
size = msg.bytesize
UNIXSocket.pair(:SEQPACKET) do |a, b|
  nr.times do
    a.sendmsg(msg)
    b.recv_nonblock(size, 0, buf, exception: false)
  end
end

-----------------------------------------------------------
raw data:

[["recv_nonblock",
  [[1.83511221408844,
    1.8703329525887966,
    1.8448856547474861,
    1.859263762831688,
    1.8331583738327026],
   [1.5637447573244572,
    1.4062932096421719,
    1.4247371144592762,
    1.4108827747404575,
    1.4802536629140377]]]]

Elapsed time: 16.530452496 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name          a       b
recv_nonblock   1.833   1.406

Speedup ratio: compare with the result of `a' (greater is better)
name          b
recv_nonblock   1.304
---
 ext/socket/basicsocket.c |  60 +++--------------
 ext/socket/init.c        |  13 ++--
 ext/socket/lib/socket.rb | 171 +++++++++++++++++++++++++++++++++++++++++++++++
 ext/socket/rubysocket.h  |   3 +-
 ext/socket/socket.c      |  72 ++------------------
 ext/socket/udpsocket.c   |  63 ++---------------
 6 files changed, 199 insertions(+), 183 deletions(-)

diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c
index e5597f0..6bf10e8 100644
--- a/ext/socket/basicsocket.c
+++ b/ext/socket/basicsocket.c
@@ -643,59 +643,11 @@ bsock_recv(int argc, VALUE *argv, VALUE sock)
     return rsock_s_recvfrom(sock, argc, argv, RECV_RECV);
 }
 
-/*
- * call-seq:
- * 	basicsocket.recv_nonblock(maxlen [, flags [, options ]) => mesg
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The result, _mesg_, is the data received.
- *
- * When recvfrom(2) returns 0, Socket#recv_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- * * +options+ - keyword hash, supporting `exception: false`
- *
- * === Example
- * 	serv = TCPServer.new("127.0.0.1", 0)
- * 	af, port, host, addr = serv.addr
- * 	c = TCPSocket.new(addr, port)
- * 	s = serv.accept
- * 	c.send "aaa", 0
- * 	begin # emulate blocking recv.
- * 	  p s.recv_nonblock(10) #=> "aaa"
- * 	rescue IO::WaitReadable
- * 	  IO.select([s])
- * 	  retry
- * 	end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recv_nonblock_ fails.
- *
- * BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that recv_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- *
- * === See
- * * Socket#recvfrom
- */
-
+/* :nodoc: */
 static VALUE
-bsock_recv_nonblock(int argc, VALUE *argv, VALUE sock)
+bsock_recv_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
 {
-    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_RECV);
+    return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_RECV);
 }
 
 /*
@@ -764,10 +716,14 @@ rsock_init_basicsocket(void)
     rb_define_method(rb_cBasicSocket, "remote_address", bsock_remote_address, 0);
     rb_define_method(rb_cBasicSocket, "send", rsock_bsock_send, -1);
     rb_define_method(rb_cBasicSocket, "recv", bsock_recv, -1);
-    rb_define_method(rb_cBasicSocket, "recv_nonblock", bsock_recv_nonblock, -1);
+
     rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup", bsock_do_not_reverse_lookup, 0);
     rb_define_method(rb_cBasicSocket, "do_not_reverse_lookup=", bsock_do_not_reverse_lookup_set, 1);
 
+    /* for ext/socket/lib/socket.rb use only: */
+    rb_define_private_method(rb_cBasicSocket,
+			     "__recv_nonblock", bsock_recv_nonblock, 4);
+
     rb_define_method(rb_cBasicSocket, "sendmsg", rsock_bsock_sendmsg, -1); /* in ancdata.c */
     rb_define_method(rb_cBasicSocket, "sendmsg_nonblock", rsock_bsock_sendmsg_nonblock, -1); /* in ancdata.c */
     rb_define_method(rb_cBasicSocket, "recvmsg", rsock_bsock_recvmsg, -1); /* in ancdata.c */
diff --git a/ext/socket/init.c b/ext/socket/init.c
index 1710129..350ba65 100644
--- a/ext/socket/init.c
+++ b/ext/socket/init.c
@@ -200,24 +200,19 @@ rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
 }
 
 VALUE
-rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from)
+rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+			  VALUE ex, enum sock_recv_type from)
 {
     rb_io_t *fptr;
-    VALUE str;
     union_sockaddr buf;
     socklen_t alen = (socklen_t)sizeof buf;
-    VALUE len, flg;
     long buflen;
     long slen;
     int fd, flags;
     VALUE addr = Qnil;
-    VALUE opts = Qnil;
     socklen_t len0;
 
-    rb_scan_args(argc, argv, "12:", &len, &flg, &str, &opts);
-
-    if (flg == Qnil) flags = 0;
-    else             flags = NUM2INT(flg);
+    flags = NUM2INT(flg);
     buflen = NUM2INT(len);
     str = rsock_strbuf(str, buflen);
 
@@ -249,7 +244,7 @@ rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type
 #if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
 	  case EWOULDBLOCK:
 #endif
-            if (rsock_opt_false_p(opts, sym_exception))
+            if (ex == Qfalse)
 		return sym_wait_readable;
             rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvfrom(2) would block");
 	}
diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb
index 7c66e8f..915eb96 100644
--- a/ext/socket/lib/socket.rb
+++ b/ext/socket/lib/socket.rb
@@ -272,6 +272,56 @@ class BasicSocket < IO
     end
     addr
   end
+
+  # call-seq:
+  # 	basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg
+  #
+  # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+  # O_NONBLOCK is set for the underlying file descriptor.
+  # _flags_ is zero or more of the +MSG_+ options.
+  # The result, _mesg_, is the data received.
+  #
+  # When recvfrom(2) returns 0, Socket#recv_nonblock returns
+  # an empty string as data.
+  # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+  #
+  # === Parameters
+  # * +maxlen+ - the number of bytes to receive from the socket
+  # * +flags+ - zero or more of the +MSG_+ options
+  # * +options+ - keyword hash, supporting `exception: false`
+  #
+  # === Example
+  # 	serv = TCPServer.new("127.0.0.1", 0)
+  # 	af, port, host, addr = serv.addr
+  # 	c = TCPSocket.new(addr, port)
+  # 	s = serv.accept
+  # 	c.send "aaa", 0
+  # 	begin # emulate blocking recv.
+  # 	  p s.recv_nonblock(10) #=> "aaa"
+  # 	rescue IO::WaitReadable
+  # 	  IO.select([s])
+  # 	  retry
+  # 	end
+  #
+  # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+  # to _recv_nonblock_ fails.
+  #
+  # BasicSocket#recv_nonblock may raise any error corresponding to recvfrom(2) failure,
+  # including Errno::EWOULDBLOCK.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitReadable.
+  # So IO::WaitReadable can be used to rescue the exceptions for retrying recv_nonblock.
+  #
+  # By specifying `exception: false`, the options hash allows you to indicate
+  # that recv_nonblock should not raise an IO::WaitWritable exception, but
+  # return the symbol :wait_writable instead.
+  #
+  # === See
+  # * Socket#recvfrom
+  def recv_nonblock(len, flag = 0, str = nil, exception: true)
+    __recv_nonblock(len, flag, str, exception)
+  end
 end
 
 class Socket < BasicSocket
@@ -282,6 +332,70 @@ class Socket < BasicSocket
     end
   end
 
+  # call-seq:
+  #   socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
+  #   socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
+  #
+  # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
+  # O_NONBLOCK is set for the underlying file descriptor.
+  # _flags_ is zero or more of the +MSG_+ options.
+  # The first element of the results, _mesg_, is the data received.
+  # The second element, _sender_addrinfo_, contains protocol-specific address
+  # information of the sender.
+  #
+  # When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
+  # an empty string as data.
+  # The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
+  #
+  # === Parameters
+  # * +maxlen+ - the maximum number of bytes to receive from the socket
+  # * +flags+ - zero or more of the +MSG_+ options
+  #
+  # === Example
+  #   # In one file, start this first
+  #   require 'socket'
+  #   include Socket::Constants
+  #   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+  #   sockaddr = Socket.sockaddr_in(2200, 'localhost')
+  #   socket.bind(sockaddr)
+  #   socket.listen(5)
+  #   client, client_addrinfo = socket.accept
+  #   begin # emulate blocking recvfrom
+  #     pair = client.recvfrom_nonblock(20)
+  #   rescue IO::WaitReadable
+  #     IO.select([client])
+  #     retry
+  #   end
+  #   data = pair[0].chomp
+  #   puts "I only received 20 bytes '#{data}'"
+  #   sleep 1
+  #   socket.close
+  #
+  #   # In another file, start this second
+  #   require 'socket'
+  #   include Socket::Constants
+  #   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
+  #   sockaddr = Socket.sockaddr_in(2200, 'localhost')
+  #   socket.connect(sockaddr)
+  #   socket.puts "Watch this get cut short!"
+  #   socket.close
+  #
+  # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+  # to _recvfrom_nonblock_ fails.
+  #
+  # Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+  # including Errno::EWOULDBLOCK.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitReadable.
+  # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+  #
+  # === See
+  # * Socket#recvfrom
+  def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+    __recvfrom_nonblock(len, flag, str, exception)
+  end
+
   # :call-seq:
   #   Socket.tcp(host, port, local_host=nil, local_port=nil, [opts]) {|socket| ... }
   #   Socket.tcp(host, port, local_host=nil, local_port=nil, [opts])
@@ -866,3 +980,60 @@ class Socket < BasicSocket
 
 end
 
+class UDPSocket < IPSocket
+
+  # call-seq:
+  #   udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
+  #
+  # Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
+  # O_NONBLOCK is set for the underlying file descriptor.
+  # If _maxlen_ is omitted, its default value is 65536.
+  # _flags_ is zero or more of the +MSG_+ options.
+  # The first element of the results, _mesg_, is the data received.
+  # The second element, _sender_inet_addr_, is an array to represent the sender address.
+  #
+  # When recvfrom(2) returns 0,
+  # Socket#recvfrom_nonblock returns an empty string as data.
+  # It means an empty packet.
+  #
+  # === Parameters
+  # * +maxlen+ - the number of bytes to receive from the socket
+  # * +flags+ - zero or more of the +MSG_+ options
+  # * +options+ - keyword hash, supporting `exception: false`
+  #
+  # === Example
+  # 	require 'socket'
+  # 	s1 = UDPSocket.new
+  # 	s1.bind("127.0.0.1", 0)
+  # 	s2 = UDPSocket.new
+  # 	s2.bind("127.0.0.1", 0)
+  # 	s2.connect(*s1.addr.values_at(3,1))
+  # 	s1.connect(*s2.addr.values_at(3,1))
+  # 	s1.send "aaa", 0
+  # 	begin # emulate blocking recvfrom
+  # 	  p s2.recvfrom_nonblock(10)  #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
+  # 	rescue IO::WaitReadable
+  # 	  IO.select([s2])
+  # 	  retry
+  # 	end
+  #
+  # Refer to Socket#recvfrom for the exceptions that may be thrown if the call
+  # to _recvfrom_nonblock_ fails.
+  #
+  # UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
+  # including Errno::EWOULDBLOCK.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitReadable.
+  # So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
+  #
+  # By specifying `exception: false`, the options hash allows you to indicate
+  # that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
+  # return the symbol :wait_writable instead.
+  #
+  # === See
+  # * Socket#recvfrom
+  def recvfrom_nonblock(len, flag = 0, str = nil, exception: true)
+    __recvfrom_nonblock(len, flag, str, exception)
+  end
+end
diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h
index 601667d..9fa16ec 100644
--- a/ext/socket/rubysocket.h
+++ b/ext/socket/rubysocket.h
@@ -347,7 +347,8 @@ enum sock_recv_type {
     RECV_SOCKET                 /* Socket#recvfrom */
 };
 
-VALUE rsock_s_recvfrom_nonblock(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
+VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
+			        VALUE ex, enum sock_recv_type from);
 VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
 
 int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
diff --git a/ext/socket/socket.c b/ext/socket/socket.c
index 779398c..1a3320d 100644
--- a/ext/socket/socket.c
+++ b/ext/socket/socket.c
@@ -813,72 +813,11 @@ sock_recvfrom(int argc, VALUE *argv, VALUE sock)
     return rsock_s_recvfrom(sock, argc, argv, RECV_SOCKET);
 }
 
-/*
- * call-seq:
- *   socket.recvfrom_nonblock(maxlen) => [mesg, sender_addrinfo]
- *   socket.recvfrom_nonblock(maxlen, flags) => [mesg, sender_addrinfo]
- *
- * Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_addrinfo_, contains protocol-specific address
- * information of the sender.
- *
- * When recvfrom(2) returns 0, Socket#recvfrom_nonblock returns
- * an empty string as data.
- * The meaning depends on the socket: EOF on TCP, empty packet on UDP, etc.
- *
- * === Parameters
- * * +maxlen+ - the maximum number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- *
- * === Example
- *   # In one file, start this first
- *   require 'socket'
- *   include Socket::Constants
- *   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- *   sockaddr = Socket.sockaddr_in(2200, 'localhost')
- *   socket.bind(sockaddr)
- *   socket.listen(5)
- *   client, client_addrinfo = socket.accept
- *   begin # emulate blocking recvfrom
- *     pair = client.recvfrom_nonblock(20)
- *   rescue IO::WaitReadable
- *     IO.select([client])
- *     retry
- *   end
- *   data = pair[0].chomp
- *   puts "I only received 20 bytes '#{data}'"
- *   sleep 1
- *   socket.close
- *
- *   # In another file, start this second
- *   require 'socket'
- *   include Socket::Constants
- *   socket = Socket.new(AF_INET, SOCK_STREAM, 0)
- *   sockaddr = Socket.sockaddr_in(2200, 'localhost')
- *   socket.connect(sockaddr)
- *   socket.puts "Watch this get cut short!"
- *   socket.close
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * Socket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
 static VALUE
-sock_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+sock_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
 {
-    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_SOCKET);
+    return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_SOCKET);
 }
 
 /*
@@ -2182,7 +2121,10 @@ Init_socket(void)
     rb_define_method(rb_cSocket, "sysaccept", sock_sysaccept, 0);
 
     rb_define_method(rb_cSocket, "recvfrom", sock_recvfrom, -1);
-    rb_define_method(rb_cSocket, "recvfrom_nonblock", sock_recvfrom_nonblock, -1);
+
+    /* for ext/socket/lib/socket.rb use only: */
+    rb_define_private_method(rb_cSocket,
+			     "__recvfrom_nonblock", sock_recvfrom_nonblock, 4);
 
     rb_define_singleton_method(rb_cSocket, "socketpair", rsock_sock_s_socketpair, -1);
     rb_define_singleton_method(rb_cSocket, "pair", rsock_sock_s_socketpair, -1);
diff --git a/ext/socket/udpsocket.c b/ext/socket/udpsocket.c
index d55ddfe..7b7b34f 100644
--- a/ext/socket/udpsocket.c
+++ b/ext/socket/udpsocket.c
@@ -214,63 +214,11 @@ udp_send(int argc, VALUE *argv, VALUE sock)
     return ret;
 }
 
-/*
- * call-seq:
- *   udpsocket.recvfrom_nonblock(maxlen [, flags [, options]]) => [mesg, sender_inet_addr]
- *
- * Receives up to _maxlen_ bytes from +udpsocket+ using recvfrom(2) after
- * O_NONBLOCK is set for the underlying file descriptor.
- * If _maxlen_ is omitted, its default value is 65536.
- * _flags_ is zero or more of the +MSG_+ options.
- * The first element of the results, _mesg_, is the data received.
- * The second element, _sender_inet_addr_, is an array to represent the sender address.
- *
- * When recvfrom(2) returns 0,
- * Socket#recvfrom_nonblock returns an empty string as data.
- * It means an empty packet.
- *
- * === Parameters
- * * +maxlen+ - the number of bytes to receive from the socket
- * * +flags+ - zero or more of the +MSG_+ options
- * * +options+ - keyword hash, supporting `exception: false`
- *
- * === Example
- * 	require 'socket'
- * 	s1 = UDPSocket.new
- * 	s1.bind("127.0.0.1", 0)
- * 	s2 = UDPSocket.new
- * 	s2.bind("127.0.0.1", 0)
- * 	s2.connect(*s1.addr.values_at(3,1))
- * 	s1.connect(*s2.addr.values_at(3,1))
- * 	s1.send "aaa", 0
- * 	begin # emulate blocking recvfrom
- * 	  p s2.recvfrom_nonblock(10)  #=> ["aaa", ["AF_INET", 33302, "localhost.localdomain", "127.0.0.1"]]
- * 	rescue IO::WaitReadable
- * 	  IO.select([s2])
- * 	  retry
- * 	end
- *
- * Refer to Socket#recvfrom for the exceptions that may be thrown if the call
- * to _recvfrom_nonblock_ fails.
- *
- * UDPSocket#recvfrom_nonblock may raise any error corresponding to recvfrom(2) failure,
- * including Errno::EWOULDBLOCK.
- *
- * If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
- * it is extended by IO::WaitReadable.
- * So IO::WaitReadable can be used to rescue the exceptions for retrying recvfrom_nonblock.
- *
- * By specifying `exception: false`, the options hash allows you to indicate
- * that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- *
- * === See
- * * Socket#recvfrom
- */
+/* :nodoc: */
 static VALUE
-udp_recvfrom_nonblock(int argc, VALUE *argv, VALUE sock)
+udp_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str, VALUE ex)
 {
-    return rsock_s_recvfrom_nonblock(sock, argc, argv, RECV_IP);
+    return rsock_s_recvfrom_nonblock(sock, len, flg, str, ex, RECV_IP);
 }
 
 void
@@ -287,5 +235,8 @@ rsock_init_udpsocket(void)
     rb_define_method(rb_cUDPSocket, "connect", udp_connect, 2);
     rb_define_method(rb_cUDPSocket, "bind", udp_bind, 2);
     rb_define_method(rb_cUDPSocket, "send", udp_send, -1);
-    rb_define_method(rb_cUDPSocket, "recvfrom_nonblock", udp_recvfrom_nonblock, -1);
+
+    /* for ext/socket/lib/socket.rb use only: */
+    rb_define_private_method(rb_cUDPSocket,
+			     "__recvfrom_nonblock", udp_recvfrom_nonblock, 4);
 }
-- 
EW


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-11-12  9:48 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-12  9:48 [PATCH] socket: avoid arg parsing in rsock_s_recvfrom_nonblock Eric Wong
  -- strict thread matches above, loose matches on Subject: below --
2015-11-12  9:41 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).