nio4r 2.1.0 → 2.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rubocop.yml +22 -2
- data/.travis.yml +3 -2
- data/CHANGES.md +43 -0
- data/Gemfile +2 -2
- data/Guardfile +1 -1
- data/README.md +3 -1
- data/Rakefile +1 -1
- data/appveyor.yml +27 -0
- data/ext/nio4r/bytebuffer.c +12 -4
- data/ext/nio4r/extconf.rb +15 -24
- data/ext/nio4r/monitor.c +2 -2
- data/ext/nio4r/org/nio4r/ByteBuffer.java +1 -3
- data/ext/nio4r/org/nio4r/Monitor.java +6 -0
- data/ext/nio4r/org/nio4r/Selector.java +18 -1
- data/ext/nio4r/selector.c +84 -9
- data/lib/nio.rb +3 -4
- data/lib/nio/bytebuffer.rb +11 -8
- data/lib/nio/monitor.rb +1 -1
- data/lib/nio/selector.rb +10 -1
- data/lib/nio/version.rb +1 -1
- data/nio4r.gemspec +1 -1
- data/spec/nio/acceptables_spec.rb +3 -3
- data/spec/nio/bytebuffer_spec.rb +8 -1
- data/spec/nio/monitor_spec.rb +1 -1
- data/spec/nio/selectables/pipe_spec.rb +7 -2
- data/spec/nio/selectables/ssl_socket_spec.rb +8 -9
- data/spec/nio/selectables/tcp_socket_spec.rb +2 -6
- data/spec/nio/selectables/udp_socket_spec.rb +15 -5
- data/spec/nio/selector_spec.rb +25 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/support/selectable_examples.rb +8 -3
- metadata +6 -6
- data/.ruby-version +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1b801ac687bb5098220b7d2b870f84d172cdcd0683c50175006196e7ab9f5021
|
4
|
+
data.tar.gz: 93301d044d3bb5fe7b7e9db9b1ab7d0b683770a22adda61b6e6ccb60bbe1a137
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 000f6a6ebe2acb74581d0c4976c0fc46ed2ae2baeaea6b18622c7b7105567e3734517429867e9b1bed9df5e8b320430d4dff505f98e817d9c6248eca6a7ccdba
|
7
|
+
data.tar.gz: 988ee869b08ea7d91c5383ee28c505db0e595eec35c98513b3468e1ecec66224894514e352db810cc1143b797c9c6af714ebd3d3eee90291f036e09ad4a28ccd
|
data/.rubocop.yml
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
AllCops:
|
2
|
+
TargetRubyVersion: 2.2
|
2
3
|
DisplayCopNames: true
|
3
4
|
|
4
5
|
#
|
@@ -18,6 +19,9 @@ Lint/Loop:
|
|
18
19
|
Metrics/AbcSize:
|
19
20
|
Max: 35
|
20
21
|
|
22
|
+
Metrics/BlockLength:
|
23
|
+
Max: 128
|
24
|
+
|
21
25
|
Metrics/ClassLength:
|
22
26
|
Max: 128
|
23
27
|
|
@@ -34,12 +38,22 @@ Metrics/CyclomaticComplexity:
|
|
34
38
|
Metrics/PerceivedComplexity:
|
35
39
|
Max: 15
|
36
40
|
|
41
|
+
#
|
42
|
+
# Performance
|
43
|
+
#
|
44
|
+
|
45
|
+
Performance/RegexpMatch:
|
46
|
+
Enabled: false
|
47
|
+
|
37
48
|
#
|
38
49
|
# Style
|
39
50
|
#
|
40
51
|
|
41
|
-
Style/
|
42
|
-
|
52
|
+
Style/FormatStringToken:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Style/FrozenStringLiteralComment:
|
56
|
+
Enabled: true
|
43
57
|
|
44
58
|
Style/GlobalVars:
|
45
59
|
Enabled: false
|
@@ -50,5 +64,11 @@ Style/NumericPredicate:
|
|
50
64
|
Style/RescueModifier:
|
51
65
|
Enabled: false
|
52
66
|
|
67
|
+
Style/SafeNavigation:
|
68
|
+
Enabled: false
|
69
|
+
|
70
|
+
Style/StringLiterals:
|
71
|
+
EnforcedStyle: double_quotes
|
72
|
+
|
53
73
|
Style/TrivialAccessors:
|
54
74
|
Enabled: false
|
data/.travis.yml
CHANGED
@@ -3,7 +3,7 @@ sudo: false
|
|
3
3
|
cache: bundler
|
4
4
|
|
5
5
|
before_install:
|
6
|
-
- gem update --system
|
6
|
+
- gem update --system
|
7
7
|
- gem --version
|
8
8
|
|
9
9
|
bundler_args: --without development
|
@@ -13,10 +13,11 @@ branches:
|
|
13
13
|
- master
|
14
14
|
|
15
15
|
rvm:
|
16
|
-
- jruby-9.1.
|
16
|
+
- jruby-9.1.15.0 # latest stable
|
17
17
|
- 2.2.7
|
18
18
|
- 2.3.4
|
19
19
|
- 2.4.1
|
20
|
+
- 2.5.0
|
20
21
|
- ruby-head
|
21
22
|
|
22
23
|
env:
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,41 @@
|
|
1
|
+
## 2.2.0 (2017-12-27)
|
2
|
+
|
3
|
+
* [#151](https://github.com/socketry/nio4r/pull/151)
|
4
|
+
`NIO::Selector`: Support for enumerating and configuring backend
|
5
|
+
([@tarcieri])
|
6
|
+
|
7
|
+
* [#153](https://github.com/socketry/nio4r/pull/153)
|
8
|
+
Fix builds on Windows
|
9
|
+
([@unak])
|
10
|
+
|
11
|
+
* [#157](https://github.com/socketry/nio4r/pull/157)
|
12
|
+
Windows / MinGW test failure - fix spec_helper.rb
|
13
|
+
([@MSP-Greg])
|
14
|
+
|
15
|
+
* [#162](https://github.com/socketry/nio4r/pull/162)
|
16
|
+
Don't build the C extension on Windows
|
17
|
+
([@larskanis])
|
18
|
+
|
19
|
+
* [#164](https://github.com/socketry/nio4r/pull/164)
|
20
|
+
Fix NIO::ByteBuffer leak
|
21
|
+
([@HoneyryderChuck])
|
22
|
+
|
23
|
+
* [#170](https://github.com/socketry/nio4r/pull/170)
|
24
|
+
Avoid CancelledKeyExceptions on JRuby
|
25
|
+
([@HoneyryderChuck])
|
26
|
+
|
27
|
+
* [#177](https://github.com/socketry/nio4r/pull/177)
|
28
|
+
Fix `NIO::ByteBuffer` string conversions on JRuby
|
29
|
+
([@tarcieri])
|
30
|
+
|
31
|
+
* [#179](https://github.com/socketry/nio4r/pull/179)
|
32
|
+
Fix argument error when running on ruby 2.5.0
|
33
|
+
([@tompng])
|
34
|
+
|
35
|
+
* [#180](https://github.com/socketry/nio4r/pull/180)
|
36
|
+
ext/nio4r/extconf.rb: check for port_event_t in port.h (fixes #178)
|
37
|
+
([@tarcieri])
|
38
|
+
|
1
39
|
## 2.1.0 (2017-05-28)
|
2
40
|
|
3
41
|
* [#130](https://github.com/socketry/nio4r/pull/130)
|
@@ -163,3 +201,8 @@
|
|
163
201
|
[@johnnyt]: https://github.com/johnnyt
|
164
202
|
[@UpeksheJay]: https://github.com/UpeksheJay
|
165
203
|
[@junaruga]: https://github.com/junaruga
|
204
|
+
[@unak]: https://github.com/unak
|
205
|
+
[@MSP-Greg]: https://github.com/MSP-Greg
|
206
|
+
[@larskanis]: https://github.com/larskanis
|
207
|
+
[@HoneyryderChuck]: https://github.com/HoneyryderChuck
|
208
|
+
[@tompng]: https://github.com/tompng
|
data/Gemfile
CHANGED
@@ -14,7 +14,7 @@ end
|
|
14
14
|
group :development, :test do
|
15
15
|
gem "coveralls", require: false
|
16
16
|
gem "rake-compiler", require: false
|
17
|
-
gem "rspec", "~> 3",
|
17
|
+
gem "rspec", "~> 3.7", require: false
|
18
18
|
gem "rspec-retry", require: false
|
19
|
-
gem "rubocop", "0.
|
19
|
+
gem "rubocop", "0.52.1", require: false
|
20
20
|
end
|
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# ![nio4r](https://raw.github.com/socketry/nio4r/master/logo.png)
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/nio4r.svg)](http://rubygems.org/gems/nio4r)
|
4
|
-
[![
|
4
|
+
[![Travis CI Status](https://secure.travis-ci.org/socketry/nio4r.svg?branch=master)](http://travis-ci.org/socketry/nio4r)
|
5
|
+
[![Appveyor Status](https://ci.appveyor.com/api/projects/status/1ru8x81v91vaewax/branch/master?svg=true)](https://ci.appveyor.com/project/tarcieri/nio4r/branch/master)
|
5
6
|
[![Code Climate](https://codeclimate.com/github/socketry/nio4r.svg)](https://codeclimate.com/github/socketry/nio4r)
|
6
7
|
[![Coverage Status](https://coveralls.io/repos/socketry/nio4r/badge.svg?branch=master)](https://coveralls.io/r/socketry/nio4r)
|
8
|
+
[![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/nio4r/2.2.0)
|
7
9
|
[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/socketry/nio4r/blob/master/LICENSE.txt)
|
8
10
|
|
9
11
|
_NOTE: This is the 2.x **stable** branch of nio4r. For the 1.x **legacy** branch,
|
data/Rakefile
CHANGED
data/appveyor.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
branches:
|
2
|
+
only:
|
3
|
+
- master
|
4
|
+
|
5
|
+
environment:
|
6
|
+
PATH: C:\Ruby%RUBY_VERSION%\DevKit\mingw\bin;C:\Ruby%RUBY_VERSION%\bin;C:\Ruby%RUBY_VERSION%\DevKit\bin;%PATH%
|
7
|
+
matrix:
|
8
|
+
- RUBY_VERSION: "24-x64"
|
9
|
+
- RUBY_VERSION: "23-x64"
|
10
|
+
- RUBY_VERSION: "23"
|
11
|
+
- RUBY_VERSION: "22"
|
12
|
+
|
13
|
+
install:
|
14
|
+
- SET RAKEOPT=-rdevkit
|
15
|
+
- ruby -v
|
16
|
+
- gem -v
|
17
|
+
- bundle -v
|
18
|
+
- bundle install
|
19
|
+
|
20
|
+
build: off
|
21
|
+
|
22
|
+
before_build:
|
23
|
+
- gem update --system
|
24
|
+
|
25
|
+
test_script:
|
26
|
+
- echo %PATH%
|
27
|
+
- bundle exec rake spec
|
data/ext/nio4r/bytebuffer.c
CHANGED
@@ -75,6 +75,7 @@ void Init_NIO_ByteBuffer()
|
|
75
75
|
static VALUE NIO_ByteBuffer_allocate(VALUE klass)
|
76
76
|
{
|
77
77
|
struct NIO_ByteBuffer *bytebuffer = (struct NIO_ByteBuffer *)xmalloc(sizeof(struct NIO_ByteBuffer));
|
78
|
+
bytebuffer->buffer = NULL;
|
78
79
|
return Data_Wrap_Struct(klass, NIO_ByteBuffer_gc_mark, NIO_ByteBuffer_free, bytebuffer);
|
79
80
|
}
|
80
81
|
|
@@ -84,6 +85,8 @@ static void NIO_ByteBuffer_gc_mark(struct NIO_ByteBuffer *buffer)
|
|
84
85
|
|
85
86
|
static void NIO_ByteBuffer_free(struct NIO_ByteBuffer *buffer)
|
86
87
|
{
|
88
|
+
if(buffer->buffer)
|
89
|
+
xfree(buffer->buffer);
|
87
90
|
xfree(buffer);
|
88
91
|
}
|
89
92
|
|
@@ -124,10 +127,11 @@ static VALUE NIO_ByteBuffer_get_position(VALUE self)
|
|
124
127
|
|
125
128
|
static VALUE NIO_ByteBuffer_set_position(VALUE self, VALUE new_position)
|
126
129
|
{
|
130
|
+
int pos;
|
127
131
|
struct NIO_ByteBuffer *buffer;
|
128
132
|
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
|
129
133
|
|
130
|
-
|
134
|
+
pos = NUM2INT(new_position);
|
131
135
|
|
132
136
|
if(pos < 0) {
|
133
137
|
rb_raise(rb_eArgError, "negative position given");
|
@@ -156,10 +160,11 @@ static VALUE NIO_ByteBuffer_get_limit(VALUE self)
|
|
156
160
|
|
157
161
|
static VALUE NIO_ByteBuffer_set_limit(VALUE self, VALUE new_limit)
|
158
162
|
{
|
163
|
+
int lim;
|
159
164
|
struct NIO_ByteBuffer *buffer;
|
160
165
|
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
|
161
166
|
|
162
|
-
|
167
|
+
lim = NUM2INT(new_limit);
|
163
168
|
|
164
169
|
if(lim < 0) {
|
165
170
|
rb_raise(rb_eArgError, "negative limit given");
|
@@ -237,10 +242,11 @@ static VALUE NIO_ByteBuffer_get(int argc, VALUE *argv, VALUE self)
|
|
237
242
|
|
238
243
|
static VALUE NIO_ByteBuffer_fetch(VALUE self, VALUE index)
|
239
244
|
{
|
245
|
+
int i;
|
240
246
|
struct NIO_ByteBuffer *buffer;
|
241
247
|
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
|
242
248
|
|
243
|
-
|
249
|
+
i = NUM2INT(index);
|
244
250
|
|
245
251
|
if(i < 0) {
|
246
252
|
rb_raise(rb_eArgError, "negative index given");
|
@@ -255,10 +261,12 @@ static VALUE NIO_ByteBuffer_fetch(VALUE self, VALUE index)
|
|
255
261
|
|
256
262
|
static VALUE NIO_ByteBuffer_put(VALUE self, VALUE string)
|
257
263
|
{
|
264
|
+
long length;
|
258
265
|
struct NIO_ByteBuffer *buffer;
|
259
266
|
Data_Get_Struct(self, struct NIO_ByteBuffer, buffer);
|
260
267
|
|
261
|
-
|
268
|
+
StringValue(string);
|
269
|
+
length = RSTRING_LEN(string);
|
262
270
|
|
263
271
|
if(length > buffer->limit - buffer->position) {
|
264
272
|
rb_raise(cNIO_ByteBuffer_OverflowError, "buffer is full");
|
data/ext/nio4r/extconf.rb
CHANGED
@@ -1,35 +1,26 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "
|
4
|
-
|
5
|
-
have_header("unistd.h")
|
6
|
-
|
7
|
-
$defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
|
3
|
+
require "rubygems"
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
$defs << "-DEV_USE_KQUEUE"
|
5
|
+
# Write a dummy Makefile on Windows because we use the pure Ruby implementation there
|
6
|
+
if Gem.win_platform?
|
7
|
+
File.write("Makefile", "all install::\n")
|
8
|
+
File.write("nio4r_ext.so", "")
|
9
|
+
exit
|
15
10
|
end
|
16
11
|
|
17
|
-
|
12
|
+
require "mkmf"
|
18
13
|
|
14
|
+
have_header("unistd.h")
|
15
|
+
|
16
|
+
$defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
|
17
|
+
$defs << "-DEV_USE_POLL" if have_type("port_event_t", "poll.h")
|
18
|
+
$defs << "-DEV_USE_EPOLL" if have_header("sys/epoll.h")
|
19
|
+
$defs << "-DEV_USE_KQUEUE" if have_header("sys/event.h") && have_header("sys/queue.h")
|
20
|
+
$defs << "-DEV_USE_PORT" if have_type("port_event_t", "port.h")
|
19
21
|
$defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
|
20
22
|
|
21
|
-
CONFIG["optflags"] << " -fno-strict-aliasing"
|
23
|
+
CONFIG["optflags"] << " -fno-strict-aliasing" unless RUBY_PLATFORM =~ /mswin/
|
22
24
|
|
23
25
|
dir_config "nio4r_ext"
|
24
26
|
create_makefile "nio4r_ext"
|
25
|
-
|
26
|
-
# win32 needs to link in "just the right order" for some reason or
|
27
|
-
# ioctlsocket will be mapped to an [inverted] ruby specific version.
|
28
|
-
if RUBY_PLATFORM =~ /mingw|win32/
|
29
|
-
makefile_contents = File.read "Makefile"
|
30
|
-
|
31
|
-
makefile_contents.gsub! "DLDFLAGS = ", "DLDFLAGS = -export-all "
|
32
|
-
|
33
|
-
makefile_contents.gsub! "LIBS = $(LIBRUBYARG_SHARED)", "LIBS = -lws2_32 $(LIBRUBYARG_SHARED)"
|
34
|
-
File.open("Makefile", "w") { |f| f.write makefile_contents }
|
35
|
-
end
|
data/ext/nio4r/monitor.c
CHANGED
@@ -92,7 +92,7 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
|
|
92
92
|
monitor->interests = EV_READ | EV_WRITE;
|
93
93
|
} else {
|
94
94
|
rb_raise(rb_eArgError, "invalid event type %s (must be :r, :w, or :rw)",
|
95
|
-
RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0
|
95
|
+
RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
|
96
96
|
}
|
97
97
|
|
98
98
|
GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
|
@@ -258,7 +258,7 @@ static int NIO_Monitor_symbol2interest(VALUE interests)
|
|
258
258
|
return EV_READ | EV_WRITE;
|
259
259
|
} else {
|
260
260
|
rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
|
261
|
-
RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0
|
261
|
+
RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
|
262
262
|
}
|
263
263
|
}
|
264
264
|
|
@@ -163,10 +163,8 @@ public class ByteBuffer extends RubyObject {
|
|
163
163
|
|
164
164
|
@JRubyMethod(name = "<<")
|
165
165
|
public IRubyObject put(ThreadContext context, IRubyObject str) {
|
166
|
-
String string = str.asJavaString();
|
167
|
-
|
168
166
|
try {
|
169
|
-
this.byteBuffer.put(
|
167
|
+
this.byteBuffer.put(str.convertToString().getByteList().bytes());
|
170
168
|
} catch(BufferOverflowException e) {
|
171
169
|
throw ByteBuffer.newOverflowError(context, "buffer is full");
|
172
170
|
}
|
@@ -102,12 +102,16 @@ public class Monitor extends RubyObject {
|
|
102
102
|
|
103
103
|
@JRubyMethod
|
104
104
|
public IRubyObject readiness(ThreadContext context) {
|
105
|
+
if(!key.isValid())
|
106
|
+
return this.interests;
|
105
107
|
return Nio4r.interestOpsToSymbol(context.getRuntime(), key.readyOps());
|
106
108
|
}
|
107
109
|
|
108
110
|
@JRubyMethod(name = "readable?")
|
109
111
|
public IRubyObject isReadable(ThreadContext context) {
|
110
112
|
Ruby runtime = context.getRuntime();
|
113
|
+
if (!this.key.isValid())
|
114
|
+
return runtime.getTrue();
|
111
115
|
int readyOps = this.key.readyOps();
|
112
116
|
|
113
117
|
if((readyOps & SelectionKey.OP_READ) != 0 || (readyOps & SelectionKey.OP_ACCEPT) != 0) {
|
@@ -120,6 +124,8 @@ public class Monitor extends RubyObject {
|
|
120
124
|
@JRubyMethod(name = {"writable?", "writeable?"})
|
121
125
|
public IRubyObject writable(ThreadContext context) {
|
122
126
|
Ruby runtime = context.getRuntime();
|
127
|
+
if (!this.key.isValid())
|
128
|
+
return runtime.getTrue();
|
123
129
|
int readyOps = this.key.readyOps();
|
124
130
|
|
125
131
|
if((readyOps & SelectionKey.OP_WRITE) != 0 || (readyOps & SelectionKey.OP_CONNECT) != 0) {
|
@@ -7,6 +7,7 @@ import java.io.IOException;
|
|
7
7
|
import java.nio.channels.Channel;
|
8
8
|
import java.nio.channels.SelectableChannel;
|
9
9
|
import java.nio.channels.SelectionKey;
|
10
|
+
import java.nio.channels.CancelledKeyException;
|
10
11
|
|
11
12
|
import org.jruby.Ruby;
|
12
13
|
import org.jruby.RubyArray;
|
@@ -30,8 +31,23 @@ public class Selector extends RubyObject {
|
|
30
31
|
super(ruby, rubyClass);
|
31
32
|
}
|
32
33
|
|
34
|
+
@JRubyMethod(meta = true)
|
35
|
+
public static IRubyObject backends(ThreadContext context, IRubyObject self) {
|
36
|
+
return context.runtime.newArray(context.runtime.newSymbol("java"));
|
37
|
+
}
|
38
|
+
|
33
39
|
@JRubyMethod
|
34
40
|
public IRubyObject initialize(ThreadContext context) {
|
41
|
+
initialize(context, context.runtime.newSymbol("java"));
|
42
|
+
return context.nil;
|
43
|
+
}
|
44
|
+
|
45
|
+
@JRubyMethod
|
46
|
+
public IRubyObject initialize(ThreadContext context, IRubyObject backend) {
|
47
|
+
if(backend != context.runtime.newSymbol("java")) {
|
48
|
+
throw context.runtime.newArgumentError(":java is the only supported backend");
|
49
|
+
}
|
50
|
+
|
35
51
|
this.cancelledKeys = new HashMap<SelectableChannel,SelectionKey>();
|
36
52
|
this.wakeupFired = false;
|
37
53
|
|
@@ -193,6 +209,7 @@ public class Selector extends RubyObject {
|
|
193
209
|
while(selectedKeys.hasNext()) {
|
194
210
|
SelectionKey key = (SelectionKey)selectedKeys.next();
|
195
211
|
processKey(key);
|
212
|
+
|
196
213
|
selectedKeys.remove();
|
197
214
|
|
198
215
|
if(block.isGiven()) {
|
@@ -254,7 +271,7 @@ public class Selector extends RubyObject {
|
|
254
271
|
// Remove connect interest from connected sockets
|
255
272
|
// See: http://stackoverflow.com/questions/204186/java-nio-select-returns-without-selected-keys-why
|
256
273
|
private void processKey(SelectionKey key) {
|
257
|
-
if((key.readyOps() & SelectionKey.OP_CONNECT) != 0) {
|
274
|
+
if(key.isValid() && (key.readyOps() & SelectionKey.OP_CONNECT) != 0) {
|
258
275
|
int interestOps = key.interestOps();
|
259
276
|
|
260
277
|
interestOps &= ~SelectionKey.OP_CONNECT;
|
data/ext/nio4r/selector.c
CHANGED
@@ -27,8 +27,11 @@ static void NIO_Selector_mark(struct NIO_Selector *loop);
|
|
27
27
|
static void NIO_Selector_shutdown(struct NIO_Selector *selector);
|
28
28
|
static void NIO_Selector_free(struct NIO_Selector *loop);
|
29
29
|
|
30
|
-
/*
|
31
|
-
static VALUE
|
30
|
+
/* Class methods */
|
31
|
+
static VALUE NIO_Selector_supported_backends(VALUE klass);
|
32
|
+
|
33
|
+
/* Instance methods */
|
34
|
+
static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self);
|
32
35
|
static VALUE NIO_Selector_backend(VALUE self);
|
33
36
|
static VALUE NIO_Selector_register(VALUE self, VALUE selectable, VALUE interest);
|
34
37
|
static VALUE NIO_Selector_deregister(VALUE self, VALUE io);
|
@@ -65,7 +68,8 @@ void Init_NIO_Selector()
|
|
65
68
|
cNIO_Selector = rb_define_class_under(mNIO, "Selector", rb_cObject);
|
66
69
|
rb_define_alloc_func(cNIO_Selector, NIO_Selector_allocate);
|
67
70
|
|
68
|
-
|
71
|
+
rb_define_singleton_method(cNIO_Selector, "backends", NIO_Selector_supported_backends, 0);
|
72
|
+
rb_define_method(cNIO_Selector, "initialize", NIO_Selector_initialize, -1);
|
69
73
|
rb_define_method(cNIO_Selector, "backend", NIO_Selector_backend, 0);
|
70
74
|
rb_define_method(cNIO_Selector, "register", NIO_Selector_register, 2);
|
71
75
|
rb_define_method(cNIO_Selector, "deregister", NIO_Selector_deregister, 1);
|
@@ -102,7 +106,9 @@ static VALUE NIO_Selector_allocate(VALUE klass)
|
|
102
106
|
}
|
103
107
|
|
104
108
|
selector = (struct NIO_Selector *)xmalloc(sizeof(struct NIO_Selector));
|
105
|
-
|
109
|
+
|
110
|
+
/* Defer initializing the loop to #initialize */
|
111
|
+
selector->ev_loop = 0;
|
106
112
|
|
107
113
|
ev_init(&selector->timer, NIO_Selector_timeout_callback);
|
108
114
|
|
@@ -112,8 +118,6 @@ static VALUE NIO_Selector_allocate(VALUE klass)
|
|
112
118
|
ev_io_init(&selector->wakeup, NIO_Selector_wakeup_callback, selector->wakeup_reader, EV_READ);
|
113
119
|
selector->wakeup.data = (void *)selector;
|
114
120
|
|
115
|
-
ev_io_start(selector->ev_loop, &selector->wakeup);
|
116
|
-
|
117
121
|
selector->closed = selector->selecting = selector->wakeup_fired = selector->ready_count = 0;
|
118
122
|
selector->ready_array = Qnil;
|
119
123
|
|
@@ -154,12 +158,83 @@ static void NIO_Selector_free(struct NIO_Selector *selector)
|
|
154
158
|
xfree(selector);
|
155
159
|
}
|
156
160
|
|
161
|
+
/* Return an array of symbols for supported backends */
|
162
|
+
static VALUE NIO_Selector_supported_backends(VALUE klass) {
|
163
|
+
unsigned int backends = ev_supported_backends();
|
164
|
+
VALUE result = rb_ary_new();
|
165
|
+
|
166
|
+
if(backends & EVBACKEND_EPOLL) {
|
167
|
+
rb_ary_push(result, ID2SYM(rb_intern("epoll")));
|
168
|
+
}
|
169
|
+
|
170
|
+
if(backends & EVBACKEND_POLL) {
|
171
|
+
rb_ary_push(result, ID2SYM(rb_intern("poll")));
|
172
|
+
}
|
173
|
+
|
174
|
+
if(backends & EVBACKEND_KQUEUE) {
|
175
|
+
rb_ary_push(result, ID2SYM(rb_intern("kqueue")));
|
176
|
+
}
|
177
|
+
|
178
|
+
if(backends & EVBACKEND_SELECT) {
|
179
|
+
rb_ary_push(result, ID2SYM(rb_intern("select")));
|
180
|
+
}
|
181
|
+
|
182
|
+
if(backends & EVBACKEND_PORT) {
|
183
|
+
rb_ary_push(result, ID2SYM(rb_intern("port")));
|
184
|
+
}
|
185
|
+
|
186
|
+
return result;
|
187
|
+
}
|
188
|
+
|
157
189
|
/* Create a new selector. This is more or less the pure Ruby version
|
158
190
|
translated into an MRI cext */
|
159
|
-
static VALUE NIO_Selector_initialize(VALUE self)
|
191
|
+
static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
|
160
192
|
{
|
193
|
+
ID backend_id;
|
194
|
+
VALUE backend;
|
161
195
|
VALUE lock;
|
162
196
|
|
197
|
+
struct NIO_Selector *selector;
|
198
|
+
unsigned int flags = 0;
|
199
|
+
|
200
|
+
Data_Get_Struct(self, struct NIO_Selector, selector);
|
201
|
+
|
202
|
+
rb_scan_args(argc, argv, "01", &backend);
|
203
|
+
|
204
|
+
if(backend != Qnil) {
|
205
|
+
if(!rb_ary_includes(NIO_Selector_supported_backends(CLASS_OF(self)), backend)) {
|
206
|
+
rb_raise(rb_eArgError, "unsupported backend: %s",
|
207
|
+
RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
|
208
|
+
}
|
209
|
+
|
210
|
+
backend_id = SYM2ID(backend);
|
211
|
+
|
212
|
+
if(backend_id == rb_intern("epoll")) {
|
213
|
+
flags = EVBACKEND_EPOLL;
|
214
|
+
} else if(backend_id == rb_intern("poll")) {
|
215
|
+
flags = EVBACKEND_POLL;
|
216
|
+
} else if(backend_id == rb_intern("kqueue")) {
|
217
|
+
flags = EVBACKEND_KQUEUE;
|
218
|
+
} else if(backend_id == rb_intern("select")) {
|
219
|
+
flags = EVBACKEND_SELECT;
|
220
|
+
} else if(backend_id == rb_intern("port")) {
|
221
|
+
flags = EVBACKEND_PORT;
|
222
|
+
} else {
|
223
|
+
rb_raise(rb_eArgError, "unsupported backend: %s",
|
224
|
+
RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
/* Ensure the selector loop has not yet been initialized */
|
229
|
+
assert(!selector->ev_loop);
|
230
|
+
|
231
|
+
selector->ev_loop = ev_loop_new(flags);
|
232
|
+
if(!selector->ev_loop) {
|
233
|
+
rb_raise(rb_eIOError, "error initializing event loop");
|
234
|
+
}
|
235
|
+
|
236
|
+
ev_io_start(selector->ev_loop, &selector->wakeup);
|
237
|
+
|
163
238
|
rb_ivar_set(self, rb_intern("selectables"), rb_hash_new());
|
164
239
|
rb_ivar_set(self, rb_intern("lock_holder"), Qnil);
|
165
240
|
|
@@ -204,7 +279,7 @@ static VALUE NIO_Selector_synchronize(VALUE self, VALUE (*func)(VALUE *args), VA
|
|
204
279
|
|
205
280
|
if(lock_holder != current_thread) {
|
206
281
|
lock = rb_ivar_get(self, rb_intern("lock"));
|
207
|
-
rb_funcall(lock, rb_intern("lock"), 0
|
282
|
+
rb_funcall(lock, rb_intern("lock"), 0);
|
208
283
|
rb_ivar_set(self, rb_intern("lock_holder"), current_thread);
|
209
284
|
|
210
285
|
/* We've acquired the lock, so ensure we unlock it */
|
@@ -223,7 +298,7 @@ static VALUE NIO_Selector_unlock(VALUE self)
|
|
223
298
|
rb_ivar_set(self, rb_intern("lock_holder"), Qnil);
|
224
299
|
|
225
300
|
lock = rb_ivar_get(self, rb_intern("lock"));
|
226
|
-
rb_funcall(lock, rb_intern("unlock"), 0
|
301
|
+
rb_funcall(lock, rb_intern("unlock"), 0);
|
227
302
|
|
228
303
|
return Qnil;
|
229
304
|
}
|
data/lib/nio.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "thread"
|
4
3
|
require "socket"
|
5
4
|
require "nio/version"
|
6
5
|
|
@@ -19,7 +18,7 @@ if ENV["NIO4R_PURE"] == "true" || (Gem.win_platform? && !defined?(JRUBY_VERSION)
|
|
19
18
|
require "nio/monitor"
|
20
19
|
require "nio/selector"
|
21
20
|
require "nio/bytebuffer"
|
22
|
-
NIO::ENGINE = "ruby"
|
21
|
+
NIO::ENGINE = "ruby".freeze
|
23
22
|
else
|
24
23
|
require "nio4r_ext"
|
25
24
|
|
@@ -27,8 +26,8 @@ else
|
|
27
26
|
require "java"
|
28
27
|
require "jruby"
|
29
28
|
org.nio4r.Nio4r.new.load(JRuby.runtime, false)
|
30
|
-
NIO::ENGINE = "java"
|
29
|
+
NIO::ENGINE = "java".freeze
|
31
30
|
else
|
32
|
-
NIO::ENGINE = "libev"
|
31
|
+
NIO::ENGINE = "libev".freeze
|
33
32
|
end
|
34
33
|
end
|
data/lib/nio/bytebuffer.rb
CHANGED
@@ -48,10 +48,8 @@ module NIO
|
|
48
48
|
raise ArgumentError, "negative position given" if new_position < 0
|
49
49
|
raise ArgumentError, "specified position exceeds capacity" if new_position > @capacity
|
50
50
|
|
51
|
+
@mark = nil if @mark && @mark > new_position
|
51
52
|
@position = new_position
|
52
|
-
@mark = nil if @mark && @mark > @position
|
53
|
-
|
54
|
-
new_position
|
55
53
|
end
|
56
54
|
|
57
55
|
# Set the limit to the given value. New limit must be less than capacity.
|
@@ -65,11 +63,9 @@ module NIO
|
|
65
63
|
raise ArgumentError, "negative limit given" if new_limit < 0
|
66
64
|
raise ArgumentError, "specified limit exceeds capacity" if new_limit > @capacity
|
67
65
|
|
66
|
+
@position = new_limit if @position > new_limit
|
67
|
+
@mark = nil if @mark && @mark > new_limit
|
68
68
|
@limit = new_limit
|
69
|
-
@position = new_limit if @position > @limit
|
70
|
-
@mark = nil if @mark && @mark > @limit
|
71
|
-
|
72
|
-
new_limit
|
73
69
|
end
|
74
70
|
|
75
71
|
# Number of bytes remaining in the buffer before the limit
|
@@ -115,15 +111,22 @@ module NIO
|
|
115
111
|
|
116
112
|
# Add a String to the buffer
|
117
113
|
#
|
114
|
+
# @param str [#to_str] data to add to the buffer
|
115
|
+
#
|
116
|
+
# @raise [TypeError] given a non-string type
|
118
117
|
# @raise [NIO::ByteBuffer::OverflowError] buffer is full
|
119
118
|
#
|
120
119
|
# @return [self]
|
121
|
-
def
|
120
|
+
def put(str)
|
121
|
+
raise TypeError, "expected String, got #{str.class}" unless str.respond_to?(:to_str)
|
122
|
+
str = str.to_str
|
123
|
+
|
122
124
|
raise OverflowError, "buffer is full" if str.length > @limit - @position
|
123
125
|
@buffer[@position...str.length] = str
|
124
126
|
@position += str.length
|
125
127
|
self
|
126
128
|
end
|
129
|
+
alias << put
|
127
130
|
|
128
131
|
# Perform a non-blocking read from the given IO object into the buffer
|
129
132
|
# Reads as much data as is immediately available and returns
|
data/lib/nio/monitor.rb
CHANGED
@@ -31,7 +31,7 @@ module NIO
|
|
31
31
|
# @return [Symbol] new interests
|
32
32
|
def interests=(interests)
|
33
33
|
raise EOFError, "monitor is closed" if closed?
|
34
|
-
raise ArgumentError, "bad interests: #{interests}" unless [
|
34
|
+
raise ArgumentError, "bad interests: #{interests}" unless %i[r w rw].include?(interests)
|
35
35
|
|
36
36
|
@interests = interests
|
37
37
|
end
|
data/lib/nio/selector.rb
CHANGED
@@ -5,8 +5,17 @@ require "set"
|
|
5
5
|
module NIO
|
6
6
|
# Selectors monitor IO objects for events of interest
|
7
7
|
class Selector
|
8
|
+
# Return supported backends as symbols
|
9
|
+
#
|
10
|
+
# See `#backend` method definition for all possible backends
|
11
|
+
def self.backends
|
12
|
+
[:ruby]
|
13
|
+
end
|
14
|
+
|
8
15
|
# Create a new NIO::Selector
|
9
|
-
def initialize
|
16
|
+
def initialize(backend = :ruby)
|
17
|
+
raise ArgumentError, "unsupported backend: #{backend}" unless backend == :ruby
|
18
|
+
|
10
19
|
@selectables = {}
|
11
20
|
@lock = Mutex.new
|
12
21
|
|
data/lib/nio/version.rb
CHANGED
data/nio4r.gemspec
CHANGED
@@ -20,13 +20,13 @@ RSpec.describe "NIO acceptables" do
|
|
20
20
|
let(:port) { next_available_tcp_port }
|
21
21
|
|
22
22
|
let :acceptable_subject do
|
23
|
-
server = TCPServer.new("
|
24
|
-
TCPSocket.open("
|
23
|
+
server = TCPServer.new("127.0.0.1", port)
|
24
|
+
TCPSocket.open("127.0.0.1", port)
|
25
25
|
server
|
26
26
|
end
|
27
27
|
|
28
28
|
let :unacceptable_subject do
|
29
|
-
TCPServer.new("
|
29
|
+
TCPServer.new("127.0.0.1", port + 1)
|
30
30
|
end
|
31
31
|
|
32
32
|
it_behaves_like "an NIO acceptable"
|
data/spec/nio/bytebuffer_spec.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
+
# rubocop:disable Metrics/BlockLength
|
5
6
|
RSpec.describe NIO::ByteBuffer do
|
6
7
|
let(:capacity) { 256 }
|
7
8
|
let(:example_string) { "Testing 1 2 3..." }
|
@@ -179,6 +180,11 @@ RSpec.describe NIO::ByteBuffer do
|
|
179
180
|
expect(bytebuffer.limit).to eq capacity
|
180
181
|
end
|
181
182
|
|
183
|
+
it "raises TypeError if given a non-String type" do
|
184
|
+
expect { bytebuffer << 42 }.to raise_error(TypeError)
|
185
|
+
expect { bytebuffer << nil }.to raise_error(TypeError)
|
186
|
+
end
|
187
|
+
|
182
188
|
it "raises NIO::ByteBuffer::OverflowError if the buffer is full" do
|
183
189
|
bytebuffer << "X" * (capacity - 1)
|
184
190
|
expect { bytebuffer << "X" }.not_to raise_error
|
@@ -281,7 +287,7 @@ RSpec.describe NIO::ByteBuffer do
|
|
281
287
|
end
|
282
288
|
|
283
289
|
context "I/O" do
|
284
|
-
let(:addr) { "
|
290
|
+
let(:addr) { "127.0.0.1" }
|
285
291
|
let(:port) { next_available_tcp_port }
|
286
292
|
let(:server) { TCPServer.new(addr, port) }
|
287
293
|
let(:client) { TCPSocket.new(addr, port) }
|
@@ -347,3 +353,4 @@ RSpec.describe NIO::ByteBuffer do
|
|
347
353
|
end
|
348
354
|
end
|
349
355
|
end
|
356
|
+
# rubocop:enable Metrics/BlockLength
|
data/spec/nio/monitor_spec.rb
CHANGED
@@ -27,12 +27,17 @@ RSpec.describe "IO.pipe" do
|
|
27
27
|
# will throw EAGAIN if there is too little space to write the string
|
28
28
|
# TODO: Use FFI to lookup the platform-specific size of PIPE_BUF
|
29
29
|
str = "JUNK IN THE TUBES" * 10_000
|
30
|
+
cntr = 0
|
30
31
|
begin
|
31
32
|
pipe.write_nonblock str
|
32
|
-
|
33
|
+
cntr += 1
|
34
|
+
t = select [], [pipe], [], 0
|
33
35
|
rescue Errno::EPIPE
|
34
36
|
break
|
35
|
-
|
37
|
+
rescue IO::EWOULDBLOCKWaitWritable
|
38
|
+
skip "windows - can't test due to 'select' not showing correct status"
|
39
|
+
break
|
40
|
+
end while t && t[1].include?(pipe) && cntr < 20
|
36
41
|
|
37
42
|
pipe
|
38
43
|
end
|
@@ -4,23 +4,23 @@ require "spec_helper"
|
|
4
4
|
require "openssl"
|
5
5
|
|
6
6
|
RSpec.describe OpenSSL::SSL::SSLSocket do
|
7
|
-
let(:addr) { "
|
7
|
+
let(:addr) { "127.0.0.1" }
|
8
8
|
let(:port) { next_available_tcp_port }
|
9
9
|
|
10
10
|
let(:ssl_key) { OpenSSL::PKey::RSA.new(1024) }
|
11
11
|
|
12
12
|
let(:ssl_cert) do
|
13
|
-
name = OpenSSL::X509::Name.new([%w
|
13
|
+
name = OpenSSL::X509::Name.new([%w[CN 127.0.0.1]])
|
14
14
|
OpenSSL::X509::Certificate.new.tap do |cert|
|
15
15
|
cert.version = 2
|
16
16
|
cert.serial = 1
|
17
17
|
cert.issuer = name
|
18
18
|
cert.subject = name
|
19
19
|
cert.not_before = Time.now
|
20
|
-
cert.not_after = Time.now + (
|
20
|
+
cert.not_after = Time.now + (7 * 24 * 60 * 60)
|
21
21
|
cert.public_key = ssl_key.public_key
|
22
22
|
|
23
|
-
cert.sign(ssl_key, OpenSSL::Digest::
|
23
|
+
cert.sign(ssl_key, OpenSSL::Digest::SHA256.new)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
@@ -111,14 +111,15 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
111
111
|
ssl_peer.accept
|
112
112
|
thread.join
|
113
113
|
|
114
|
+
cntr = 0
|
114
115
|
begin
|
115
|
-
_, writers = select [], [ssl_client], [], 0
|
116
116
|
count = ssl_client.write_nonblock "X" * 1024
|
117
117
|
expect(count).not_to eq(0)
|
118
|
+
cntr += 1
|
119
|
+
t = select [], [ssl_client], [], 0
|
118
120
|
rescue IO::WaitReadable, IO::WaitWritable
|
119
121
|
pending "SSL will report writable but not accept writes"
|
120
|
-
|
121
|
-
end while writers && writers.include?(ssl_client)
|
122
|
+
end while t && t[1].include?(ssl_client) && cntr < 30
|
122
123
|
|
123
124
|
# I think the kernel might manage to drain its buffer a bit even after
|
124
125
|
# the socket first goes unwritable. Attempt to sleep past this and then
|
@@ -141,8 +142,6 @@ RSpec.describe OpenSSL::SSL::SSLSocket do
|
|
141
142
|
end
|
142
143
|
|
143
144
|
let :pair do
|
144
|
-
pending "figure out why newly created sockets are selecting readable immediately"
|
145
|
-
|
146
145
|
server = TCPServer.new(addr, port)
|
147
146
|
client = TCPSocket.new(addr, port)
|
148
147
|
peer = server.accept
|
@@ -19,9 +19,7 @@ RSpec.describe TCPSocket do
|
|
19
19
|
sock = TCPSocket.new(addr, port)
|
20
20
|
|
21
21
|
# Sanity check to make sure we actually produced an unreadable socket
|
22
|
-
if select([sock], [], [], 0)
|
23
|
-
pending "Failed to produce an unreadable socket"
|
24
|
-
end
|
22
|
+
pending "Failed to produce an unreadable socket" if select([sock], [], [], 0)
|
25
23
|
|
26
24
|
sock
|
27
25
|
end
|
@@ -57,9 +55,7 @@ RSpec.describe TCPSocket do
|
|
57
55
|
end
|
58
56
|
|
59
57
|
# Sanity check to make sure we actually produced an unwritable socket
|
60
|
-
if select([], [sock], [], 0)
|
61
|
-
pending "Failed to produce an unwritable socket"
|
62
|
-
end
|
58
|
+
pending "Failed to produce an unwritable socket" if select([], [sock], [], 0)
|
63
59
|
|
64
60
|
sock
|
65
61
|
end
|
@@ -2,27 +2,37 @@
|
|
2
2
|
|
3
3
|
require "spec_helper"
|
4
4
|
|
5
|
-
RSpec.describe UDPSocket do
|
5
|
+
RSpec.describe UDPSocket, if: !defined?(JRUBY_VERSION) do
|
6
6
|
let(:udp_port) { 23_456 }
|
7
7
|
|
8
8
|
let :readable_subject do
|
9
9
|
sock = UDPSocket.new
|
10
|
-
sock.bind("
|
10
|
+
sock.bind("127.0.0.1", udp_port)
|
11
11
|
|
12
12
|
peer = UDPSocket.new
|
13
|
-
peer.send("hi there", 0, "
|
13
|
+
peer.send("hi there", 0, "127.0.0.1", udp_port)
|
14
14
|
|
15
15
|
sock
|
16
16
|
end
|
17
17
|
|
18
18
|
let :unreadable_subject do
|
19
19
|
sock = UDPSocket.new
|
20
|
-
sock.bind("
|
20
|
+
sock.bind("127.0.0.1", udp_port + 1)
|
21
21
|
sock
|
22
22
|
end
|
23
23
|
|
24
24
|
let :writable_subject do
|
25
|
-
|
25
|
+
peer = UDPSocket.new
|
26
|
+
peer.connect "127.0.0.1", udp_port
|
27
|
+
cntr = 0
|
28
|
+
begin
|
29
|
+
peer.send("X" * 1024, 0)
|
30
|
+
cntr += 1
|
31
|
+
t = select [], [peer], [], 0
|
32
|
+
rescue Errno::ECONNREFUSED => ex
|
33
|
+
skip "Couln't make writable UDPSocket subject: #{ex.class}: #{ex}"
|
34
|
+
end while t && t[1].include?(peer) && cntr < 5
|
35
|
+
peer
|
26
36
|
end
|
27
37
|
|
28
38
|
let :unwritable_subject do
|
data/spec/nio/selector_spec.rb
CHANGED
@@ -8,11 +8,35 @@ require "timeout"
|
|
8
8
|
# the tests
|
9
9
|
TIMEOUT_PRECISION = 0.1
|
10
10
|
|
11
|
+
# rubocop:disable Metrics/BlockLength
|
11
12
|
RSpec.describe NIO::Selector do
|
12
13
|
let(:pair) { IO.pipe }
|
13
14
|
let(:reader) { pair.first }
|
14
15
|
let(:writer) { pair.last }
|
15
16
|
|
17
|
+
context ".backends" do
|
18
|
+
it "knows all supported backends" do
|
19
|
+
expect(described_class.backends).to be_a Array
|
20
|
+
expect(described_class.backends.first).to be_a Symbol
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "#initialize" do
|
25
|
+
it "allows explicitly specifying a backend" do
|
26
|
+
backend = described_class.backends.first
|
27
|
+
selector = described_class.new(backend)
|
28
|
+
expect(selector.backend).to eq backend
|
29
|
+
end
|
30
|
+
|
31
|
+
it "raises ArgumentError if given an invalid backend" do
|
32
|
+
expect { described_class.new(:derp) }.to raise_error ArgumentError
|
33
|
+
end
|
34
|
+
|
35
|
+
it "raises TypeError if given a non-Symbol parameter" do
|
36
|
+
expect { described_class.new(42).to raise_error TypeError }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
16
40
|
context "backend" do
|
17
41
|
it "knows its backend" do
|
18
42
|
expect(subject.backend).to be_a Symbol
|
@@ -191,3 +215,4 @@ RSpec.describe NIO::Selector do
|
|
191
215
|
expect(subject).to be_closed
|
192
216
|
end
|
193
217
|
end
|
218
|
+
# rubocop:enable Metrics/BlockLength
|
data/spec/spec_helper.rb
CHANGED
@@ -20,8 +20,8 @@ def next_available_tcp_port
|
|
20
20
|
$current_tcp_port += 1
|
21
21
|
|
22
22
|
begin
|
23
|
-
sock = Timeout.timeout(
|
24
|
-
rescue Errno::ECONNREFUSED
|
23
|
+
sock = Timeout.timeout(0.5) { TCPSocket.new("127.0.0.1", $current_tcp_port) }
|
24
|
+
rescue Errno::ECONNREFUSED, Timeout::Error
|
25
25
|
break $current_tcp_port
|
26
26
|
end
|
27
27
|
|
@@ -34,9 +34,6 @@ RSpec.shared_context "an NIO selectable stream" do
|
|
34
34
|
let(:peer) { pair.last }
|
35
35
|
|
36
36
|
it "selects readable when the other end closes" do
|
37
|
-
# hax: this test is broken for OpenSSL sockets
|
38
|
-
skip "broken for SSL ;_;" if peer.is_a? OpenSSL::SSL::SSLSocket
|
39
|
-
|
40
37
|
monitor = selector.register(stream, :r)
|
41
38
|
expect(selector.select(0)).to be_nil
|
42
39
|
|
@@ -57,4 +54,12 @@ RSpec.shared_context "an NIO bidirectional stream" do
|
|
57
54
|
expect(m.readiness).to eq(:rw)
|
58
55
|
end
|
59
56
|
end
|
57
|
+
it "keeps readiness after the selectable has been closed" do
|
58
|
+
selector.register(readable_subject, :rw)
|
59
|
+
selector.select(0) do |m|
|
60
|
+
expect(m.readiness).to eq(:rw)
|
61
|
+
readable_subject.close
|
62
|
+
expect(m.readiness).to eq(:rw)
|
63
|
+
end
|
64
|
+
end
|
60
65
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nio4r
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tony Arcieri
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-12-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -25,7 +25,7 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
@@ -50,7 +50,6 @@ files:
|
|
50
50
|
- ".gitignore"
|
51
51
|
- ".rspec"
|
52
52
|
- ".rubocop.yml"
|
53
|
-
- ".ruby-version"
|
54
53
|
- ".travis.yml"
|
55
54
|
- CHANGES.md
|
56
55
|
- Gemfile
|
@@ -58,6 +57,7 @@ files:
|
|
58
57
|
- LICENSE.txt
|
59
58
|
- README.md
|
60
59
|
- Rakefile
|
60
|
+
- appveyor.yml
|
61
61
|
- examples/echo_server.rb
|
62
62
|
- ext/libev/Changes
|
63
63
|
- ext/libev/LICENSE
|
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
127
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.
|
128
|
+
rubygems_version: 2.7.3
|
129
129
|
signing_key:
|
130
130
|
specification_version: 4
|
131
131
|
summary: New IO for Ruby
|
data/.ruby-version
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
2.4.0
|