1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

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.
This commit is contained in:
Koichi Sasada 2019-11-08 09:39:28 +09:00
parent dad2abc69f
commit 365557f111
6 changed files with 142 additions and 130 deletions

View file

@ -13,6 +13,7 @@ rbconfig.rb
trace_point.rb
ast.rb
io.rb
# the lib/ directory (which has its own .document file)
lib

View file

@ -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

View file

@ -70,6 +70,7 @@ rb_call_inits(void)
CALL(builtin);
CALL(IO_nonblock);
CALL(ast);
CALL(vm_trace);
}

17
io.c
View file

@ -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();
}

123
io.rb Normal file
View file

@ -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

View file

@ -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