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

ruby-changes:58630

From: Koichi <ko1@a...>
Date: Fri, 8 Nov 2019 10:03:53 +0900 (JST)
Subject: [ruby-changes:58630] 365557f111 (master): Define IO#read/write_nonblock with builtins.

https://git.ruby-lang.org/ruby.git/commit/?id=365557f111

From 365557f111b453289a5e2ce0cdda0899ae248c71 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Fri, 8 Nov 2019 09:39:28 +0900
Subject: Define IO#read/write_nonblock with builtins.

IO#read/write_nonblock methods are defined in prelude.rb with
special private method __read/write_nonblock to reduce keyword
parameters overhead. We can move them into io.rb with builtin
functions.

diff --git a/.document b/.document
index c0c9cde..2a76ac0 100644
--- a/.document
+++ b/.document
@@ -13,6 +13,7 @@ rbconfig.rb https://github.com/ruby/ruby/blob/trunk/.document#L13
 
 trace_point.rb
 ast.rb
+io.rb
 
 # the lib/ directory (which has its own .document file)
 lib
diff --git a/common.mk b/common.mk
index 15561b6..2b9fe1d 100644
--- a/common.mk
+++ b/common.mk
@@ -1094,7 +1094,7 @@ preludes: {$(VPATH)}prelude.c https://github.com/ruby/ruby/blob/trunk/common.mk#L1094
 preludes: {$(VPATH)}miniprelude.c
 preludes: {$(srcdir)}golf_prelude.c
 
-BUILTIN_RB_SRCS = $(srcdir)/trace_point.rb $(srcdir)/ast.rb
+BUILTIN_RB_SRCS = $(srcdir)/trace_point.rb $(srcdir)/ast.rb $(srcdir)/io.rb
 
 builtin_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/tool/mk_builtin_binary.rb
 	$(Q) $(MINIRUBY) $(srcdir)/tool/mk_builtin_binary.rb
@@ -1105,6 +1105,9 @@ load_trace_point.inc: $(srcdir)/trace_point.rb $(srcdir)/tool/mk_builtin_loader. https://github.com/ruby/ruby/blob/trunk/common.mk#L1105
 load_ast.inc: $(srcdir)/ast.rb $(srcdir)/tool/mk_builtin_loader.rb
 	$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/ast.rb
 
+load_io.inc: $(srcdir)/io.rb $(srcdir)/tool/mk_builtin_loader.rb
+	$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/io.rb
+
 $(srcdir)/revision.h:
 	$(Q)$(gnumake:yes=#) $(RM) $(@F)
 	$(Q)$(gnumake:yes=#) exit > $@ || exit > $(@F)
@@ -2217,6 +2220,7 @@ io.$(OBJEXT): $(CCAN_DIR)/str/str.h https://github.com/ruby/ruby/blob/trunk/common.mk#L2220
 io.$(OBJEXT): $(hdrdir)/ruby.h
 io.$(OBJEXT): $(hdrdir)/ruby/ruby.h
 io.$(OBJEXT): {$(VPATH)}assert.h
+io.$(OBJEXT): {$(VPATH)}builtin.h
 io.$(OBJEXT): {$(VPATH)}config.h
 io.$(OBJEXT): {$(VPATH)}defines.h
 io.$(OBJEXT): {$(VPATH)}dln.h
@@ -2227,6 +2231,7 @@ io.$(OBJEXT): {$(VPATH)}intern.h https://github.com/ruby/ruby/blob/trunk/common.mk#L2231
 io.$(OBJEXT): {$(VPATH)}internal.h
 io.$(OBJEXT): {$(VPATH)}io.c
 io.$(OBJEXT): {$(VPATH)}io.h
+io.$(OBJEXT): {$(VPATH)}load_io.inc
 io.$(OBJEXT): {$(VPATH)}method.h
 io.$(OBJEXT): {$(VPATH)}missing.h
 io.$(OBJEXT): {$(VPATH)}node.h
diff --git a/inits.c b/inits.c
index 16569ad..3faa8b8 100644
--- a/inits.c
+++ b/inits.c
@@ -70,6 +70,7 @@ rb_call_inits(void) https://github.com/ruby/ruby/blob/trunk/inits.c#L70
 
     CALL(builtin);
 
+    CALL(IO_nonblock);
     CALL(ast);
     CALL(vm_trace);
 }
diff --git a/io.c b/io.c
index eccd429..ada3300 100644
--- a/io.c
+++ b/io.c
@@ -22,6 +22,7 @@ https://github.com/ruby/ruby/blob/trunk/io.c#L22
 #include <errno.h>
 #include "ruby_atomic.h"
 #include "ccan/list/list.h"
+#include "builtin.h"
 
 #undef free
 #define free(x) xfree(x)
@@ -2941,7 +2942,7 @@ io_nonblock_eof(int no_exception) https://github.com/ruby/ruby/blob/trunk/io.c#L2942
 
 /* :nodoc: */
 static VALUE
-io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex)
+io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
 {
     rb_io_t *fptr;
     long n, len;
@@ -2993,7 +2994,7 @@ io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex) https://github.com/ruby/ruby/blob/trunk/io.c#L2994
 
 /* :nodoc: */
 static VALUE
