diff options
author | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-17 01:05:30 +0000 |
---|---|---|
committer | normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2015-11-17 01:05:30 +0000 |
commit | 87b783296b9e3f46ccea670fd15711ccea92a8b4 (patch) | |
tree | 6eca4779f256042dab98c3f20b28597be448cc27 | |
parent | 790a45f98f2e8de61e261588b07348e668ce9464 (diff) | |
download | ruby-87b783296b9e3f46ccea670fd15711ccea92a8b4.tar.gz |
socket: avoid arg parsing in bsock_sendmsg_internal
* ext/socket/ancdata.c (bsock_sendmsg_internal): avoid arg parsing
[ruby-core:71439] [Feature #11339]
(rsock_bsock_sendmsg): make private, adjust for above
(rsock_bsock_sendmsg_nonblock): ditto
* ext/socket/rubysocket.h: adjust prototypes
(rsock_opt_false_p): remove
* ext/socket/basicsocket.c (rsock_init_basicsocket):
define private methods
* ext/socket/lib/socket.rb (BasicSocket#sendmsg): new wrapper
(BasicSocket#sendmsg_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]
-----------------------------------------------------------
sendmsg_nonblock
require 'socket'
nr = 1_000_000
i = 0
msg = '.'
buf = '.'
begin
r, w = UNIXSocket.pair(:SEQPACKET)
while i < nr
i += 1
w.sendmsg_nonblock(msg, exception: false)
r.recv(1, 0, buf)
end
ensure
r.close
w.close
end
-----------------------------------------------------------
raw data:
[["sendmsg_nonblock",
[[1.875997293740511,
1.8452614955604076,
1.8449317328631878,
1.8418389447033405,
1.869386937469244],
[1.5175109766423702,
1.4987873211503029,
1.4989623799920082,
1.47918451577425,
1.5017359890043736]]]]
Elapsed time: 16.775453245 (sec)
-----------------------------------------------------------
benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
sendmsg_nonblock 1.842 1.479
Speedup ratio: compare with the result of `a' (greater is better)
name b
sendmsg_nonblock 1.245
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52603 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 13 | ||||
-rw-r--r-- | ext/socket/ancdata.c | 82 | ||||
-rw-r--r-- | ext/socket/basicsocket.c | 7 | ||||
-rw-r--r-- | ext/socket/lib/socket.rb | 50 | ||||
-rw-r--r-- | ext/socket/rubysocket.h | 14 |
5 files changed, 88 insertions, 78 deletions
@@ -1,3 +1,16 @@ +Tue Nov 17 09:59:00 2015 Eric Wong <e@80x24.org> + + * ext/socket/ancdata.c (bsock_sendmsg_internal): avoid arg parsing + [ruby-core:71439] [Feature #11339] + (rsock_bsock_sendmsg): make private, adjust for above + (rsock_bsock_sendmsg_nonblock): ditto + * ext/socket/rubysocket.h: adjust prototypes + (rsock_opt_false_p): remove + * ext/socket/basicsocket.c (rsock_init_basicsocket): + define private methods + * ext/socket/lib/socket.rb (BasicSocket#sendmsg): new wrapper + (BasicSocket#sendmsg_nonblock): ditto + Tue Nov 17 09:45:18 2015 Eric Wong <e@80x24.org> * ext/socket/ancdata.c (bsock_recvmsg_internal): avoid arg parsing diff --git a/ext/socket/ancdata.c b/ext/socket/ancdata.c index 877975e4df..7e0441c042 100644 --- a/ext/socket/ancdata.c +++ b/ext/socket/ancdata.c @@ -3,7 +3,7 @@ #include <time.h> int rsock_cmsg_cloexec_state = -1; /* <0: unknown, 0: ignored, >0: working */ -static VALUE sym_exception, sym_wait_readable, sym_wait_writable; +static VALUE sym_wait_readable, sym_wait_writable; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) static VALUE rb_cAncillaryData; @@ -1128,14 +1128,13 @@ rb_sendmsg(int fd, const struct msghdr *msg, int flags) } static VALUE -bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) +bsock_sendmsg_internal(VALUE sock, VALUE data, VALUE vflags, + VALUE dest_sockaddr, VALUE controls, VALUE ex, + int nonblock) { rb_io_t *fptr; - VALUE data, vflags, dest_sockaddr; struct msghdr mh; struct iovec iov; - VALUE opts = Qnil; - VALUE controls = Qnil; int controls_num; #if defined(HAVE_STRUCT_MSGHDR_MSG_CONTROL) VALUE controls_str = 0; @@ -1149,15 +1148,11 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) family = rsock_getfamily(fptr); #endif - data = vflags = dest_sockaddr = Qnil; - - if (argc == 0) - rb_raise(rb_eArgError, "mesg argument required"); - - rb_scan_args(argc, argv, "12*:", &data, &vflags, &dest_sockaddr, &controls, - &opts); - StringValue(data); + + if (!RB_TYPE_P(controls, T_ARRAY)) { + controls = rb_ary_new(); + } controls_num = RARRAY_LENINT(controls); if (controls_num) { @@ -1285,7 +1280,7 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) goto retry; } if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) { - if (rsock_opt_false_p(opts, sym_exception)) { + if (ex == Qfalse) { return sym_wait_writable; } rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, @@ -1302,64 +1297,22 @@ bsock_sendmsg_internal(int argc, VALUE *argv, VALUE sock, int nonblock) #endif #if defined(HAVE_SENDMSG) -/* - * call-seq: - * basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent - * - * sendmsg sends a message using sendmsg(2) system call in blocking manner. - * - * _mesg_ is a string to send. - * - * _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB. - * - * _dest_sockaddr_ is a destination socket address for connection-less socket. - * It should be a sockaddr such as a result of Socket.sockaddr_in. - * An Addrinfo object can be used too. - * - * _controls_ is a list of ancillary data. - * The element of _controls_ should be Socket::AncillaryData or - * 3-elements array. - * The 3-element array should contains cmsg_level, cmsg_type and data. - * - * The return value, _numbytes_sent_ is an integer which is the number of bytes sent. - * - * sendmsg can be used to implement send_io as follows: - * - * # use Socket::AncillaryData. - * ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno) - * sock.sendmsg("a", 0, nil, ancdata) - * - * # use 3-element array. - * ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")] - * sock.sendmsg("\0", 0, nil, ancdata) - * - */ VALUE -rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock) +rsock_bsock_sendmsg(VALUE sock, VALUE data, VALUE flags, VALUE dest_sockaddr, + VALUE controls) { - return bsock_sendmsg_internal(argc, argv, sock, 0); + return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr, controls, + Qtrue, 0); } #endif #if defined(HAVE_SENDMSG) -/* - * call-seq: - * basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent - * - * sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner. - * - * It is similar to BasicSocket#sendmsg - * but the 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 sendmsg_nonblock should not raise an IO::WaitWritable exception, but - * return the symbol :wait_writable instead. - */ VALUE -rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock) +rsock_bsock_sendmsg_nonblock(VALUE sock, VALUE data, VALUE flags, + VALUE dest_sockaddr, VALUE controls, VALUE ex) { - return bsock_sendmsg_internal(argc, argv, sock, 1); + return bsock_sendmsg_internal(sock, data, flags, dest_sockaddr, + controls, ex, 1); } #endif @@ -1773,7 +1726,6 @@ rsock_init_ancdata(void) rb_define_method(rb_cAncillaryData, "ipv6_pktinfo_ifindex", ancillary_ipv6_pktinfo_ifindex, 0); #endif #undef rb_intern - sym_exception = ID2SYM(rb_intern("exception")); sym_wait_readable = ID2SYM(rb_intern("wait_readable")); sym_wait_writable = ID2SYM(rb_intern("wait_writable")); } diff --git a/ext/socket/basicsocket.c b/ext/socket/basicsocket.c index 1a0120cb27..eef66d4803 100644 --- a/ext/socket/basicsocket.c +++ b/ext/socket/basicsocket.c @@ -724,10 +724,11 @@ rsock_init_basicsocket(void) 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 */ - /* in ancdata.c */ + rb_define_private_method(rb_cBasicSocket, "__sendmsg", + rsock_bsock_sendmsg, 4); + rb_define_private_method(rb_cBasicSocket, "__sendmsg_nonblock", + rsock_bsock_sendmsg_nonblock, 5); rb_define_private_method(rb_cBasicSocket, "__recvmsg", rsock_bsock_recvmsg, 4); rb_define_private_method(rb_cBasicSocket, "__recvmsg_nonblock", diff --git a/ext/socket/lib/socket.rb b/ext/socket/lib/socket.rb index 9e85318c1b..705a0b8459 100644 --- a/ext/socket/lib/socket.rb +++ b/ext/socket/lib/socket.rb @@ -276,6 +276,56 @@ class BasicSocket < IO end # call-seq: + # basicsocket.sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls) => numbytes_sent + # + # sendmsg sends a message using sendmsg(2) system call in blocking manner. + # + # _mesg_ is a string to send. + # + # _flags_ is bitwise OR of MSG_* constants such as Socket::MSG_OOB. + # + # _dest_sockaddr_ is a destination socket address for connection-less socket. + # It should be a sockaddr such as a result of Socket.sockaddr_in. + # An Addrinfo object can be used too. + # + # _controls_ is a list of ancillary data. + # The element of _controls_ should be Socket::AncillaryData or + # 3-elements array. + # The 3-element array should contains cmsg_level, cmsg_type and data. + # + # The return value, _numbytes_sent_ is an integer which is the number of bytes sent. + # + # sendmsg can be used to implement send_io as follows: + # + # # use Socket::AncillaryData. + # ancdata = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, io.fileno) + # sock.sendmsg("a", 0, nil, ancdata) + # + # # use 3-element array. + # ancdata = [:SOCKET, :RIGHTS, [io.fileno].pack("i!")] + # sock.sendmsg("\0", 0, nil, ancdata) + def sendmsg(mesg, flags = 0, dest_sockaddr = nil, *controls) + __sendmsg(mesg, flags, dest_sockaddr, controls) + end + + # call-seq: + # basicsocket.sendmsg_nonblock(mesg, flags=0, dest_sockaddr=nil, *controls, opts={}) => numbytes_sent + # + # sendmsg_nonblock sends a message using sendmsg(2) system call in non-blocking manner. + # + # It is similar to BasicSocket#sendmsg + # but the 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 sendmsg_nonblock should not raise an IO::WaitWritable exception, but + # return the symbol :wait_writable instead. + def sendmsg_nonblock(mesg, flags = 0, dest_sockaddr = nil, *controls, + exception: true) + __sendmsg_nonblock(mesg, flags, dest_sockaddr, controls, exception) + end + + # call-seq: # basicsocket.recv_nonblock(maxlen [, flags [, buf [, options ]]]) => mesg # # Receives up to _maxlen_ bytes from +socket+ using recvfrom(2) after diff --git a/ext/socket/rubysocket.h b/ext/socket/rubysocket.h index 652876cc89..2135ea4a0b 100644 --- a/ext/socket/rubysocket.h +++ b/ext/socket/rubysocket.h @@ -361,8 +361,10 @@ VALUE rsock_sock_listen(VALUE sock, VALUE log); VALUE rsock_sockopt_new(int family, int level, int optname, VALUE data); #if defined(HAVE_SENDMSG) -VALUE rsock_bsock_sendmsg(int argc, VALUE *argv, VALUE sock); -VALUE rsock_bsock_sendmsg_nonblock(int argc, VALUE *argv, VALUE sock); +VALUE rsock_bsock_sendmsg(VALUE sock, VALUE data, VALUE flags, + VALUE dest_sockaddr, VALUE controls); +VALUE rsock_bsock_sendmsg_nonblock(VALUE sock, VALUE data, VALUE flags, + VALUE dest_sockaddr, VALUE controls, VALUE ex); #else #define rsock_bsock_sendmsg rb_f_notimplement #define rsock_bsock_sendmsg_nonblock rb_f_notimplement @@ -437,12 +439,4 @@ static inline void rsock_maybe_wait_fd(int fd) { } # define MSG_DONTWAIT_RELIABLE 0 #endif -static inline int -rsock_opt_false_p(VALUE opt, VALUE sym) -{ - if (!NIL_P(opt) && Qfalse == rb_hash_lookup2(opt, sym, Qundef)) - return 1; - return 0; -} - #endif |