aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKoichi Sasada <ko1@atdot.net>2019-11-08 09:39:28 +0900
committerKoichi Sasada <ko1@atdot.net>2019-11-08 10:03:19 +0900
commit365557f111b453289a5e2ce0cdda0899ae248c71 (patch)
treeb5df6aef79ebf5cd02a3182bce5163724881178b
parentdad2abc69fdd1af52df353b8604017bd6a5c6a99 (diff)
downloadruby-365557f111b453289a5e2ce0cdda0899ae248c71.tar.gz
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.
-rw-r--r--.document1
-rw-r--r--common.mk7
-rw-r--r--inits.c1
-rw-r--r--io.c17
-rw-r--r--io.rb123
-rw-r--r--prelude.rb123
6 files changed, 142 insertions, 130 deletions
diff --git a/.document b/.document
index c0c9cded79..2a76ac0705 100644
--- a/.document
+++ b/.document
@@ -13,6 +13,7 @@ rbconfig.rb
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 15561b6307..2b9fe1dbaa 100644
--- a/common.mk
+++ b/common.mk
@@ -1094,7 +1094,7 @@ preludes: {$(VPATH)}prelude.c
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.
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
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
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 16569ad32a..3faa8b8c56 100644
--- a/inits.c
+++ b/inits.c
@@ -70,6 +70,7 @@ rb_call_inits(void)
CALL(builtin);
+ CALL(IO_nonblock);
CALL(ast);
CALL(vm_trace);
}
diff --git a/io.c b/io.c
index eccd429352..ada3300645 100644
--- a/io.c
+++ b/io.c
@@ -22,6 +22,7 @@
#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)
/* :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)
/* :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)
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)
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 0000000000..1b6dddf9e5
--- /dev/null
+++ b/io.rb
@@ -0,0 +1,123 @@
+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 7cc2d260b6..be249af751 100644
--- a/prelude.rb
+++ b/prelude.rb
@@ -13,129 +13,6 @@ class << Thread
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> 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)
- __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)
- __write_nonblock(buf, exception)
- end
-end
-
class Binding
# :nodoc:
def irb