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:
parent
dad2abc69f
commit
365557f111
6 changed files with 142 additions and 130 deletions
|
@ -13,6 +13,7 @@ rbconfig.rb
|
|||
|
||||
trace_point.rb
|
||||
ast.rb
|
||||
io.rb
|
||||
|
||||
# the lib/ directory (which has its own .document file)
|
||||
lib
|
||||
|
|
|
@ -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
|
||||
|
|
1
inits.c
1
inits.c
|
@ -70,6 +70,7 @@ rb_call_inits(void)
|
|||
|
||||
CALL(builtin);
|
||||
|
||||
CALL(IO_nonblock);
|
||||
CALL(ast);
|
||||
CALL(vm_trace);
|
||||
}
|
||||
|
|
17
io.c
17
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();
|
||||
}
|
||||
|
|
123
io.rb
Normal file
123
io.rb
Normal 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
|
123
prelude.rb
123
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
|
||||
|
|
Loading…
Reference in a new issue