-io_write_nonblock(VALUE io, VALUE str, VALUE ex)
+io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
 {
     rb_io_t *fptr;
     long n;
@@ -13312,10 +13313,6 @@ Init_IO(void) https://github.com/ruby/ruby/blob/trunk/io.c#L13313
 
     rb_define_method(rb_cIO, "readlines",  rb_io_readlines, -1);
 
-    /* for prelude.rb use only: */
-    rb_define_private_method(rb_cIO, "__read_nonblock", io_read_nonblock, 3);
-    rb_define_private_method(rb_cIO, "__write_nonblock", io_write_nonblock, 2);
-
     rb_define_method(rb_cIO, "readpartial",  io_readpartial, -1);
     rb_define_method(rb_cIO, "read",  io_read, -1);
     rb_define_method(rb_cIO, "write", io_write_m, -1);
@@ -13525,3 +13522,11 @@ Init_IO(void) https://github.com/ruby/ruby/blob/trunk/io.c#L13522
     sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
     sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
 }
+
+#include "load_io.inc"
+
+void
+Init_IO_nonblock(void)
+{
+    load_io();
+}
diff --git a/io.rb b/io.rb
new file mode 100644
index 0000000..1b6dddf
--- /dev/null
+++ b/io.rb
@@ -0,0 +1,123 @@ https://github.com/ruby/ruby/blob/trunk/io.rb#L1
+class IO
+  # other IO methods are defined in io.c
+
+  # call-seq:
+  #    ios.read_nonblock(maxlen [, options])              -> string
+  #    ios.read_nonblock(maxlen, outbuf [, options])      -> outbuf
+  #
+  # Reads at most <i>maxlen</i> bytes from <em>ios</em> using
+  # the read(2) system call after O_NONBLOCK is set for
+  # the underlying file descriptor.
+  #
+  # If the optional <i>outbuf</i> argument is present,
+  # it must reference a String, which will receive the data.
+  # The <i>outbuf</i> will contain only the received data after the method call
+  # even if it is not empty at the beginning.
+  #
+  # read_nonblock just calls the read(2) system call.
+  # It causes all errors the read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
+  # The caller should care such errors.
+  #
+  # 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
+  # read_nonblock.
+  #
+  # read_nonblock causes EOFError on EOF.
+  #
+  # On some platforms, such as Windows, non-blocking mode is not supported
+  # on IO objects other than sockets. In such cases, Errno::EBADF will
+  # be raised.
+  #
+  # If the read byte buffer is not empty,
+  # read_nonblock reads from the buffer like readpartial.
+  # In this case, the read(2) system call is not called.
+  #
+  # When read_nonblock raises an exception kind of IO::WaitReadable,
+  # read_nonblock should not be called
+  # until io is readable for avoiding busy loop.
+  # This can be done as follows.
+  #
+  #   # emulates blocking read (readpartial).
+  #   begin
+  #     result = io.read_nonblock(maxlen)
+  #   rescue IO::WaitReadable
+  #     IO.select([io])
+  #     retry
+  #   end
+  #
+  # Although IO#read_nonblock doesn't raise IO::WaitWritable.
+  # OpenSSL::Buffering#read_nonblock can raise IO::WaitWritable.
+  # If IO and SSL should be used polymorphically,
+  # IO::WaitWritable should be rescued too.
+  # See the document of OpenSSL::Buffering#read_nonblock for sample code.
+  #
+  # Note that this method is identical to readpartial
+  # except the non-blocking flag is set.
+  #
+  # By specifying a keyword argument _exception_ to +false+, you can indicate
+  # that read_nonblock should not raise an IO::WaitReadable exception, but
+  # return the symbol +:wait_readable+ instead. At EOF, it will return nil
+  # instead of raising EOFError.
+  def read_nonblock(len, buf = nil, exception: true)
+    __builtin_io_read_nonblock(len, buf, exception)
+  end
+
+  # call-seq:
+  #    ios.write_nonblock(string)   -> integer
+  #    ios.write_nonblock(string [, options])   -> integer
+  #
+  # Writes the given string to <em>ios</em> using
+  # the write(2) system call after O_NONBLOCK is set for
+  # the underlying file descriptor.
+  #
+  # It returns the number of bytes written.
+  #
+  # write_nonblock just calls the write(2) system call.
+  # It causes all errors the write(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
+  # The result may also be smaller than string.length (partial write).
+  # The caller should care such errors and partial write.
+  #
+  # If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
+  # it is extended by IO::WaitWritable.
+  # So IO::WaitWritable can be used to rescue the exceptions for retrying write_nonblock.
+  #
+  #   # Creates a pipe.
+  #   r, w = IO.pipe
+  #
+  #   # write_nonblock writes only 65536 bytes and return 65536.
+  #   # (The pipe size is 65536 bytes on this environment.)
+  #   s = "a" * 100000
+  #   p w.write_nonblock(s)     #=> 65536
+  #
+  #   # write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
+  #   p w.write_nonblock("b")   # Resource temporarily unavailable (Errno::EAGAIN)
+  #
+  # If the write buffer is not empty, it is flushed at first.
+  #
+  # When write_nonblock raises an exception kind of IO::WaitWritable,
+  # write_nonblock should not be called
+  # until io is writable for avoiding busy loop.
+  # This can be done as follows.
+  #
+  #   begin
+  #     result = io.write_nonblock(string)
+  #   rescue IO::WaitWritable, Errno::EINTR
+  #     IO.select(nil, [io])
+  #     retry
+  #   end
+  #
+  # Note that this doesn't guarantee to write all data in string.
+  # The length written is reported as result and it should be checked later.
+  #
+  # On some platforms such as Windows, write_nonblock is not supported
+  # according to the kind of the IO object.
+  # In such cases, write_nonblock raises <code>Errno::EBADF</code>.
+  #
+  # By specifying a keyword argument _exception_ to +false+, you can indicate
+  # that write_nonblock should not raise an IO::WaitWritable exception, but
+  # return the symbol +:wait_writable+ instead.
+  def write_nonblock(buf, exception: true)
+    __builtin_io_write_nonblock(buf, exception)
+  end
+end
diff --git a/prelude.rb b/prelude.rb
index 7cc2d26..be249af 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -13,129 +13,6 @@ class << Thread https://github.com/ruby/ruby/blob/trunk/prelude.rb#L13
   end
 end
 
-class IO
-
-  # call-seq:
-  #    ios.read_nonblock(maxlen [, options])              -> string
-  #    ios.read_nonblock(maxlen, outbuf [, options])      -> outbuf
-  #
-  # Reads at most <i>maxlen</i> byt (... truncated)

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

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