Skip to content
This repository was archived by the owner on Aug 29, 2024. It is now read-only.

Commit 0232aa8

Browse files
committed
Use native I/O when the scheduler is supported.
1 parent 632d9bb commit 0232aa8

File tree

3 files changed

+79
-61
lines changed

3 files changed

+79
-61
lines changed

async-io.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec|
1515

1616
spec.required_ruby_version = ">= 2.5"
1717

18-
spec.add_dependency "async", "~> 1.14"
18+
spec.add_dependency "async", "~> 1.29"
1919

2020
spec.add_development_dependency "async-container", "~> 0.15"
2121
spec.add_development_dependency "async-rspec", "~> 1.10"

lib/async/io/generic.rb

Lines changed: 56 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -100,71 +100,75 @@ def wrap(*args)
100100

101101
wraps ::IO, :external_encoding, :internal_encoding, :autoclose?, :autoclose=, :pid, :stat, :binmode, :flush, :set_encoding, :set_encoding_by_bom, :to_io, :to_i, :reopen, :fileno, :fsync, :fdatasync, :sync, :sync=, :tell, :seek, :rewind, :pos, :pos=, :eof, :eof?, :close_on_exec?, :close_on_exec=, :closed?, :close_read, :close_write, :isatty, :tty?, :binmode?, :sysseek, :advise, :ioctl, :fcntl, :nread, :ready?, :pread, :pwrite, :pathconf
102102

103-
# Read the specified number of bytes from the input stream. This is fast path.
104-
# @example
105-
# data = io.sysread(512)
106-
wrap_blocking_method :sysread, :read_nonblock
107-
108-
alias readpartial read_nonblock
109-
110-
# Read `length` bytes of data from the underlying I/O. If length is unspecified, read everything.
111-
def read(length = nil, buffer = nil)
112-
if buffer
113-
buffer.clear
114-
else
115-
buffer = String.new
116-
end
103+
if Async::Scheduler.supported?
104+
def_delegators :@io, :read, :write, :sysread, :syswrite, :read_nonblock, :write_nonblock, :readpartial
105+
else
106+
# Read the specified number of bytes from the input stream. This is fast path.
107+
# @example
108+
# data = io.sysread(512)
109+
wrap_blocking_method :sysread, :read_nonblock
110+
111+
alias readpartial read_nonblock
117112

118-
if length
119-
return "" if length <= 0
113+
# Read `length` bytes of data from the underlying I/O. If length is unspecified, read everything.
114+
def read(length = nil, buffer = nil)
115+
if buffer
116+
buffer.clear
117+
else
118+
buffer = String.new
119+
end
120120

121-
# Fast path:
122-
if buffer = self.sysread(length, buffer)
121+
if length
122+
return "" if length <= 0
123123

124-
# Slow path:
125-
while buffer.bytesize < length
124+
# Fast path:
125+
if buffer = self.sysread(length, buffer)
126+
126127
# Slow path:
127-
if chunk = self.sysread(length - buffer.bytesize)
128-
buffer << chunk
129-
else
130-
break
128+
while buffer.bytesize < length
129+
# Slow path:
130+
if chunk = self.sysread(length - buffer.bytesize)
131+
buffer << chunk
132+
else
133+
break
134+
end
131135
end
136+
137+
return buffer
138+
else
139+
return nil
140+
end
141+
else
142+
buffer = self.sysread(BLOCK_SIZE, buffer)
143+
144+
while chunk = self.sysread(BLOCK_SIZE)
145+
buffer << chunk
132146
end
133147

134148
return buffer
135-
else
136-
return nil
137149
end
138-
else
139-
buffer = self.sysread(BLOCK_SIZE, buffer)
140-
141-
while chunk = self.sysread(BLOCK_SIZE)
142-
buffer << chunk
143-
end
144-
145-
return buffer
146150
end
147-
end
148-
149-
# Write entire buffer to output stream. This is fast path.
150-
# @example
151-
# io.syswrite("Hello World")
152-
wrap_blocking_method :syswrite, :write_nonblock
153-
154-
def write(buffer)
155-
# Fast path:
156-
written = self.syswrite(buffer)
157-
remaining = buffer.bytesize - written
158151

159-
while remaining > 0
160-
# Slow path:
161-
length = self.syswrite(buffer.byteslice(written, remaining))
152+
# Write entire buffer to output stream. This is fast path.
153+
# @example
154+
# io.syswrite("Hello World")
155+
wrap_blocking_method :syswrite, :write_nonblock
156+
157+
def write(buffer)
158+
# Fast path:
159+
written = self.syswrite(buffer)
160+
remaining = buffer.bytesize - written
162161

163-
remaining -= length
164-
written += length
162+
while remaining > 0
163+
# Slow path:
164+
length = self.syswrite(buffer.byteslice(written, remaining))
165+
166+
remaining -= length
167+
written += length
168+
end
169+
170+
return written
165171
end
166-
167-
return written
168172
end
169173

170174
def << buffer

lib/async/io/stream.rb

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,16 +258,30 @@ def fill_read_buffer(size = @block_size)
258258
flush
259259

260260
if @read_buffer.empty?
261-
if @io.read_nonblock(size, @read_buffer, exception: false)
262-
# Async.logger.debug(self, name: "read") {@read_buffer.inspect}
263-
return true
261+
while true
262+
case result = @io.read_nonblock(size, @read_buffer, exception: false)
263+
when String
264+
# Async.logger.debug(self, name: "read") {@read_buffer.inspect}
265+
return true
266+
when Symbol
267+
@io.__send__(result)
268+
else
269+
break
270+
end
264271
end
265272
else
266-
if chunk = @io.read_nonblock(size, @input_buffer, exception: false)
267-
@read_buffer << chunk
268-
# Async.logger.debug(self, name: "read") {@read_buffer.inspect}
269-
270-
return true
273+
while true
274+
case result = @io.read_nonblock(size, @input_buffer, exception: false)
275+
when String
276+
@read_buffer << result
277+
# Async.logger.debug(self, name: "read") {@read_buffer.inspect}
278+
279+
return true
280+
when Symbol
281+
@io.__send__(result)
282+
else
283+
break
284+
end
271285
end
272286
end
273287

0 commit comments

Comments
 (0)