nio4r 0.2.0 → 2.7.5
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 +7 -0
- checksums.yaml.gz.sig +0 -0
- data/ext/libev/Changes +232 -3
- data/ext/libev/LICENSE +2 -1
- data/ext/libev/README +11 -10
- data/ext/libev/ev.c +2249 -473
- data/ext/libev/ev.h +165 -135
- data/ext/libev/ev_epoll.c +68 -36
- data/ext/libev/ev_iouring.c +694 -0
- data/ext/libev/ev_kqueue.c +44 -18
- data/ext/libev/ev_linuxaio.c +620 -0
- data/ext/libev/ev_poll.c +28 -20
- data/ext/libev/ev_port.c +23 -10
- data/ext/libev/ev_select.c +18 -12
- data/ext/libev/ev_vars.h +65 -19
- data/ext/libev/ev_win32.c +16 -7
- data/ext/libev/ev_wrap.h +236 -160
- data/ext/nio4r/.clang-format +16 -0
- data/ext/nio4r/bytebuffer.c +465 -0
- data/ext/nio4r/extconf.rb +44 -35
- data/ext/nio4r/libev.h +3 -4
- data/ext/nio4r/monitor.c +186 -54
- data/ext/nio4r/nio4r.h +17 -23
- data/ext/nio4r/nio4r_ext.c +11 -3
- data/ext/nio4r/org/nio4r/ByteBuffer.java +295 -0
- data/ext/nio4r/org/nio4r/Monitor.java +176 -0
- data/ext/nio4r/org/nio4r/Nio4r.java +104 -0
- data/ext/nio4r/org/nio4r/Selector.java +297 -0
- data/ext/nio4r/selector.c +350 -182
- data/lib/nio/bytebuffer.rb +235 -0
- data/lib/nio/monitor.rb +100 -8
- data/lib/nio/selector.rb +110 -44
- data/lib/nio/version.rb +8 -1
- data/lib/nio.rb +47 -16
- data/lib/nio4r.rb +7 -0
- data/license.md +80 -0
- data/readme.md +91 -0
- data/releases.md +343 -0
- data.tar.gz.sig +2 -0
- metadata +114 -79
- metadata.gz.sig +0 -0
- data/.gitignore +0 -20
- data/.rspec +0 -4
- data/.travis.yml +0 -7
- data/CHANGES.md +0 -10
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -20
- data/README.md +0 -171
- data/Rakefile +0 -9
- data/examples/echo_server.rb +0 -38
- data/ext/libev/README.embed +0 -3
- data/ext/libev/test_libev_win32.c +0 -123
- data/lib/nio/jruby/monitor.rb +0 -42
- data/lib/nio/jruby/selector.rb +0 -135
- data/nio4r.gemspec +0 -22
- data/spec/nio/monitor_spec.rb +0 -46
- data/spec/nio/selector_spec.rb +0 -269
- data/spec/spec_helper.rb +0 -3
- data/tasks/extension.rake +0 -10
- data/tasks/rspec.rake +0 -7
data/lib/nio/jruby/monitor.rb
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
module NIO
|
|
2
|
-
# Monitors watch Channels for specific events
|
|
3
|
-
class Monitor
|
|
4
|
-
attr_accessor :value, :io
|
|
5
|
-
|
|
6
|
-
# :nodoc
|
|
7
|
-
def initialize(io, selection_key)
|
|
8
|
-
@io, @key = io, selection_key
|
|
9
|
-
selection_key.attach self
|
|
10
|
-
@closed = false
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
# Obtain the interests for this monitor
|
|
14
|
-
def interests
|
|
15
|
-
Selector.iops2sym @key.interestOps
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
# What is the IO object ready for?
|
|
19
|
-
def readiness
|
|
20
|
-
Selector.iops2sym @key.readyOps
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Is the IO object readable?
|
|
24
|
-
def readable?
|
|
25
|
-
readiness == :r || readiness == :rw
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Is the IO object writable?
|
|
29
|
-
def writable?
|
|
30
|
-
readiness == :w || readiness == :rw
|
|
31
|
-
end
|
|
32
|
-
alias_method :writeable?, :writable?
|
|
33
|
-
|
|
34
|
-
# Is this monitor closed?
|
|
35
|
-
def closed?; @closed; end
|
|
36
|
-
|
|
37
|
-
# Deactivate this monitor
|
|
38
|
-
def close
|
|
39
|
-
@closed = true
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
data/lib/nio/jruby/selector.rb
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
module NIO
|
|
2
|
-
# Selectors monitor IO objects for events of interest
|
|
3
|
-
class Selector
|
|
4
|
-
java_import "java.nio.channels.Selector"
|
|
5
|
-
java_import "java.nio.channels.SelectionKey"
|
|
6
|
-
|
|
7
|
-
# Convert nio4r interest symbols to Java NIO interest ops
|
|
8
|
-
def self.sym2iops(interest, channel)
|
|
9
|
-
case interest
|
|
10
|
-
when :r
|
|
11
|
-
if channel.validOps & SelectionKey::OP_ACCEPT != 0
|
|
12
|
-
SelectionKey::OP_ACCEPT
|
|
13
|
-
else
|
|
14
|
-
SelectionKey::OP_READ
|
|
15
|
-
end
|
|
16
|
-
when :w
|
|
17
|
-
if channel.respond_to? :connected? and not channel.connected?
|
|
18
|
-
SelectionKey::OP_CONNECT
|
|
19
|
-
else
|
|
20
|
-
SelectionKey::OP_WRITE
|
|
21
|
-
end
|
|
22
|
-
when :rw
|
|
23
|
-
super(:r, channel) | super(:w, channel)
|
|
24
|
-
else raise ArgumentError, "invalid interest type: #{interest}"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Convert Java NIO interest ops to the corresponding Ruby symbols
|
|
29
|
-
def self.iops2sym(interest_ops)
|
|
30
|
-
case interest_ops
|
|
31
|
-
when SelectionKey::OP_READ, SelectionKey::OP_ACCEPT
|
|
32
|
-
:r
|
|
33
|
-
when SelectionKey::OP_WRITE, SelectionKey::OP_CONNECT
|
|
34
|
-
:w
|
|
35
|
-
when SelectionKey::OP_READ | SelectionKey::OP_WRITE
|
|
36
|
-
:rw
|
|
37
|
-
when 0 then nil
|
|
38
|
-
else raise ArgumentError, "unknown interest op combination: 0x#{interest_ops.to_s(16)}"
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
# Create a new NIO::Selector
|
|
43
|
-
def initialize
|
|
44
|
-
@java_selector = Selector.open
|
|
45
|
-
@select_lock = Mutex.new
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Register interest in an IO object with the selector for the given types
|
|
49
|
-
# of events. Valid event types for interest are:
|
|
50
|
-
# * :r - is the IO readable?
|
|
51
|
-
# * :w - is the IO writeable?
|
|
52
|
-
# * :rw - is the IO either readable or writeable?
|
|
53
|
-
def register(io, interest)
|
|
54
|
-
java_channel = io.to_channel
|
|
55
|
-
java_channel.configureBlocking(false)
|
|
56
|
-
interest_ops = self.class.sym2iops(interest, java_channel)
|
|
57
|
-
|
|
58
|
-
begin
|
|
59
|
-
selector_key = java_channel.register @java_selector, interest_ops
|
|
60
|
-
rescue NativeException => ex
|
|
61
|
-
case ex.cause
|
|
62
|
-
when java.lang.IllegalArgumentException
|
|
63
|
-
raise ArgumentError, "invalid interest type for #{java_channel}: #{interest}"
|
|
64
|
-
else raise
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
NIO::Monitor.new(io, selector_key)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
# Deregister the given IO object from the selector
|
|
72
|
-
def deregister(io)
|
|
73
|
-
key = io.to_channel.keyFor(@java_selector)
|
|
74
|
-
return unless key
|
|
75
|
-
|
|
76
|
-
monitor = key.attachment
|
|
77
|
-
monitor.close
|
|
78
|
-
monitor
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Is the given IO object registered with the selector?
|
|
82
|
-
def registered?(io)
|
|
83
|
-
key = io.to_channel.keyFor(@java_selector)
|
|
84
|
-
return unless key
|
|
85
|
-
!key.attachment.closed?
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
# Select which monitors are ready
|
|
89
|
-
def select(timeout = nil)
|
|
90
|
-
selected = []
|
|
91
|
-
ready = select_each(timeout) { |monitor| selected << monitor }
|
|
92
|
-
return unless ready
|
|
93
|
-
|
|
94
|
-
selected
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Iterate across all selectable monitors
|
|
98
|
-
def select_each(timeout = nil)
|
|
99
|
-
@select_lock.synchronize do
|
|
100
|
-
if timeout == 0
|
|
101
|
-
# The Java NIO API thinks zero means you want to BLOCK FOREVER o_O
|
|
102
|
-
# How about we don't block at all instead?
|
|
103
|
-
ready = @java_selector.selectNow
|
|
104
|
-
elsif timeout
|
|
105
|
-
ready = @java_selector.select(timeout * 1000)
|
|
106
|
-
else
|
|
107
|
-
ready = @java_selector.select
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
return unless ready > 0 # timeout or wakeup
|
|
111
|
-
|
|
112
|
-
@java_selector.selectedKeys.each { |key| yield key.attachment }
|
|
113
|
-
@java_selector.selectedKeys.clear
|
|
114
|
-
|
|
115
|
-
ready
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
# Wake up the other thread that's currently blocking on this selector
|
|
120
|
-
def wakeup
|
|
121
|
-
@java_selector.wakeup
|
|
122
|
-
nil
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# Close this selector
|
|
126
|
-
def close
|
|
127
|
-
@java_selector.close
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
# Is this selector closed?
|
|
131
|
-
def closed?
|
|
132
|
-
!@java_selector.isOpen
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
data/nio4r.gemspec
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
require File.expand_path('../lib/nio/version', __FILE__)
|
|
3
|
-
|
|
4
|
-
Gem::Specification.new do |gem|
|
|
5
|
-
gem.authors = ["Tony Arcieri"]
|
|
6
|
-
gem.email = ["tony.arcieri@gmail.com"]
|
|
7
|
-
gem.description = "New IO for Ruby"
|
|
8
|
-
gem.summary = "NIO provides a high performance selector API for monitoring IO objects"
|
|
9
|
-
gem.homepage = "https://github.com/tarcieri/nio4r"
|
|
10
|
-
|
|
11
|
-
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
12
|
-
gem.files = `git ls-files`.split("\n")
|
|
13
|
-
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
14
|
-
gem.name = "nio4r"
|
|
15
|
-
gem.require_paths = ["lib"]
|
|
16
|
-
gem.version = NIO::VERSION
|
|
17
|
-
gem.extensions = ["ext/nio4r/extconf.rb"]
|
|
18
|
-
|
|
19
|
-
gem.add_development_dependency "rake-compiler", "~> 0.7.9"
|
|
20
|
-
gem.add_development_dependency "rake"
|
|
21
|
-
gem.add_development_dependency "rspec", "~> 2.7.0"
|
|
22
|
-
end
|
data/spec/nio/monitor_spec.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
describe NIO::Monitor do
|
|
4
|
-
let :readable do
|
|
5
|
-
reader, writer = IO.pipe
|
|
6
|
-
writer << "have some data"
|
|
7
|
-
reader
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
let :selector do
|
|
11
|
-
NIO::Selector.new
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
# Monitors are created by registering IO objects or channels with a selector
|
|
15
|
-
subject { selector.register(readable, :r) }
|
|
16
|
-
|
|
17
|
-
it "knows its interests" do
|
|
18
|
-
subject.interests.should == :r
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
it "stores arbitrary values" do
|
|
22
|
-
subject.value = 42
|
|
23
|
-
subject.value.should == 42
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
it "knows what IO objects are ready for" do
|
|
27
|
-
# Perhaps let bindings are just confusing me but they're not producing
|
|
28
|
-
# what I want. Manually doing the setup here does
|
|
29
|
-
# FIXME: Hey RSpec wizards! Fix this!
|
|
30
|
-
reader, writer = IO.pipe
|
|
31
|
-
writer << "loldata"
|
|
32
|
-
selector = NIO::Selector.new
|
|
33
|
-
subject = selector.register(reader, :r)
|
|
34
|
-
|
|
35
|
-
# Here's where the spec really begins
|
|
36
|
-
selector.select(1).should include(subject)
|
|
37
|
-
subject.readiness.should == :r
|
|
38
|
-
subject.should be_readable
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it "closes" do
|
|
42
|
-
subject.should_not be_closed
|
|
43
|
-
subject.close
|
|
44
|
-
subject.should be_closed
|
|
45
|
-
end
|
|
46
|
-
end
|
data/spec/nio/selector_spec.rb
DELETED
|
@@ -1,269 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
# Timeouts should be at least this precise (in seconds) to pass the tests
|
|
4
|
-
# Typical precision should be better than this, but if it's worse it will fail
|
|
5
|
-
# the tests
|
|
6
|
-
TIMEOUT_PRECISION = 0.1
|
|
7
|
-
|
|
8
|
-
describe NIO::Selector do
|
|
9
|
-
it "monitors IO objects" do
|
|
10
|
-
pipe, _ = IO.pipe
|
|
11
|
-
|
|
12
|
-
monitor = subject.register(pipe, :r)
|
|
13
|
-
monitor.should_not be_closed
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it "knows which IO objects are registered" do
|
|
17
|
-
reader, writer = IO.pipe
|
|
18
|
-
subject.register(reader, :r)
|
|
19
|
-
|
|
20
|
-
subject.should be_registered(reader)
|
|
21
|
-
subject.should_not be_registered(writer)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
it "deregisters IO objects" do
|
|
25
|
-
pipe, _ = IO.pipe
|
|
26
|
-
|
|
27
|
-
subject.register(pipe, :r)
|
|
28
|
-
monitor = subject.deregister(pipe)
|
|
29
|
-
subject.should_not be_registered(pipe)
|
|
30
|
-
monitor.should be_closed
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
context "select" do
|
|
34
|
-
it "waits for a timeout when selecting" do
|
|
35
|
-
reader, writer = IO.pipe
|
|
36
|
-
monitor = subject.register(reader, :r)
|
|
37
|
-
|
|
38
|
-
payload = "hi there"
|
|
39
|
-
writer << payload
|
|
40
|
-
|
|
41
|
-
timeout = 0.5
|
|
42
|
-
started_at = Time.now
|
|
43
|
-
subject.select(timeout).should include monitor
|
|
44
|
-
(Time.now - started_at).should be_within(TIMEOUT_PRECISION).of(0)
|
|
45
|
-
reader.read_nonblock(payload.size)
|
|
46
|
-
|
|
47
|
-
started_at = Time.now
|
|
48
|
-
subject.select(timeout).should be_nil
|
|
49
|
-
(Time.now - started_at).should be_within(TIMEOUT_PRECISION).of(timeout)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "wakes up if signaled to from another thread" do
|
|
53
|
-
pipe, _ = IO.pipe
|
|
54
|
-
subject.register(pipe, :r)
|
|
55
|
-
|
|
56
|
-
thread = Thread.new do
|
|
57
|
-
started_at = Time.now
|
|
58
|
-
subject.select.should be_nil
|
|
59
|
-
Time.now - started_at
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
timeout = 0.1
|
|
63
|
-
sleep timeout
|
|
64
|
-
subject.wakeup
|
|
65
|
-
|
|
66
|
-
thread.value.should be_within(TIMEOUT_PRECISION).of(timeout)
|
|
67
|
-
end
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
context "select_each" do
|
|
71
|
-
it "iterates across ready selectables" do
|
|
72
|
-
readable1, writer = IO.pipe
|
|
73
|
-
writer << "ohai"
|
|
74
|
-
|
|
75
|
-
readable2, writer = IO.pipe
|
|
76
|
-
writer << "ohai"
|
|
77
|
-
|
|
78
|
-
unreadable, _ = IO.pipe
|
|
79
|
-
|
|
80
|
-
monitor1 = subject.register(readable1, :r)
|
|
81
|
-
monitor2 = subject.register(readable2, :r)
|
|
82
|
-
monitor3 = subject.register(unreadable, :r)
|
|
83
|
-
|
|
84
|
-
readables = []
|
|
85
|
-
subject.select_each { |monitor| readables << monitor }
|
|
86
|
-
|
|
87
|
-
readables.should include(monitor1)
|
|
88
|
-
readables.should include(monitor2)
|
|
89
|
-
readables.should_not include(monitor3)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
it "allows new monitors to be registered in the select_each block" do
|
|
93
|
-
server = TCPServer.new("localhost", 10001)
|
|
94
|
-
|
|
95
|
-
monitor = subject.register(server, :r)
|
|
96
|
-
connector = TCPSocket.open("localhost", 10001)
|
|
97
|
-
|
|
98
|
-
block_fired = false
|
|
99
|
-
subject.select_each do |monitor|
|
|
100
|
-
block_fired = true
|
|
101
|
-
socket = server.accept
|
|
102
|
-
subject.register(socket, :r).should be_a NIO::Monitor
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
block_fired.should be_true
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
it "closes" do
|
|
110
|
-
subject.close
|
|
111
|
-
subject.should be_closed
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
context "selectables" do
|
|
115
|
-
shared_context "an NIO selectable" do
|
|
116
|
-
it "selects for read readiness" do
|
|
117
|
-
waiting_monitor = subject.register(unreadable_subject, :r)
|
|
118
|
-
ready_monitor = subject.register(readable_subject, :r)
|
|
119
|
-
|
|
120
|
-
ready_monitors = subject.select
|
|
121
|
-
ready_monitors.should include ready_monitor
|
|
122
|
-
ready_monitors.should_not include waiting_monitor
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it "selects for write readiness" do
|
|
126
|
-
waiting_monitor = subject.register(unwritable_subject, :w)
|
|
127
|
-
ready_monitor = subject.register(writable_subject, :w)
|
|
128
|
-
|
|
129
|
-
ready_monitors = subject.select(0.1)
|
|
130
|
-
|
|
131
|
-
ready_monitors.should include ready_monitor
|
|
132
|
-
ready_monitors.should_not include waiting_monitor
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
context "IO.pipe" do
|
|
137
|
-
let :readable_subject do
|
|
138
|
-
pipe, peer = IO.pipe
|
|
139
|
-
peer << "data"
|
|
140
|
-
pipe
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
let :unreadable_subject do
|
|
144
|
-
pipe, _ = IO.pipe
|
|
145
|
-
pipe
|
|
146
|
-
end
|
|
147
|
-
|
|
148
|
-
let :writable_subject do
|
|
149
|
-
_, pipe = IO.pipe
|
|
150
|
-
pipe
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
let :unwritable_subject do
|
|
154
|
-
reader, pipe = IO.pipe
|
|
155
|
-
|
|
156
|
-
begin
|
|
157
|
-
pipe.write_nonblock "JUNK IN THE TUBES"
|
|
158
|
-
_, writers = select [], [pipe], [], 0
|
|
159
|
-
rescue Errno::EPIPE
|
|
160
|
-
break
|
|
161
|
-
end while writers and writers.include? pipe
|
|
162
|
-
|
|
163
|
-
pipe
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
it_behaves_like "an NIO selectable"
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
context TCPSocket do
|
|
170
|
-
let(:tcp_port) { 12345 }
|
|
171
|
-
|
|
172
|
-
let :readable_subject do
|
|
173
|
-
server = TCPServer.new("localhost", tcp_port)
|
|
174
|
-
sock = TCPSocket.open("localhost", tcp_port)
|
|
175
|
-
peer = server.accept
|
|
176
|
-
peer << "data"
|
|
177
|
-
sock
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
let :unreadable_subject do
|
|
181
|
-
if defined?(JRUBY_VERSION) and ENV['TRAVIS']
|
|
182
|
-
pending "This is sporadically showing up readable on JRuby in CI"
|
|
183
|
-
else
|
|
184
|
-
TCPServer.new("localhost", tcp_port + 1)
|
|
185
|
-
TCPSocket.open("localhost", tcp_port + 1)
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
let :writable_subject do
|
|
190
|
-
TCPServer.new("localhost", tcp_port + 2)
|
|
191
|
-
TCPSocket.open("localhost", tcp_port + 2)
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
let :unwritable_subject do
|
|
195
|
-
server = TCPServer.new("localhost", tcp_port + 3)
|
|
196
|
-
sock = TCPSocket.open("localhost", tcp_port + 3)
|
|
197
|
-
peer = server.accept
|
|
198
|
-
|
|
199
|
-
begin
|
|
200
|
-
sock.write_nonblock "JUNK IN THE TUBES"
|
|
201
|
-
_, writers = select [], [sock], [], 0
|
|
202
|
-
end while writers and writers.include? sock
|
|
203
|
-
|
|
204
|
-
sock
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
it_behaves_like "an NIO selectable"
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
context UDPSocket do
|
|
211
|
-
let(:udp_port) { 23456 }
|
|
212
|
-
|
|
213
|
-
let :readable_subject do
|
|
214
|
-
sock = UDPSocket.new
|
|
215
|
-
sock.bind('localhost', udp_port)
|
|
216
|
-
|
|
217
|
-
peer = UDPSocket.new
|
|
218
|
-
peer.send("hi there", 0, 'localhost', udp_port)
|
|
219
|
-
|
|
220
|
-
sock
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
let :unreadable_subject do
|
|
224
|
-
sock = UDPSocket.new
|
|
225
|
-
sock.bind('localhost', udp_port + 1)
|
|
226
|
-
sock
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
let :writable_subject do
|
|
230
|
-
pending "come up with a writable UDPSocket example"
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
let :unwritable_subject do
|
|
234
|
-
pending "come up with a UDPSocket that's blocked on writing"
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
it_behaves_like "an NIO selectable"
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
context "acceptables" do
|
|
242
|
-
shared_context "an NIO acceptable" do
|
|
243
|
-
it "selects for read readiness" do
|
|
244
|
-
waiting_monitor = subject.register(unacceptable_subject, :r)
|
|
245
|
-
ready_monitor = subject.register(acceptable_subject, :r)
|
|
246
|
-
|
|
247
|
-
ready_monitors = subject.select
|
|
248
|
-
ready_monitors.should include ready_monitor
|
|
249
|
-
ready_monitors.should_not include waiting_monitor
|
|
250
|
-
end
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
context TCPServer do
|
|
254
|
-
let(:tcp_port) { 23456 }
|
|
255
|
-
|
|
256
|
-
let :acceptable_subject do
|
|
257
|
-
server = TCPServer.new("localhost", tcp_port)
|
|
258
|
-
TCPSocket.open("localhost", tcp_port)
|
|
259
|
-
server
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
let :unacceptable_subject do
|
|
263
|
-
TCPServer.new("localhost", tcp_port + 1)
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
it_behaves_like "an NIO acceptable"
|
|
267
|
-
end
|
|
268
|
-
end
|
|
269
|
-
end
|
data/spec/spec_helper.rb
DELETED
data/tasks/extension.rake
DELETED