polyphony 0.40 → 0.43.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +11 -2
- data/.gitignore +2 -2
- data/.rubocop.yml +30 -0
- data/CHANGELOG.md +29 -2
- data/Gemfile.lock +13 -10
- data/README.md +0 -1
- data/Rakefile +3 -3
- data/TODO.md +27 -97
- data/docs/_config.yml +56 -7
- data/docs/_sass/custom/custom.scss +6 -26
- data/docs/_sass/overrides.scss +0 -46
- data/docs/{user-guide → _user-guide}/all-about-timers.md +0 -0
- data/docs/_user-guide/index.md +9 -0
- data/docs/{user-guide → _user-guide}/web-server.md +0 -0
- data/docs/api-reference/fiber.md +2 -2
- data/docs/api-reference/index.md +9 -0
- data/docs/api-reference/polyphony-process.md +1 -1
- data/docs/api-reference/thread.md +1 -1
- data/docs/faq.md +21 -11
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +10 -0
- data/docs/getting-started/installing.md +2 -6
- data/docs/getting-started/overview.md +486 -0
- data/docs/getting-started/tutorial.md +27 -19
- data/docs/index.md +6 -2
- data/docs/main-concepts/concurrency.md +0 -5
- data/docs/main-concepts/design-principles.md +69 -21
- data/docs/main-concepts/extending.md +1 -1
- data/docs/main-concepts/index.md +9 -0
- data/docs/polyphony-logo.png +0 -0
- data/examples/adapters/redis_blpop.rb +12 -0
- data/examples/core/01-spinning-up-fibers.rb +1 -0
- data/examples/core/03-interrupting.rb +4 -1
- data/examples/core/04-handling-signals.rb +19 -0
- data/examples/core/xx-agent.rb +102 -0
- data/examples/core/xx-sleeping.rb +14 -6
- data/examples/io/xx-irb.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +7 -6
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +13 -36
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +58 -0
- data/examples/performance/xx-array.rb +11 -0
- data/examples/performance/xx-fiber-switch.rb +9 -0
- data/examples/performance/xx-snooze.rb +15 -0
- data/ext/{gyro → polyphony}/extconf.rb +2 -2
- data/ext/{gyro → polyphony}/fiber.c +15 -22
- data/ext/{gyro → polyphony}/libev.c +0 -0
- data/ext/{gyro → polyphony}/libev.h +0 -0
- data/ext/polyphony/libev_agent.c +725 -0
- data/ext/polyphony/libev_queue.c +217 -0
- data/ext/{gyro/gyro.c → polyphony/polyphony.c} +12 -37
- data/ext/polyphony/polyphony.h +90 -0
- data/ext/polyphony/polyphony_ext.c +21 -0
- data/ext/{gyro → polyphony}/thread.c +34 -151
- data/ext/{gyro → polyphony}/tracing.c +1 -1
- data/lib/polyphony.rb +19 -12
- data/lib/polyphony/adapters/irb.rb +1 -1
- data/lib/polyphony/adapters/postgres.rb +6 -5
- data/lib/polyphony/adapters/process.rb +5 -5
- data/lib/polyphony/adapters/redis.rb +3 -2
- data/lib/polyphony/adapters/trace.rb +28 -28
- data/lib/polyphony/core/channel.rb +3 -3
- data/lib/polyphony/core/exceptions.rb +1 -1
- data/lib/polyphony/core/global_api.rb +13 -11
- data/lib/polyphony/core/resource_pool.rb +3 -3
- data/lib/polyphony/core/sync.rb +2 -2
- data/lib/polyphony/core/thread_pool.rb +6 -6
- data/lib/polyphony/core/throttler.rb +13 -6
- data/lib/polyphony/event.rb +27 -0
- data/lib/polyphony/extensions/core.rb +22 -14
- data/lib/polyphony/extensions/fiber.rb +4 -4
- data/lib/polyphony/extensions/io.rb +59 -25
- data/lib/polyphony/extensions/openssl.rb +36 -16
- data/lib/polyphony/extensions/socket.rb +28 -10
- data/lib/polyphony/extensions/thread.rb +16 -9
- data/lib/polyphony/net.rb +9 -9
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +3 -3
- data/test/helper.rb +12 -1
- data/test/test_agent.rb +130 -0
- data/test/{test_async.rb → test_event.rb} +13 -7
- data/test/test_ext.rb +25 -4
- data/test/test_fiber.rb +19 -10
- data/test/test_global_api.rb +6 -6
- data/test/test_io.rb +46 -24
- data/test/test_queue.rb +74 -0
- data/test/test_signal.rb +3 -40
- data/test/test_socket.rb +34 -0
- data/test/test_thread.rb +37 -16
- data/test/test_trace.rb +6 -5
- metadata +39 -41
- data/docs/_includes/nav.html +0 -51
- data/docs/_includes/prevnext.html +0 -17
- data/docs/_layouts/default.html +0 -106
- data/docs/api-reference.md +0 -11
- data/docs/api-reference/gyro-async.md +0 -57
- data/docs/api-reference/gyro-child.md +0 -29
- data/docs/api-reference/gyro-queue.md +0 -44
- data/docs/api-reference/gyro-timer.md +0 -51
- data/docs/api-reference/gyro.md +0 -25
- data/docs/getting-started.md +0 -10
- data/docs/main-concepts.md +0 -10
- data/docs/user-guide.md +0 -10
- data/examples/core/forever_sleep.rb +0 -19
- data/ext/gyro/async.c +0 -132
- data/ext/gyro/child.c +0 -108
- data/ext/gyro/gyro.h +0 -158
- data/ext/gyro/gyro_ext.c +0 -33
- data/ext/gyro/io.c +0 -457
- data/ext/gyro/queue.c +0 -146
- data/ext/gyro/selector.c +0 -205
- data/ext/gyro/signal.c +0 -99
- data/ext/gyro/socket.c +0 -213
- data/ext/gyro/timer.c +0 -115
- data/test/test_timer.rb +0 -56
data/lib/polyphony/core/sync.rb
CHANGED
@@ -4,7 +4,7 @@ module Polyphony
|
|
4
4
|
# Implements mutex lock for synchronizing access to a shared resource
|
5
5
|
class Mutex
|
6
6
|
def initialize
|
7
|
-
@waiting_fibers =
|
7
|
+
@waiting_fibers = Polyphony::Queue.new
|
8
8
|
end
|
9
9
|
|
10
10
|
def synchronize
|
@@ -18,4 +18,4 @@ module Polyphony
|
|
18
18
|
snooze
|
19
19
|
end
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end
|
@@ -8,29 +8,29 @@ module Polyphony
|
|
8
8
|
attr_reader :size
|
9
9
|
|
10
10
|
def self.process(&block)
|
11
|
-
@default_pool ||=
|
11
|
+
@default_pool ||= new
|
12
12
|
@default_pool.process(&block)
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.reset
|
16
16
|
return unless @default_pool
|
17
|
-
|
17
|
+
|
18
18
|
@default_pool.stop
|
19
19
|
@default_pool = nil
|
20
20
|
end
|
21
21
|
|
22
22
|
def initialize(size = Etc.nprocessors)
|
23
23
|
@size = size
|
24
|
-
@task_queue =
|
24
|
+
@task_queue = Polyphony::Queue.new
|
25
25
|
@threads = (1..@size).map { Thread.new { thread_loop } }
|
26
26
|
end
|
27
27
|
|
28
28
|
def process(&block)
|
29
29
|
setup unless @task_queue
|
30
30
|
|
31
|
-
|
32
|
-
@task_queue << [block,
|
33
|
-
|
31
|
+
watcher = Fiber.current.auto_watcher
|
32
|
+
@task_queue << [block, watcher]
|
33
|
+
watcher.await
|
34
34
|
end
|
35
35
|
|
36
36
|
def cast(&block)
|
@@ -6,17 +6,24 @@ module Polyphony
|
|
6
6
|
def initialize(rate)
|
7
7
|
@rate = rate_from_argument(rate)
|
8
8
|
@min_dt = 1.0 / @rate
|
9
|
+
@next_time = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
9
10
|
end
|
10
11
|
|
11
|
-
def call
|
12
|
-
|
13
|
-
@
|
14
|
-
|
12
|
+
def call
|
13
|
+
now = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
14
|
+
delta = @next_time - now
|
15
|
+
Thread.current.agent.sleep(delta) if delta > 0
|
16
|
+
yield self
|
17
|
+
|
18
|
+
loop do
|
19
|
+
@next_time += @min_dt
|
20
|
+
break if @next_time > now
|
21
|
+
end
|
15
22
|
end
|
16
23
|
alias_method :process, :call
|
17
24
|
|
18
25
|
def stop
|
19
|
-
@
|
26
|
+
@stop = true
|
20
27
|
end
|
21
28
|
|
22
29
|
private
|
@@ -31,4 +38,4 @@ module Polyphony
|
|
31
38
|
raise "Invalid rate argument #{arg.inspect}"
|
32
39
|
end
|
33
40
|
end
|
34
|
-
end
|
41
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Polyphony
|
4
|
+
# Event watcher for thread-safe synchronisation
|
5
|
+
class Event
|
6
|
+
def initialize
|
7
|
+
@i, @o = IO.pipe
|
8
|
+
end
|
9
|
+
|
10
|
+
def await
|
11
|
+
Thread.current.agent.read(@i, +'', 8192, false)
|
12
|
+
raise @value if @value.is_a?(Exception)
|
13
|
+
|
14
|
+
@value
|
15
|
+
end
|
16
|
+
|
17
|
+
def await_no_raise
|
18
|
+
Thread.current.agent.read(@i, +'', 8192, false)
|
19
|
+
@value
|
20
|
+
end
|
21
|
+
|
22
|
+
def signal(value = nil)
|
23
|
+
@value = value
|
24
|
+
Thread.current.agent.write(@o, '1')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -8,8 +8,6 @@ require_relative '../core/exceptions'
|
|
8
8
|
|
9
9
|
# Exeption overrides
|
10
10
|
class ::Exception
|
11
|
-
EXIT_EXCEPTION_CLASSES = [::Interrupt, ::SystemExit].freeze
|
12
|
-
|
13
11
|
class << self
|
14
12
|
attr_accessor :__disable_sanitized_backtrace__
|
15
13
|
end
|
@@ -24,7 +22,7 @@ class ::Exception
|
|
24
22
|
|
25
23
|
alias_method :orig_backtrace, :backtrace
|
26
24
|
def backtrace
|
27
|
-
unless @first_backtrace_call
|
25
|
+
unless @first_backtrace_call
|
28
26
|
@first_backtrace_call = true
|
29
27
|
return orig_backtrace
|
30
28
|
end
|
@@ -52,10 +50,13 @@ end
|
|
52
50
|
|
53
51
|
# Overrides for Process
|
54
52
|
module ::Process
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
53
|
+
class << self
|
54
|
+
alias_method :orig_detach, :detach
|
55
|
+
def detach(pid)
|
56
|
+
fiber = spin { Thread.current.agent.waitpid(pid) }
|
57
|
+
fiber.define_singleton_method(:pid) { pid }
|
58
|
+
fiber
|
59
|
+
end
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -67,10 +68,9 @@ module ::Kernel
|
|
67
68
|
def `(cmd)
|
68
69
|
Open3.popen3(cmd) do |i, o, e, _t|
|
69
70
|
i.close
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
o.read
|
71
|
+
err = e.read
|
72
|
+
$stderr << err if err
|
73
|
+
o.read || ''
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -91,6 +91,7 @@ module ::Kernel
|
|
91
91
|
def gets(*_args)
|
92
92
|
if !ARGV.empty? || @gets_fiber
|
93
93
|
@gets_fiber ||= Fiber.new(&ARGV_GETS_LOOP)
|
94
|
+
@gets_fiber.thread = Thread.current
|
94
95
|
result = @gets_fiber.alive? && @gets_fiber.safe_transfer(Fiber.current)
|
95
96
|
return result if result
|
96
97
|
|
@@ -104,14 +105,21 @@ module ::Kernel
|
|
104
105
|
def system(*args)
|
105
106
|
Open3.popen2(*args) do |i, o, _t|
|
106
107
|
i.close
|
107
|
-
|
108
|
-
$stdout << l
|
109
|
-
end
|
108
|
+
pipe_to_eof(o, $stdout)
|
110
109
|
end
|
111
110
|
true
|
112
111
|
rescue SystemCallError
|
113
112
|
nil
|
114
113
|
end
|
114
|
+
|
115
|
+
def pipe_to_eof(src, dest)
|
116
|
+
loop do
|
117
|
+
data = src.readpartial(8192)
|
118
|
+
dest << data
|
119
|
+
rescue EOFError
|
120
|
+
break
|
121
|
+
end
|
122
|
+
end
|
115
123
|
end
|
116
124
|
|
117
125
|
# Override Timeout to use cancel scope
|
@@ -238,7 +238,7 @@ module Polyphony
|
|
238
238
|
@parent = parent
|
239
239
|
@caller = caller
|
240
240
|
@block = block
|
241
|
-
@mailbox =
|
241
|
+
@mailbox = Polyphony::Queue.new
|
242
242
|
__fiber_trace__(:fiber_create, self)
|
243
243
|
schedule
|
244
244
|
end
|
@@ -268,7 +268,7 @@ module Polyphony
|
|
268
268
|
# allows the fiber to be scheduled and to receive messages.
|
269
269
|
def setup_raw
|
270
270
|
@thread = Thread.current
|
271
|
-
@mailbox =
|
271
|
+
@mailbox = Polyphony::Queue.new
|
272
272
|
end
|
273
273
|
|
274
274
|
def setup_main_fiber
|
@@ -277,11 +277,11 @@ module Polyphony
|
|
277
277
|
@thread = Thread.current
|
278
278
|
@running = true
|
279
279
|
@children&.clear
|
280
|
-
@mailbox =
|
280
|
+
@mailbox = Polyphony::Queue.new
|
281
281
|
end
|
282
282
|
|
283
283
|
def restart_self(first_value)
|
284
|
-
@mailbox =
|
284
|
+
@mailbox = Polyphony::Queue.new
|
285
285
|
@when_done_procs = nil
|
286
286
|
@waiting_fibers = nil
|
287
287
|
run(first_value)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'open3'
|
4
4
|
|
5
|
-
# IO
|
5
|
+
# IO class method patches
|
6
6
|
class ::IO
|
7
7
|
class << self
|
8
8
|
alias_method :orig_binread, :binread
|
@@ -72,7 +72,10 @@ class ::IO
|
|
72
72
|
Open3.popen2(cmd) { |_i, o, _t| yield o }
|
73
73
|
end
|
74
74
|
end
|
75
|
+
end
|
75
76
|
|
77
|
+
# IO instance method patches
|
78
|
+
class ::IO
|
76
79
|
# def each(sep = $/, limit = nil, chomp: nil)
|
77
80
|
# sep, limit = $/, sep if sep.is_a?(Integer)
|
78
81
|
# end
|
@@ -93,6 +96,39 @@ class ::IO
|
|
93
96
|
# def getc
|
94
97
|
# end
|
95
98
|
|
99
|
+
alias_method :orig_read, :read
|
100
|
+
def read(len = 1 << 30)
|
101
|
+
@read_buffer ||= +''
|
102
|
+
result = Thread.current.agent.read(self, @read_buffer, len, true)
|
103
|
+
return nil unless result
|
104
|
+
|
105
|
+
already_read = @read_buffer
|
106
|
+
@read_buffer = +''
|
107
|
+
already_read
|
108
|
+
end
|
109
|
+
|
110
|
+
alias_method :orig_readpartial, :read
|
111
|
+
def readpartial(len)
|
112
|
+
@read_buffer ||= +''
|
113
|
+
result = Thread.current.agent.read(self, @read_buffer, len, false)
|
114
|
+
raise EOFError unless result
|
115
|
+
|
116
|
+
already_read = @read_buffer
|
117
|
+
@read_buffer = +''
|
118
|
+
already_read
|
119
|
+
end
|
120
|
+
|
121
|
+
alias_method :orig_write, :write
|
122
|
+
def write(str)
|
123
|
+
Thread.current.agent.write(self, str)
|
124
|
+
end
|
125
|
+
|
126
|
+
alias_method :orig_write_chevron, :<<
|
127
|
+
def <<(str)
|
128
|
+
Thread.current.agent.write(self, str)
|
129
|
+
self
|
130
|
+
end
|
131
|
+
|
96
132
|
alias_method :orig_gets, :gets
|
97
133
|
def gets(sep = $/, _limit = nil, _chomp: nil)
|
98
134
|
if sep.is_a?(Integer)
|
@@ -101,23 +137,17 @@ class ::IO
|
|
101
137
|
end
|
102
138
|
sep_size = sep.bytesize
|
103
139
|
|
104
|
-
@
|
140
|
+
@read_buffer ||= +''
|
105
141
|
|
106
142
|
loop do
|
107
|
-
idx = @
|
108
|
-
return @
|
109
|
-
|
110
|
-
if (data = readpartial(8192))
|
111
|
-
@gets_buffer << data
|
112
|
-
else
|
113
|
-
return nil if @gets_buffer.empty?
|
143
|
+
idx = @read_buffer.index(sep)
|
144
|
+
return @read_buffer.slice!(0, idx + sep_size) if idx
|
114
145
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
146
|
+
data = readpartial(8192)
|
147
|
+
@read_buffer << data
|
148
|
+
rescue EOFError
|
149
|
+
return nil
|
119
150
|
end
|
120
|
-
# orig_gets(sep, limit, chomp: chomp)
|
121
151
|
end
|
122
152
|
|
123
153
|
# def print(*args)
|
@@ -171,16 +201,20 @@ class ::IO
|
|
171
201
|
buf ? readpartial(maxlen, buf) : readpartial(maxlen)
|
172
202
|
end
|
173
203
|
|
174
|
-
|
175
|
-
|
176
|
-
if length
|
177
|
-
return outbuf ? readpartial(length) : readpartial(length, outbuf)
|
178
|
-
end
|
179
|
-
|
180
|
-
until eof?
|
181
|
-
outbuf ||= +''
|
182
|
-
outbuf << readpartial(8192)
|
183
|
-
end
|
184
|
-
outbuf
|
204
|
+
def read_loop(&block)
|
205
|
+
Thread.current.agent.read_loop(self, &block)
|
185
206
|
end
|
207
|
+
|
208
|
+
# alias_method :orig_read, :read
|
209
|
+
# def read(length = nil, outbuf = nil)
|
210
|
+
# if length
|
211
|
+
# return outbuf ? readpartial(length) : readpartial(length, outbuf)
|
212
|
+
# end
|
213
|
+
|
214
|
+
# until eof?
|
215
|
+
# outbuf ||= +''
|
216
|
+
# outbuf << readpartial(8192)
|
217
|
+
# end
|
218
|
+
# outbuf
|
219
|
+
# end
|
186
220
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'openssl'
|
4
|
-
|
5
4
|
require_relative './socket'
|
6
5
|
|
7
6
|
# Open ssl socket helper methods (to make it compatible with Socket API)
|
@@ -18,14 +17,36 @@ class ::OpenSSL::SSL::SSLSocket
|
|
18
17
|
io.reuse_addr
|
19
18
|
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
alias_method :orig_accept, :accept
|
21
|
+
def accept
|
22
|
+
loop do
|
23
|
+
result = accept_nonblock(exception: false)
|
24
|
+
case result
|
25
|
+
when :wait_readable then Thread.current.agent.wait_io(io, false)
|
26
|
+
when :wait_writable then Thread.current.agent.wait_io(io, true)
|
27
|
+
else
|
28
|
+
return result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
alias_method :orig_sysread, :sysread
|
34
|
+
def sysread(maxlen, buf = +'')
|
24
35
|
loop do
|
25
36
|
case (result = read_nonblock(maxlen, buf, exception: false))
|
26
|
-
when :wait_readable then (
|
27
|
-
|
28
|
-
|
37
|
+
when :wait_readable then Thread.current.agent.wait_io(io, false)
|
38
|
+
else return result
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
alias_method :orig_syswrite, :syswrite
|
44
|
+
def syswrite(buf)
|
45
|
+
loop do
|
46
|
+
case (result = write_nonblock(buf, exception: false))
|
47
|
+
when :wait_writable then Thread.current.agent.wait_io(io, true)
|
48
|
+
else
|
49
|
+
return result
|
29
50
|
end
|
30
51
|
end
|
31
52
|
end
|
@@ -39,15 +60,14 @@ class ::OpenSSL::SSL::SSLSocket
|
|
39
60
|
# @sync = osync
|
40
61
|
end
|
41
62
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
63
|
+
def readpartial(maxlen, buf = +'')
|
64
|
+
result = sysread(maxlen, buf)
|
65
|
+
result || (raise EOFError)
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_loop
|
69
|
+
while (data = sysread(8192))
|
70
|
+
yield data
|
51
71
|
end
|
52
72
|
end
|
53
73
|
end
|
@@ -7,14 +7,21 @@ require_relative '../core/thread_pool'
|
|
7
7
|
|
8
8
|
# Socket overrides (eventually rewritten in C)
|
9
9
|
class ::Socket
|
10
|
+
def accept
|
11
|
+
Thread.current.agent.accept(self)
|
12
|
+
end
|
13
|
+
|
10
14
|
NO_EXCEPTION = { exception: false }.freeze
|
11
15
|
|
12
16
|
def connect(remotesockaddr)
|
13
17
|
loop do
|
14
18
|
result = connect_nonblock(remotesockaddr, **NO_EXCEPTION)
|
15
|
-
|
16
|
-
|
17
|
-
|
19
|
+
case result
|
20
|
+
when 0 then return
|
21
|
+
when :wait_writable then Thread.current.agent.wait_io(self, true)
|
22
|
+
else
|
23
|
+
raise IOError
|
24
|
+
end
|
18
25
|
end
|
19
26
|
end
|
20
27
|
|
@@ -22,9 +29,12 @@ class ::Socket
|
|
22
29
|
outbuf ||= +''
|
23
30
|
loop do
|
24
31
|
result = recv_nonblock(maxlen, flags, outbuf, **NO_EXCEPTION)
|
25
|
-
|
26
|
-
|
27
|
-
|
32
|
+
case result
|
33
|
+
when nil then raise IOError
|
34
|
+
when :wait_readable then Thread.current.agent.wait_io(self, false)
|
35
|
+
else
|
36
|
+
return result
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
|
@@ -32,9 +42,12 @@ class ::Socket
|
|
32
42
|
@read_buffer ||= +''
|
33
43
|
loop do
|
34
44
|
result = recvfrom_nonblock(maxlen, flags, @read_buffer, **NO_EXCEPTION)
|
35
|
-
|
36
|
-
|
37
|
-
|
45
|
+
case result
|
46
|
+
when nil then raise IOError
|
47
|
+
when :wait_readable then Thread.current.agent.wait_io(self, false)
|
48
|
+
else
|
49
|
+
return result
|
50
|
+
end
|
38
51
|
end
|
39
52
|
end
|
40
53
|
|
@@ -115,6 +128,11 @@ class ::TCPServer
|
|
115
128
|
|
116
129
|
alias_method :orig_accept, :accept
|
117
130
|
def accept
|
118
|
-
@io
|
131
|
+
@io.accept
|
132
|
+
end
|
133
|
+
|
134
|
+
alias_method :orig_close, :close
|
135
|
+
def close
|
136
|
+
@io.close
|
119
137
|
end
|
120
138
|
end
|