[前][次][番号順一覧][スレッド一覧]

ruby-changes:40521

From: normal <ko1@a...>
Date: Tue, 17 Nov 2015 09:58:53 +0900 (JST)
Subject: [ruby-changes:40521] normal:r52602 (trunk): socket (bsock_recvmsg_internal): avoid arg parsing

normal	2015-11-17 09:58:23 +0900 (Tue, 17 Nov 2015)

  New Revision: 52602

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=52602

  Log:
    socket (bsock_recvmsg_internal): avoid arg parsing
    
    * ext/socket/ancdata.c (bsock_recvmsg_internal): avoid arg parsing
      (rsock_bsock_recvmsg): adjust for above change
      (rsock_bsock_recvmsg_nonblock): ditto
      [ruby-core:71439] [Feature #11339]
    * ext/socket/rubysocket.h: adjust prototypes for above
    * ext/socket/basicsocket.c (rsock_init_basicsocket):
      adjust private methods
    * ext/socket/lib/socket.rb (BasicSocket#recvmsg): wrapper method
      (BasicSocket#recvmsg_nonblock): ditto
    
    target 0: a (ruby 2.3.0dev (2015-11-12 trunk 52550) [x86_64-linux])
    target 1: b (ruby 2.3.0dev (2015-11-12 avoid-kwarg-capi 52550) [x86_64-linux]
    
    -----------------------------------------------------------
    recvmsg_nonblock
    
    require 'socket'
    nr = 1_000_000
    i = 0
    msg = '.'
    buf = '.'
    begin
      r, w = UNIXSocket.pair(:SEQPACKET)
      while i < nr
        i += 1
        w.sendmsg(msg)
        r.recvmsg_nonblock(1, exception: false)
      end
    ensure
      r.close
      w.close
    end
    
    -----------------------------------------------------------
    raw data:
    
    [["recvmsg_nonblock",
      [[3.721687912940979,
        3.6072621569037437,
        3.580637402832508,
        3.614185404032469,
        3.6029579415917397],
       [2.4694008752703667,
        2.4908322244882584,
        2.5051278844475746,
        2.5037173740565777,
        2.548359278589487]]]]
    
    Elapsed time: 30.646087052 (sec)
    -----------------------------------------------------------
    benchmark results:
    minimum results in each 5 measurements.
    Execution time (sec)
    name             a       b
    recvmsg_nonblock   3.581   2.469
    
    Speedup ratio: compare with the result of `a' (greater is better)
    name             b
    recvmsg_nonblock   1.450

  Modified files:
    trunk/ChangeLog
    trunk/ext/socket/ancdata.c
    trunk/ext/socket/basicsocket.c
    trunk/ext/socket/lib/socket.rb
    trunk/ext/socket/rubysocket.h
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 52601)
+++ ChangeLog	(revision 52602)
@@ -1,3 +1,15 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Nov 17 09:45:18 2015  Eric Wong  <e@8...>
+
+	* ext/socket/ancdata.c (bsock_recvmsg_internal): avoid arg parsing
+	  (rsock_bsock_recvmsg): adjust for above change
+	  (rsock_bsock_recvmsg_nonblock): ditto
+	  [ruby-core:71439] [Feature #11339]
+	* ext/socket/rubysocket.h: adjust prototypes for above
+	* ext/socket/basicsocket.c (rsock_init_basicsocket):
+	  adjust private methods
+	* ext/socket/lib/socket.rb (BasicSocket#recvmsg): wrapper method
+	  (BasicSocket#recvmsg_nonblock): ditto
+
 Tue Nov 17 08:36:34 2015  Eric Wong  <e@8...>
 
 	* ext/socket/init.c (rsock_s_accept_nonblock): avoid parsing args
Index: ext/socket/rubysocket.h
===================================================================
--- ext/socket/rubysocket.h	(revision 52601)
+++ ext/socket/rubysocket.h	(revision 52602)
@@ -369,8 +369,10 @@ VALUE rsock_bsock_sendmsg_nonblock(int a https://github.com/ruby/ruby/blob/trunk/ext/socket/rubysocket.h#L369
 #endif
 
 #if defined(HAVE_RECVMSG)
-VALUE rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock);
-VALUE rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock);
+VALUE rsock_bsock_recvmsg(VALUE sock, VALUE dlen, VALUE clen, VALUE flags,
+			  VALUE scm_rights);
+VALUE rsock_bsock_recvmsg_nonblock(VALUE sock, VALUE dlen, VALUE clen,
+				   VALUE flags, VALUE scm_rights, VALUE ex);
 ssize_t rsock_recvmsg(int socket, struct msghdr *message, int flags);
 #else
 #define rsock_bsock_recvmsg rb_f_notimplement
Index: ext/socket/lib/socket.rb
===================================================================
--- ext/socket/lib/socket.rb	(revision 52601)
+++ ext/socket/lib/socket.rb	(revision 52602)
@@ -324,6 +324,77 @@ class BasicSocket < IO https://github.com/ruby/ruby/blob/trunk/ext/socket/lib/socket.rb#L324
   def recv_nonblock(len, flag = 0, str = nil, exception: true)
     __recv_nonblock(len, flag, str, exception)
   end
+
+  # call-seq:
+  #    basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
+  #
+  # recvmsg receives a message using recvmsg(2) system call in blocking manner.
+  #
+  # _maxmesglen_ is the maximum length of mesg to receive.
+  #
+  # _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
+  #
+  # _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
+  #
+  # _opts_ is option hash.
+  # Currently :scm_rights=>bool is the only option.
+  #
+  # :scm_rights option specifies that application expects SCM_RIGHTS control message.
+  # If the value is nil or false, application don't expects SCM_RIGHTS control message.
+  # In this case, recvmsg closes the passed file descriptors immediately.
+  # This is the default behavior.
+  #
+  # If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
+  # In this case, recvmsg creates IO objects for each file descriptors for
+  # Socket::AncillaryData#unix_rights method.
+  #
+  # The return value is 4-elements array.
+  #
+  # _mesg_ is a string of the received message.
+  #
+  # _sender_addrinfo_ is a sender socket address for connection-less socket.
+  # It is an Addrinfo object.
+  # For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
+  #
+  # _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
+  # It will be nil if the system uses 4.3BSD style old recvmsg system call.
+  #
+  # _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
+  #
+  #   #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
+  #
+  # _maxmesglen_ and _maxcontrollen_ can be nil.
+  # In that case, the buffer will be grown until the message is not truncated.
+  # Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
+  #
+  # recvmsg can be used to implement recv_io as follows:
+  #
+  #   mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
+  #   controls.each {|ancdata|
+  #     if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
+  #       return ancdata.unix_rights[0]
+  #     end
+  #   }
+  def recvmsg(dlen = 4096, flags = 0, clen = 4096, scm_rights: false)
+    __recvmsg(dlen, flags, clen, scm_rights)
+  end
+
+  # call-seq:
+  #    basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
+  #
+  # recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
+  #
+  # It is similar to BasicSocket#recvmsg
+  # but non-blocking flag is set before the system call
+  # and it doesn't retry the system call.
+  #
+  # By specifying `exception: false`, the _opts_ hash allows you to indicate
+  # that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
+  # return the symbol :wait_writable instead.
+  def recvmsg_nonblock(dlen = 4096, flags = 0, clen = 4096,
+                       scm_rights: false, exception: true)
+    __recvmsg_nonblock(dlen, flags, clen, scm_rights, exception)
+  end
 end
 
 class Socket < BasicSocket
Index: ext/socket/basicsocket.c
===================================================================
--- ext/socket/basicsocket.c	(revision 52601)
+++ ext/socket/basicsocket.c	(revision 52602)
@@ -726,7 +726,11 @@ rsock_init_basicsocket(void) https://github.com/ruby/ruby/blob/trunk/ext/socket/basicsocket.c#L726
 
     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 */
-    rb_define_method(rb_cBasicSocket, "recvmsg_nonblock", rsock_bsock_recvmsg_nonblock, -1); /* in ancdata.c */
+
+    /* in ancdata.c */
+    rb_define_private_method(rb_cBasicSocket, "__recvmsg",
+			     rsock_bsock_recvmsg, 4);
+    rb_define_private_method(rb_cBasicSocket, "__recvmsg_nonblock",
+			    rsock_bsock_recvmsg_nonblock, 5);
 
 }
Index: ext/socket/ancdata.c
===================================================================
--- ext/socket/ancdata.c	(revision 52601)
+++ ext/socket/ancdata.c	(revision 52602)
@@ -1487,11 +1487,11 @@ make_io_for_unix_rights(VALUE ctl, struc https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1487
 #endif
 
 static VALUE
-bsock_recvmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock)
+bsock_recvmsg_internal(VALUE sock,
+		VALUE vmaxdatlen, VALUE vflags, VALUE vmaxctllen,
+		VALUE scm_rights, VALUE ex, int nonblock)
 {
     rb_io_t *fptr;
-    VALUE vmaxdatlen, vmaxctllen, vflags;
-    VALUE vopts;
     int grow_buffer;
     size_t maxdatlen;
     int flags, orig_flags;
@@ -1512,17 +1512,14 @@ bsock_recvmsg_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1512
     int gc_done = 0;
 #endif
 
-
-    rb_scan_args(argc, argv, "03:", &vmaxdatlen, &vflags, &vmaxctllen, &vopts);
-
-    maxdatlen = NIL_P(vmaxdatlen) ? 4096 : NUM2SIZET(vmaxdatlen);
+    maxdatlen = NUM2SIZET(vmaxdatlen);
 #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
-    maxctllen = NIL_P(vmaxctllen) ? 4096 : NUM2SIZET(vmaxctllen);
+    maxctllen = NUM2SIZET(vmaxctllen);
 #else
     if (!NIL_P(vmaxctllen))
         rb_raise(rb_eArgError, "control message not supported");
 #endif
-    flags = NIL_P(vflags) ? 0 : NUM2INT(vflags);
+    flags = NUM2INT(vflags);
 #ifdef MSG_DONTWAIT
     if (nonblock)
         flags |= MSG_DONTWAIT;
@@ -1532,7 +1529,7 @@ bsock_recvmsg_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1529
     grow_buffer = NIL_P(vmaxdatlen) || NIL_P(vmaxctllen);
 
     request_scm_rights = 0;
-    if (!NIL_P(vopts) && RTEST(rb_hash_aref(vopts, ID2SYM(rb_intern("scm_rights")))))
+    if (RTEST(scm_rights))
         request_scm_rights = 1;
 #if !defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL)
     if (request_scm_rights)
@@ -1602,7 +1599,7 @@ bsock_recvmsg_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1599
             goto retry;
         }
         if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
-            if (rsock_opt_false_p(vopts, sym_exception)) {
+            if (ex == Qfalse) {
                 return sym_wait_readable;
             }
             rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "recvmsg(2) would block");
@@ -1720,85 +1717,21 @@ bsock_recvmsg_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/socket/ancdata.c#L1717
 #endif
 
 #if defined(HAVE_RECVMSG)
-/*
- * call-seq:
- *    basicsocket.recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={}) => [mesg, sender_addrinfo, rflags, *controls]
- *
- * recvmsg receives a message using recvmsg(2) system call in blocking manner.
- *
- * _maxmesglen_ is the maximum length of mesg to receive.
- *
- * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_PEEK.
- *
- * _maxcontrollen_ is the maximum length of controls (ancillary data) to receive.
- *
- * _opts_ is option hash.
- * Currently :scm_rights=>bool is the only option.
- *
- * :scm_rights option specifies that application expects SCM_RIGHTS control message.
- * If the value is nil or false, application don't expects SCM_RIGHTS control message.
- * In this case, recvmsg closes the passed file descriptors immediately.
- * This is the default behavior.
- *
- * If :scm_rights value is neither nil nor false, application expects SCM_RIGHTS control message.
- * In this case, recvmsg creates IO objects for each file descriptors for
- * Socket::AncillaryData#unix_rights method.
- *
- * The return value is 4-elements array.
- *
- * _mesg_ is a string of the received message.
- *
- * _sender_addrinfo_ is a sender socket address for connection-less socket.
- * It is an Addrinfo object.
- * For connection-oriented socket such as TCP, sender_addrinfo is platform dependent.
- *
- * _rflags_ is a flags on the received message which is bitwise OR of MSG_* constants such as Socket::MSG_TRUNC.
- * It will be nil if the system uses 4.3BSD style old recvmsg system call.
- *
- * _controls_ is ancillary data which is an array of Socket::AncillaryData objects such as:
- *
- *   #<Socket::AncillaryData: AF_UNIX SOCKET RIGHTS 7>
- *
- * _maxmesglen_ and _maxcontrollen_ can be nil.
- * In that case, the buffer will be grown until the message is not truncated.
- * Internally, MSG_PEEK is used and MSG_TRUNC/MSG_CTRUNC are checked.
- *
- * recvmsg can be used to implement recv_io as follows:
- *
- *   mesg, sender_sockaddr, rflags, *controls = sock.recvmsg(:scm_rights=>true)
- *   controls.each {|ancdata|
- *     if ancdata.cmsg_is?(:SOCKET, :RIGHTS)
- *       return ancdata.unix_rights[0]
- *     end
- *   }
- *
- */
 VALUE
-rsock_bsock_recvmsg(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_recvmsg(VALUE sock, VALUE dlen, VALUE flags, VALUE clen,
+		    VALUE scm_rights)
 {
-    return bsock_recvmsg_internal(argc, argv, sock, 0);
+    VALUE ex = Qtrue;
+    return bsock_recvmsg_internal(sock, dlen, flags, clen, scm_rights, ex, 0);
 }
 #endif
 
 #if defined(HAVE_RECVMSG)
-/*
- * call-seq:
- *    basicsocket.recvmsg_nonblock(maxdatalen=nil, flags=0, maxcontrollen=nil, opts={}) => [data, sender_addrinfo, rflags, *controls]
- *
- * recvmsg receives a message using recvmsg(2) system call in non-blocking manner.
- *
- * It is similar to BasicSocket#recvmsg
- * but non-blocking flag is set before the system call
- * and it doesn't retry the system call.
- *
- * By specifying `exception: false`, the _opts_ hash allows you to indicate
- * that recvmsg_nonblock should not raise an IO::WaitWritable exception, but
- * return the symbol :wait_writable instead.
- */
 VALUE
-rsock_bsock_recvmsg_nonblock(int argc, VALUE *argv, VALUE sock)
+rsock_bsock_recvmsg_nonblock(VALUE sock, VALUE dlen, VALUE flags, VALUE clen,
+			     VALUE scm_rights, VALUE ex)
 {
-    return bsock_recvmsg_internal(argc, argv, sock, 1);
+    return bsock_recvmsg_internal(sock, dlen, flags, clen, scm_rights, ex, 1);
 }
 #endif
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]