Skip to content

Commit 365557f

Browse files
committed
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.
1 parent dad2abc commit 365557f

File tree

6 files changed

+142
-130
lines changed

6 files changed

+142
-130
lines changed

.document

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rbconfig.rb
1313

1414
trace_point.rb
1515
ast.rb
16+
io.rb
1617

1718
# the lib/ directory (which has its own .document file)
1819
lib

common.mk

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,7 @@ preludes: {$(VPATH)}prelude.c
10941094
preludes: {$(VPATH)}miniprelude.c
10951095
preludes: {$(srcdir)}golf_prelude.c
10961096

1097-
BUILTIN_RB_SRCS = $(srcdir)/trace_point.rb $(srcdir)/ast.rb
1097+
BUILTIN_RB_SRCS = $(srcdir)/trace_point.rb $(srcdir)/ast.rb $(srcdir)/io.rb
10981098

10991099
builtin_binary.inc: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/tool/mk_builtin_binary.rb
11001100
$(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.
11051105
load_ast.inc: $(srcdir)/ast.rb $(srcdir)/tool/mk_builtin_loader.rb
11061106
$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/ast.rb
11071107

1108+
load_io.inc: $(srcdir)/io.rb $(srcdir)/tool/mk_builtin_loader.rb
1109+
$(Q) $(BASERUBY) $(srcdir)/tool/mk_builtin_loader.rb $(srcdir)/io.rb
1110+
11081111
$(srcdir)/revision.h:
11091112
$(Q)$(gnumake:yes=#) $(RM) $(@F)
11101113
$(Q)$(gnumake:yes=#) exit > $@ || exit > $(@F)
@@ -2217,6 +2220,7 @@ io.$(OBJEXT): $(CCAN_DIR)/str/str.h
22172220
io.$(OBJEXT): $(hdrdir)/ruby.h
22182221
io.$(OBJEXT): $(hdrdir)/ruby/ruby.h
22192222
io.$(OBJEXT): {$(VPATH)}assert.h
2223+
io.$(OBJEXT): {$(VPATH)}builtin.h
22202224
io.$(OBJEXT): {$(VPATH)}config.h
22212225
io.$(OBJEXT): {$(VPATH)}defines.h
22222226
io.$(OBJEXT): {$(VPATH)}dln.h
@@ -2227,6 +2231,7 @@ io.$(OBJEXT): {$(VPATH)}intern.h
22272231
io.$(OBJEXT): {$(VPATH)}internal.h
22282232
io.$(OBJEXT): {$(VPATH)}io.c
22292233
io.$(OBJEXT): {$(VPATH)}io.h
2234+
io.$(OBJEXT): {$(VPATH)}load_io.inc
22302235
io.$(OBJEXT): {$(VPATH)}method.h
22312236
io.$(OBJEXT): {$(VPATH)}missing.h
22322237
io.$(OBJEXT): {$(VPATH)}node.h

inits.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ rb_call_inits(void)
7070

7171
CALL(builtin);
7272

73+
CALL(IO_nonblock);
7374
CALL(ast);
7475
CALL(vm_trace);
7576
}

io.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <errno.h>
2323
#include "ruby_atomic.h"
2424
#include "ccan/list/list.h"
25+
#include "builtin.h"
2526

2627
#undef free
2728
#define free(x) xfree(x)
@@ -2941,7 +2942,7 @@ io_nonblock_eof(int no_exception)
29412942

29422943
/* :nodoc: */
29432944
static VALUE
2944-
io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex)
2945+
io_read_nonblock(rb_execution_context_t *ec, VALUE io, VALUE length, VALUE str, VALUE ex)
29452946
{
29462947
rb_io_t *fptr;
29472948
long n, len;
@@ -2993,7 +2994,7 @@ io_read_nonblock(VALUE io, VALUE length, VALUE str, VALUE ex)
29932994

29942995
/* :nodoc: */
29952996
static VALUE
2996-
io_write_nonblock(VALUE io, VALUE str, VALUE ex)
2997+
io_write_nonblock(rb_execution_context_t *ec, VALUE io, VALUE str, VALUE ex)
29972998
{
29982999
rb_io_t *fptr;
29993000
long n;
@@ -13312,10 +13313,6 @@ Init_IO(void)
1331213313

1331313314
rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
1331413315

13315-
/* for prelude.rb use only: */
13316-
rb_define_private_method(rb_cIO, "__read_nonblock", io_read_nonblock, 3);
13317-
rb_define_private_method(rb_cIO, "__write_nonblock", io_write_nonblock, 2);
13318-
1331913316
rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
1332013317
rb_define_method(rb_cIO, "read", io_read, -1);
1332113318
rb_define_method(rb_cIO, "write", io_write_m, -1);
@@ -13525,3 +13522,11 @@ Init_IO(void)
1352513522
sym_wait_readable = ID2SYM(rb_intern("wait_readable"));
1352613523
sym_wait_writable = ID2SYM(rb_intern("wait_writable"));
1352713524
}
13525+
13526+
#include "load_io.inc"
13527+
13528+
void
13529+
Init_IO_nonblock(void)
13530+
{
13531+
load_io();
13532+
}

io.rb

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
class IO
2+
# other IO methods are defined in io.c
3+
4+
# call-seq:
5+
# ios.read_nonblock(maxlen [, options]) -> string
6+
# ios.read_nonblock(maxlen, outbuf [, options]) -> outbuf
7+
#
8+
# Reads at most <i>maxlen</i> bytes from <em>ios</em> using
9+
# the read(2) system call after O_NONBLOCK is set for
10+
# the underlying file descriptor.
11+
#
12+
# If the optional <i>outbuf</i> argument is present,
13+
# it must reference a String, which will receive the data.
14+
# The <i>outbuf</i> will contain only the received data after the method call
15+
# even if it is not empty at the beginning.
16+
#
17+
# read_nonblock just calls the read(2) system call.
18+
# It causes all errors the read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
19+
# The caller should care such errors.
20+
#
21+
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
22+
# it is extended by IO::WaitReadable.
23+
# So IO::WaitReadable can be used to rescue the exceptions for retrying
24+
# read_nonblock.
25+
#
26+
# read_nonblock causes EOFError on EOF.
27+
#
28+
# On some platforms, such as Windows, non-blocking mode is not supported
29+
# on IO objects other than sockets. In such cases, Errno::EBADF will
30+
# be raised.
31+
#
32+
# If the read byte buffer is not empty,
33+
# read_nonblock reads from the buffer like readpartial.
34+
# In this case, the read(2) system call is not called.
35+
#
36+
# When read_nonblock raises an exception kind of IO::WaitReadable,
37+
# read_nonblock should not be called
38+
# until io is readable for avoiding busy loop.
39+
# This can be done as follows.
40+
#
41+
# # emulates blocking read (readpartial).
42+
# begin
43+
# result = io.read_nonblock(maxlen)
44+
# rescue IO::WaitReadable
45+
# IO.select([io])
46+
# retry
47+
# end
48+
#
49+
# Although IO#read_nonblock doesn't raise IO::WaitWritable.
50+
# OpenSSL::Buffering#read_nonblock can raise IO::WaitWritable.
51+
# If IO and SSL should be used polymorphically,
52+
# IO::WaitWritable should be rescued too.
53+
# See the document of OpenSSL::Buffering#read_nonblock for sample code.
54+
#
55+
# Note that this method is identical to readpartial
56+
# except the non-blocking flag is set.
57+
#
58+
# By specifying a keyword argument _exception_ to +false+, you can indicate
59+
# that read_nonblock should not raise an IO::WaitReadable exception, but
60+
# return the symbol +:wait_readable+ instead. At EOF, it will return nil
61+
# instead of raising EOFError.
62+
def read_nonblock(len, buf = nil, exception: true)
63+
__builtin_io_read_nonblock(len, buf, exception)
64+
end
65+
66+
# call-seq:
67+
# ios.write_nonblock(string) -> integer
68+
# ios.write_nonblock(string [, options]) -> integer
69+
#
70+
# Writes the given string to <em>ios</em> using
71+
# the write(2) system call after O_NONBLOCK is set for
72+
# the underlying file descriptor.
73+
#
74+
# It returns the number of bytes written.
75+
#
76+
# write_nonblock just calls the write(2) system call.
77+
# It causes all errors the write(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
78+
# The result may also be smaller than string.length (partial write).
79+
# The caller should care such errors and partial write.
80+
#
81+
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
82+
# it is extended by IO::WaitWritable.
83+
# So IO::WaitWritable can be used to rescue the exceptions for retrying write_nonblock.
84+
#
85+
# # Creates a pipe.
86+
# r, w = IO.pipe
87+
#
88+
# # write_nonblock writes only 65536 bytes and return 65536.
89+
# # (The pipe size is 65536 bytes on this environment.)
90+
# s = "a" * 100000
91+
# p w.write_nonblock(s) #=> 65536
92+
#
93+
# # write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
94+
# p w.write_nonblock("b") # Resource temporarily unavailable (Errno::EAGAIN)
95+
#
96+
# If the write buffer is not empty, it is flushed at first.
97+
#
98+
# When write_nonblock raises an exception kind of IO::WaitWritable,
99+
# write_nonblock should not be called
100+
# until io is writable for avoiding busy loop.
101+
# This can be done as follows.
102+
#
103+
# begin
104+
# result = io.write_nonblock(string)
105+
# rescue IO::WaitWritable, Errno::EINTR
106+
# IO.select(nil, [io])
107+
# retry
108+
# end
109+
#
110+
# Note that this doesn't guarantee to write all data in string.
111+
# The length written is reported as result and it should be checked later.
112+
#
113+
# On some platforms such as Windows, write_nonblock is not supported
114+
# according to the kind of the IO object.
115+
# In such cases, write_nonblock raises <code>Errno::EBADF</code>.
116+
#
117+
# By specifying a keyword argument _exception_ to +false+, you can indicate
118+
# that write_nonblock should not raise an IO::WaitWritable exception, but
119+
# return the symbol +:wait_writable+ instead.
120+
def write_nonblock(buf, exception: true)
121+
__builtin_io_write_nonblock(buf, exception)
122+
end
123+
end

prelude.rb

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -13,129 +13,6 @@ def exclusive(&block) end if false
1313
end
1414
end
1515

16-
class IO
17-
18-
# call-seq:
19-
# ios.read_nonblock(maxlen [, options]) -> string
20-
# ios.read_nonblock(maxlen, outbuf [, options]) -> outbuf
21-
#
22-
# Reads at most <i>maxlen</i> bytes from <em>ios</em> using
23-
# the read(2) system call after O_NONBLOCK is set for
24-
# the underlying file descriptor.
25-
#
26-
# If the optional <i>outbuf</i> argument is present,
27-
# it must reference a String, which will receive the data.
28-
# The <i>outbuf</i> will contain only the received data after the method call
29-
# even if it is not empty at the beginning.
30-
#
31-
# read_nonblock just calls the read(2) system call.
32-
# It causes all errors the read(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
33-
# The caller should care such errors.
34-
#
35-
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
36-
# it is extended by IO::WaitReadable.
37-
# So IO::WaitReadable can be used to rescue the exceptions for retrying
38-
# read_nonblock.
39-
#
40-
# read_nonblock causes EOFError on EOF.
41-
#
42-
# On some platforms, such as Windows, non-blocking mode is not supported
43-
# on IO objects other than sockets. In such cases, Errno::EBADF will
44-
# be raised.
45-
#
46-
# If the read byte buffer is not empty,
47-
# read_nonblock reads from the buffer like readpartial.
48-
# In this case, the read(2) system call is not called.
49-
#
50-
# When read_nonblock raises an exception kind of IO::WaitReadable,
51-
# read_nonblock should not be called
52-
# until io is readable for avoiding busy loop.
53-
# This can be done as follows.
54-
#
55-
# # emulates blocking read (readpartial).
56-
# begin
57-
# result = io.read_nonblock(maxlen)
58-
# rescue IO::WaitReadable
59-
# IO.select([io])
60-
# retry
61-
# end
62-
#
63-
# Although IO#read_nonblock doesn't raise IO::WaitWritable.
64-
# OpenSSL::Buffering#read_nonblock can raise IO::WaitWritable.
65-
# If IO and SSL should be used polymorphically,
66-
# IO::WaitWritable should be rescued too.
67-
# See the document of OpenSSL::Buffering#read_nonblock for sample code.
68-
#
69-
# Note that this method is identical to readpartial
70-
# except the non-blocking flag is set.
71-
#
72-
# By specifying a keyword argument _exception_ to +false+, you can indicate
73-
# that read_nonblock should not raise an IO::WaitReadable exception, but
74-
# return the symbol +:wait_readable+ instead. At EOF, it will return nil
75-
# instead of raising EOFError.
76-
def read_nonblock(len, buf = nil, exception: true)
77-
__read_nonblock(len, buf, exception)
78-
end
79-
80-
# call-seq:
81-
# ios.write_nonblock(string) -> integer
82-
# ios.write_nonblock(string [, options]) -> integer
83-
#
84-
# Writes the given string to <em>ios</em> using
85-
# the write(2) system call after O_NONBLOCK is set for
86-
# the underlying file descriptor.
87-
#
88-
# It returns the number of bytes written.
89-
#
90-
# write_nonblock just calls the write(2) system call.
91-
# It causes all errors the write(2) system call causes: Errno::EWOULDBLOCK, Errno::EINTR, etc.
92-
# The result may also be smaller than string.length (partial write).
93-
# The caller should care such errors and partial write.
94-
#
95-
# If the exception is Errno::EWOULDBLOCK or Errno::EAGAIN,
96-
# it is extended by IO::WaitWritable.
97-
# So IO::WaitWritable can be used to rescue the exceptions for retrying write_nonblock.
98-
#
99-
# # Creates a pipe.
100-
# r, w = IO.pipe
101-
#
102-
# # write_nonblock writes only 65536 bytes and return 65536.
103-
# # (The pipe size is 65536 bytes on this environment.)
104-
# s = "a" * 100000
105-
# p w.write_nonblock(s) #=> 65536
106-
#
107-
# # write_nonblock cannot write a byte and raise EWOULDBLOCK (EAGAIN).
108-
# p w.write_nonblock("b") # Resource temporarily unavailable (Errno::EAGAIN)
109-
#
110-
# If the write buffer is not empty, it is flushed at first.
111-
#
112-
# When write_nonblock raises an exception kind of IO::WaitWritable,
113-
# write_nonblock should not be called
114-
# until io is writable for avoiding busy loop.
115-
# This can be done as follows.
116-
#
117-
# begin
118-
# result = io.write_nonblock(string)
119-
# rescue IO::WaitWritable, Errno::EINTR
120-
# IO.select(nil, [io])
121-
# retry
122-
# end
123-
#
124-
# Note that this doesn't guarantee to write all data in string.
125-
# The length written is reported as result and it should be checked later.
126-
#
127-
# On some platforms such as Windows, write_nonblock is not supported
128-
# according to the kind of the IO object.
129-
# In such cases, write_nonblock raises <code>Errno::EBADF</code>.
130-
#
131-
# By specifying a keyword argument _exception_ to +false+, you can indicate
132-
# that write_nonblock should not raise an IO::WaitWritable exception, but
133-
# return the symbol +:wait_writable+ instead.
134-
def write_nonblock(buf, exception: true)
135-
__write_nonblock(buf, exception)
136-
end
137-
end
138-
13916
class Binding
14017
# :nodoc:
14118
def irb

0 commit comments

Comments
 (0)