nio4r 1.1.0 → 1.2.0

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.
data/ext/libev/ev.h CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * libev native API header
3
3
  *
4
- * Copyright (c) 2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008,2009,2010,2011,2012,2015 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
7
  * Redistribution and use in source and binary forms, with or without modifica-
@@ -42,12 +42,16 @@
42
42
 
43
43
  #ifdef __cplusplus
44
44
  # define EV_CPP(x) x
45
+ # if __cplusplus >= 201103L
46
+ # define EV_THROW noexcept
47
+ # else
48
+ # define EV_THROW throw ()
49
+ # endif
45
50
  #else
46
51
  # define EV_CPP(x)
52
+ # define EV_THROW
47
53
  #endif
48
54
 
49
- #define EV_THROW EV_CPP(throw())
50
-
51
55
  EV_CPP(extern "C" {)
52
56
 
53
57
  /*****************************************************************************/
@@ -148,6 +152,8 @@ EV_CPP(extern "C" {)
148
152
 
149
153
  typedef double ev_tstamp;
150
154
 
155
+ #include <string.h> /* for memmove */
156
+
151
157
  #ifndef EV_ATOMIC_T
152
158
  # include <signal.h>
153
159
  # define EV_ATOMIC_T sig_atomic_t volatile
@@ -205,7 +211,7 @@ struct ev_loop;
205
211
  /*****************************************************************************/
206
212
 
207
213
  #define EV_VERSION_MAJOR 4
208
- #define EV_VERSION_MINOR 19
214
+ #define EV_VERSION_MINOR 22
209
215
 
210
216
  /* eventmask, revents, events... */
211
217
  enum {
@@ -660,7 +666,7 @@ EV_API_DECL void ev_set_userdata (EV_P_ void *data) EV_THROW;
660
666
  EV_API_DECL void *ev_userdata (EV_P) EV_THROW;
661
667
  typedef void (*ev_loop_callback)(EV_P);
662
668
  EV_API_DECL void ev_set_invoke_pending_cb (EV_P_ ev_loop_callback invoke_pending_cb) EV_THROW;
663
- /* C++ doesn't allow the use of the ev_loop_callback typedef here, so we need to spell it out*/
669
+ /* C++ doesn't allow the use of the ev_loop_callback typedef here, so we need to spell it out */
664
670
  EV_API_DECL void ev_set_loop_release_cb (EV_P_ void (*release)(EV_P) EV_THROW, void (*acquire)(EV_P) EV_THROW) EV_THROW;
665
671
 
666
672
  EV_API_DECL unsigned int ev_pending_count (EV_P) EV_THROW; /* number of pending events, if any */
@@ -715,7 +721,8 @@ EV_API_DECL void ev_resume (EV_P) EV_THROW;
715
721
  #define ev_is_pending(ev) (0 + ((ev_watcher *)(void *)(ev))->pending) /* ro, true when watcher is waiting for callback invocation */
716
722
  #define ev_is_active(ev) (0 + ((ev_watcher *)(void *)(ev))->active) /* ro, true when the watcher has been started */
717
723
 
718
- #define ev_cb(ev) (ev)->cb /* rw */
724
+ #define ev_cb_(ev) (ev)->cb /* rw */
725
+ #define ev_cb(ev) (memmove (&ev_cb_ (ev), &((ev_watcher *)(ev))->cb, sizeof (ev_cb_ (ev))), (ev)->cb)
719
726
 
720
727
  #if EV_MINPRI == EV_MAXPRI
721
728
  # define ev_priority(ev) ((ev), EV_MINPRI)
@@ -728,7 +735,7 @@ EV_API_DECL void ev_resume (EV_P) EV_THROW;
728
735
  #define ev_periodic_at(ev) (+((ev_watcher_time *)(ev))->at)
729
736
 
730
737
  #ifndef ev_set_cb
731
- # define ev_set_cb(ev,cb_) ev_cb (ev) = (cb_)
738
+ # define ev_set_cb(ev,cb_) (ev_cb_ (ev) = (cb_), memmove (&((ev_watcher *)(ev))->cb, &ev_cb_ (ev), sizeof (ev_cb_ (ev))))
732
739
  #endif
733
740
 
734
741
  /* stopping (enabling, adding) a watcher does nothing if it is already running */
data/ext/libev/ev_epoll.c CHANGED
@@ -179,7 +179,7 @@ epoll_poll (EV_P_ ev_tstamp timeout)
179
179
  if (expect_false ((uint32_t)anfds [fd].egen != (uint32_t)(ev->data.u64 >> 32)))
180
180
  {
181
181
  /* recreate kernel state */
182
- postfork = 1;
182
+ postfork |= 2;
183
183
  continue;
184
184
  }
185
185
 
@@ -203,7 +203,7 @@ epoll_poll (EV_P_ ev_tstamp timeout)
203
203
  /* which is fortunately easy to do for us. */
204
204
  if (epoll_ctl (backend_fd, want ? EPOLL_CTL_MOD : EPOLL_CTL_DEL, fd, ev))
205
205
  {
206
- postfork = 1; /* an error occurred, recreate kernel state */
206
+ postfork |= 2; /* an error occurred, recreate kernel state */
207
207
  continue;
208
208
  }
209
209
  }
data/ext/libev/ev_win32.c CHANGED
@@ -39,9 +39,6 @@
39
39
 
40
40
  #ifdef _WIN32
41
41
 
42
- /* timeb.h is actually xsi legacy functionality */
43
- #include <sys/timeb.h>
44
-
45
42
  /* note: the comment below could not be substantiated, but what would I care */
46
43
  /* MSDN says this is required to handle SIGFPE */
47
44
  /* my wild guess would be that using something floating-pointy is required */
@@ -91,6 +88,8 @@ ev_pipe (int filedes [2])
91
88
  if (connect (sock [0], (struct sockaddr *)&addr, addr_size))
92
89
  goto fail;
93
90
 
91
+ /* TODO: returns INVALID_SOCKET on winsock accept, not < 0. fix it */
92
+ /* when convenient, probably by just removing error checking altogether? */
94
93
  if ((sock [1] = accept (listener, 0, 0)) < 0)
95
94
  goto fail;
96
95
 
data/ext/nio4r/extconf.rb CHANGED
@@ -1,52 +1,41 @@
1
- require 'mkmf'
1
+ require "mkmf"
2
2
 
3
- if have_func('rb_thread_blocking_region')
4
- $defs << '-DHAVE_RB_THREAD_BLOCKING_REGION'
5
- end
3
+ have_header("unistd.h")
6
4
 
7
- if have_func('rb_thread_call_without_gvl')
8
- $defs << '-DHAVE_RB_THEREAD_CALL_WITHOUT_GVL'
5
+ if have_func("rb_thread_blocking_region")
6
+ $defs << "-DHAVE_RB_THREAD_BLOCKING_REGION"
9
7
  end
10
8
 
11
- if have_header('sys/select.h')
12
- $defs << '-DEV_USE_SELECT'
9
+ if have_func("rb_thread_call_without_gvl")
10
+ $defs << "-DHAVE_RB_THEREAD_CALL_WITHOUT_GVL"
13
11
  end
14
12
 
15
- if have_header('poll.h')
16
- $defs << '-DEV_USE_POLL'
17
- end
13
+ $defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
18
14
 
19
- if have_header('sys/epoll.h')
20
- $defs << '-DEV_USE_EPOLL'
21
- end
15
+ $defs << "-DEV_USE_POLL" if have_header("poll.h")
22
16
 
23
- if have_header('sys/event.h') and have_header('sys/queue.h')
24
- $defs << '-DEV_USE_KQUEUE'
25
- end
17
+ $defs << "-DEV_USE_EPOLL" if have_header("sys/epoll.h")
26
18
 
27
- if have_header('port.h')
28
- $defs << '-DEV_USE_PORT'
19
+ if have_header("sys/event.h") && have_header("sys/queue.h")
20
+ $defs << "-DEV_USE_KQUEUE"
29
21
  end
30
22
 
31
- if have_header('sys/resource.h')
32
- $defs << '-DHAVE_SYS_RESOURCE_H'
33
- end
23
+ $defs << "-DEV_USE_PORT" if have_header("port.h")
34
24
 
35
- if RUBY_VERSION.to_f < 1.9
36
- $defs << '-DHAVE_RUBYSIG_H'
37
- end
25
+ $defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
26
+
27
+ $defs << "-DHAVE_RUBYSIG_H" if RUBY_VERSION.to_f < 1.9
38
28
 
39
- dir_config 'nio4r_ext'
40
- create_makefile 'nio4r_ext'
29
+ dir_config "nio4r_ext"
30
+ create_makefile "nio4r_ext"
41
31
 
42
- # win32 needs to link in "just the right order" for some reason or ioctlsocket will be mapped to an [inverted] ruby specific version.
43
- # See libev mailing list for (not so helpful discussion--true cause I'm not sure, but this overcomes the symptom)
32
+ # win32 needs to link in "just the right order" for some reason or
33
+ # ioctlsocket will be mapped to an [inverted] ruby specific version.
44
34
  if RUBY_PLATFORM =~ /mingw|win32/
45
- makefile_contents = File.read 'Makefile'
35
+ makefile_contents = File.read "Makefile"
46
36
 
47
- # "Init_cool could not be found" when loading cool.io.so.
48
- makefile_contents.gsub! 'DLDFLAGS = ', 'DLDFLAGS = -export-all '
37
+ makefile_contents.gsub! "DLDFLAGS = ", "DLDFLAGS = -export-all "
49
38
 
50
- makefile_contents.gsub! 'LIBS = $(LIBRUBYARG_SHARED)', 'LIBS = -lws2_32 $(LIBRUBYARG_SHARED)'
51
- File.open('Makefile', 'w') { |f| f.write makefile_contents }
39
+ makefile_contents.gsub! "LIBS = $(LIBRUBYARG_SHARED)", "LIBS = -lws2_32 $(LIBRUBYARG_SHARED)"
40
+ File.open("Makefile", "w") { |f| f.write makefile_contents }
52
41
  end
data/ext/nio4r/monitor.c CHANGED
@@ -15,6 +15,8 @@ static void NIO_Monitor_free(struct NIO_Monitor *monitor);
15
15
 
16
16
  /* Methods */
17
17
  static VALUE NIO_Monitor_initialize(VALUE self, VALUE selector, VALUE io, VALUE interests);
18
+ static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests);
19
+
18
20
  static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self);
19
21
  static VALUE NIO_Monitor_is_closed(VALUE self);
20
22
  static VALUE NIO_Monitor_io(VALUE self);
@@ -40,6 +42,7 @@ void Init_NIO_Monitor()
40
42
  rb_define_alloc_func(cNIO_Monitor, NIO_Monitor_allocate);
41
43
 
42
44
  rb_define_method(cNIO_Monitor, "initialize", NIO_Monitor_initialize, 3);
45
+ rb_define_method(cNIO_Monitor, "interests=", NIO_Monitor_set_interests, 1);
43
46
  rb_define_method(cNIO_Monitor, "close", NIO_Monitor_close, -1);
44
47
  rb_define_method(cNIO_Monitor, "closed?", NIO_Monitor_is_closed, 0);
45
48
  rb_define_method(cNIO_Monitor, "io", NIO_Monitor_io, 0);
@@ -117,6 +120,38 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
117
120
  return Qnil;
118
121
  }
119
122
 
123
+ static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
124
+ {
125
+ struct NIO_Monitor *monitor;
126
+ ID interests_id;
127
+
128
+ if(NIO_Monitor_is_closed(self) == Qtrue) {
129
+ rb_raise(rb_eTypeError, "monitor is already closed");
130
+ }
131
+
132
+ interests_id = SYM2ID(interests);
133
+ Data_Get_Struct(self, struct NIO_Monitor, monitor);
134
+
135
+ if(interests_id == rb_intern("r")) {
136
+ monitor->interests = EV_READ;
137
+ } else if(interests_id == rb_intern("w")) {
138
+ monitor->interests = EV_WRITE;
139
+ } else if(interests_id == rb_intern("rw")) {
140
+ monitor->interests = EV_READ | EV_WRITE;
141
+ } else {
142
+ rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
143
+ RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0, 0)));
144
+ }
145
+
146
+ ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
147
+ ev_io_set(&monitor->ev_io, monitor->ev_io.fd, monitor->interests);
148
+ ev_io_start(monitor->selector->ev_loop, &monitor->ev_io);
149
+
150
+ rb_ivar_set(self, rb_intern("interests"), interests);
151
+
152
+ return interests;
153
+ }
154
+
120
155
  static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
121
156
  {
122
157
  VALUE deregister, selector;
@@ -127,10 +162,11 @@ static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
127
162
  selector = rb_ivar_get(self, rb_intern("selector"));
128
163
 
129
164
  if(selector != Qnil) {
130
- /* if ev_loop is 0, it means that the loop has been stopped already (see NIO_Selector_shutdown)*/
165
+ /* if ev_loop is 0, it means that the loop has been stopped already (see NIO_Selector_shutdown) */
131
166
  if(monitor->selector->ev_loop != 0) {
132
167
  ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
133
168
  }
169
+
134
170
  monitor->selector = 0;
135
171
  rb_ivar_set(self, rb_intern("selector"), Qnil);
136
172
 
@@ -148,7 +184,7 @@ static VALUE NIO_Monitor_is_closed(VALUE self)
148
184
  struct NIO_Monitor *monitor;
149
185
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
150
186
 
151
- return !monitor->selector;
187
+ return monitor->selector == 0 ? Qtrue : Qfalse;
152
188
  }
153
189
 
154
190
  static VALUE NIO_Monitor_io(VALUE self)
@@ -235,6 +235,11 @@ public class Nio4r implements Library {
235
235
  @JRubyMethod
236
236
  public synchronized IRubyObject select(ThreadContext context, IRubyObject timeout, Block block) {
237
237
  Ruby runtime = context.getRuntime();
238
+
239
+ if(!this.selector.isOpen()) {
240
+ throw context.getRuntime().newIOError("selector is closed");
241
+ }
242
+
238
243
  int ready = doSelect(runtime, context, timeout);
239
244
 
240
245
  /* Timeout or wakeup */
@@ -353,6 +358,36 @@ public class Nio4r implements Library {
353
358
  key.attach(this);
354
359
  }
355
360
 
361
+ @JRubyMethod(name = "interests=")
362
+ public IRubyObject setInterests(ThreadContext context, IRubyObject interests) {
363
+ if(this.closed == context.getRuntime().getTrue()) {
364
+ throw context.getRuntime().newTypeError("monitor is already closed");
365
+ }
366
+
367
+ int interestOps = 0;
368
+ Ruby runtime = context.getRuntime();
369
+ Channel rawChannel = io.getChannel();
370
+ SelectableChannel channel = (SelectableChannel)rawChannel;
371
+
372
+ this.interests = interests;
373
+
374
+ if(interests == ruby.newSymbol("r")) {
375
+ interestOps = SelectionKey.OP_READ;
376
+ } else if(interests == ruby.newSymbol("w")) {
377
+ interestOps = SelectionKey.OP_WRITE;
378
+ } else if(interests == ruby.newSymbol("rw")) {
379
+ interestOps = SelectionKey.OP_READ|SelectionKey.OP_WRITE;
380
+ }
381
+
382
+ if((interestOps & ~(channel.validOps())) == 0) {
383
+ key.interestOps(interestOps);
384
+ } else {
385
+ throw context.getRuntime().newArgumentError("given interests not supported for this IO object");
386
+ }
387
+
388
+ return this.interests;
389
+ }
390
+
356
391
  @JRubyMethod
357
392
  public IRubyObject io(ThreadContext context) {
358
393
  return io;
data/ext/nio4r/selector.c CHANGED
@@ -7,7 +7,13 @@
7
7
  #ifdef HAVE_RUBYSIG_H
8
8
  # include "rubysig.h"
9
9
  #endif
10
+
11
+ #ifdef HAVE_UNISTD_H
10
12
  #include <unistd.h>
13
+ #else
14
+ #include <io.h>
15
+ #endif
16
+
11
17
  #include <fcntl.h>
12
18
  #include <assert.h>
13
19
 
@@ -291,6 +297,11 @@ static VALUE NIO_Selector_select_synchronized(VALUE *args)
291
297
  struct NIO_Selector *selector;
292
298
 
293
299
  Data_Get_Struct(args[0], struct NIO_Selector, selector);
300
+
301
+ if(selector->closed) {
302
+ rb_raise(rb_eIOError, "selector is closed");
303
+ }
304
+
294
305
  if(!rb_block_given_p()) {
295
306
  selector->ready_array = rb_ary_new();
296
307
  }
data/lib/nio/monitor.rb CHANGED
@@ -13,11 +13,21 @@ module NIO
13
13
  io = io.to_io
14
14
  end
15
15
 
16
- raise TypeError, "can't convert #{io.class} into IO" unless io.is_a? IO
16
+ fail TypeError, "can't convert #{io.class} into IO" unless io.is_a? IO
17
17
  end
18
18
 
19
- @io, @interests, @selector = io, interests, selector
20
- @closed = false
19
+ @io = io
20
+ @interests = interests
21
+ @selector = selector
22
+ @closed = false
23
+ end
24
+
25
+ # set the interests set
26
+ def interests=(interests)
27
+ fail TypeError, "monitor is already closed" if closed?
28
+ fail ArgumentError, "bad interests: #{interests}" unless [:r, :w, :rw].include?(interests)
29
+
30
+ @interests = interests
21
31
  end
22
32
 
23
33
  # Is the IO object readable?
@@ -32,7 +42,9 @@ module NIO
32
42
  alias_method :writeable?, :writable?
33
43
 
34
44
  # Is this monitor closed?
35
- def closed?; @closed; end
45
+ def closed?
46
+ @closed
47
+ end
36
48
 
37
49
  # Deactivate this monitor
38
50
  def close(deregister = true)
data/lib/nio/selector.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'set'
1
+ require "set"
2
2
 
3
3
  module NIO
4
4
  # Selectors monitor IO objects for events of interest
@@ -20,13 +20,10 @@ module NIO
20
20
  # * :rw - is the IO either readable or writeable?
21
21
  def register(io, interest)
22
22
  @lock.synchronize do
23
- if closed?
24
- raise IOError, "selector is closed"
25
- end
23
+ fail IOError, "selector is closed" if closed?
26
24
 
27
- if monitor = @selectables[io]
28
- raise ArgumentError, "this IO is already registered with the selector as #{monitor.interests.inspect}"
29
- end
25
+ monitor = @selectables[io]
26
+ fail ArgumentError, "already registered as #{monitor.interests.inspect}" if monitor
30
27
 
31
28
  monitor = Monitor.new(io, interest, self)
32
29
  @selectables[monitor.io] = monitor
@@ -39,20 +36,21 @@ module NIO
39
36
  def deregister(io)
40
37
  @lock.synchronize do
41
38
  monitor = @selectables.delete io
42
- monitor.close(false) if monitor and not monitor.closed?
39
+ monitor.close(false) if monitor && !monitor.closed?
43
40
  monitor
44
41
  end
45
42
  end
46
43
 
47
44
  # Is the given IO object registered with the selector?
48
45
  def registered?(io)
49
- @lock.synchronize { @selectables.has_key? io }
46
+ @lock.synchronize { @selectables.key? io }
50
47
  end
51
48
 
52
49
  # Select which monitors are ready
53
50
  def select(timeout = nil)
54
51
  @lock.synchronize do
55
- readers, writers = [@wakeup], []
52
+ readers = [@wakeup]
53
+ writers = []
56
54
 
57
55
  @selectables.each do |io, monitor|
58
56
  readers << io if monitor.interests == :r || monitor.interests == :rw
@@ -80,11 +78,10 @@ module NIO
80
78
 
81
79
  ready_writers.each do |io|
82
80
  monitor = @selectables[io]
83
- monitor.readiness = case monitor.readiness
84
- when :r
85
- :rw
81
+ if monitor.readiness == :r
82
+ monitor.readiness = :rw
86
83
  else
87
- :w
84
+ monitor.readiness = :w
88
85
  end
89
86
  selected_monitors << monitor
90
87
  end
@@ -124,7 +121,9 @@ module NIO
124
121
  end
125
122
 
126
123
  # Is this selector closed?
127
- def closed?; @closed end
124
+ def closed?
125
+ @closed
126
+ end
128
127
 
129
128
  def empty?
130
129
  @selectables.empty?
data/lib/nio/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module NIO
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/nio.rb CHANGED
@@ -1,6 +1,6 @@
1
- require 'thread'
2
- require 'socket'
3
- require 'nio/version'
1
+ require "thread"
2
+ require "socket"
3
+ require "nio/version"
4
4
 
5
5
  # New I/O for Ruby
6
6
  module NIO
@@ -8,22 +8,24 @@ module NIO
8
8
  # * select: in pure Ruby using Kernel.select
9
9
  # * libev: as a C extension using libev
10
10
  # * java: using Java NIO
11
- def self.engine; ENGINE end
11
+ def self.engine
12
+ ENGINE
13
+ end
12
14
  end
13
15
 
14
- if ENV["NIO4R_PURE"] || (Gem.win_platform? && !defined?(JRUBY_VERSION))
15
- require 'nio/monitor'
16
- require 'nio/selector'
17
- NIO::ENGINE = 'select'
16
+ if ENV["NIO4R_PURE"] == "true" || (Gem.win_platform? && !defined?(JRUBY_VERSION))
17
+ require "nio/monitor"
18
+ require "nio/selector"
19
+ NIO::ENGINE = "ruby"
18
20
  else
19
- require 'nio4r_ext'
21
+ require "nio4r_ext"
20
22
 
21
23
  if defined?(JRUBY_VERSION)
22
- require 'java'
23
- require 'jruby'
24
+ require "java"
25
+ require "jruby"
24
26
  org.nio4r.Nio4r.new.load(JRuby.runtime, false)
25
- NIO::ENGINE = 'java'
27
+ NIO::ENGINE = "java"
26
28
  else
27
- NIO::ENGINE = 'libev'
29
+ NIO::ENGINE = "libev"
28
30
  end
29
31
  end
data/nio4r.gemspec CHANGED
@@ -1,5 +1,5 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/nio/version', __FILE__)
2
+ require File.expand_path("../lib/nio/version", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ["Tony Arcieri"]
@@ -9,7 +9,7 @@ Gem::Specification.new do |gem|
9
9
  gem.homepage = "https://github.com/celluloid/nio4r"
10
10
  gem.license = "MIT"
11
11
 
12
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
13
13
  gem.files = `git ls-files`.split("\n")
14
14
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
15
  gem.name = "nio4r"
@@ -25,5 +25,6 @@ Gem::Specification.new do |gem|
25
25
 
26
26
  gem.add_development_dependency "rake-compiler"
27
27
  gem.add_development_dependency "rake"
28
- gem.add_development_dependency "rspec", "~> 3.0.0"
28
+ gem.add_development_dependency "rspec", "~> 3.0"
29
+ gem.add_development_dependency "rubocop"
29
30
  end
@@ -1,6 +1,6 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
- describe "NIO acceptables" do
3
+ RSpec.describe "NIO acceptables" do
4
4
  shared_context "an NIO acceptable" do
5
5
  let(:selector) { NIO::Selector.new }
6
6
 
@@ -15,7 +15,7 @@ describe "NIO acceptables" do
15
15
  end
16
16
 
17
17
  describe TCPServer do
18
- let(:tcp_port) { 23456 }
18
+ let(:tcp_port) { 23_456 }
19
19
 
20
20
  let :acceptable_subject do
21
21
  server = TCPServer.new("localhost", tcp_port)
@@ -1,20 +1,49 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
+ require "socket"
3
+
4
+ RSpec.describe NIO::Monitor do
5
+ let(:example_peers) do
6
+ address = "127.0.0.1"
7
+ base_port = 12_345
8
+ tries = 10
9
+
10
+ server = tries.times do |n|
11
+ begin
12
+ break TCPServer.new(address, base_port + n)
13
+ rescue Errno::EADDRINUSE
14
+ retry
15
+ end
16
+ end
17
+
18
+ fail Errno::EADDRINUSE, "couldn't find an open port" unless server
19
+ client = TCPSocket.new(address, server.addr[1])
20
+ [server, client]
21
+ end
22
+
23
+ let(:reader) { example_peers.first }
24
+ let(:writer) { example_peers.last }
2
25
 
3
- describe NIO::Monitor do
4
- let(:pipes) { IO.pipe }
5
- let(:reader) { pipes.first }
6
- let(:writer) { pipes.last }
7
26
  let(:selector) { NIO::Selector.new }
8
27
 
9
28
  subject { selector.register(reader, :r) }
10
29
  let(:peer) { selector.register(writer, :rw) }
11
30
  after { selector.close }
12
31
 
32
+ before { example_peers } # open server and client automatically
33
+ after { reader.close }
34
+ after { writer.close }
35
+
13
36
  it "knows its interests" do
14
37
  expect(subject.interests).to eq(:r)
15
38
  expect(peer.interests).to eq(:rw)
16
39
  end
17
40
 
41
+ it "changes the interest set" do
42
+ expect(peer.interests).not_to eq(:w)
43
+ peer.interests = :w
44
+ expect(peer.interests).to eq(:w)
45
+ end
46
+
18
47
  it "knows its IO object" do
19
48
  expect(subject.io).to eq(reader)
20
49
  end
@@ -30,17 +59,17 @@ describe NIO::Monitor do
30
59
 
31
60
  it "knows what operations IO objects are ready for" do
32
61
  # For whatever odd reason this breaks unless we eagerly evaluate subject
33
- reader_monitor, writer_monitor = subject, peer
62
+ reader_monitor = subject
63
+ writer_monitor = peer
34
64
 
35
65
  selected = selector.select(0)
36
- expect(selected).not_to include(reader_monitor)
37
66
  expect(selected).to include(writer_monitor)
38
67
 
39
68
  expect(writer_monitor.readiness).to eq(:w)
40
69
  expect(writer_monitor).not_to be_readable
41
70
  expect(writer_monitor).to be_writable
42
71
 
43
- writer << "loldata"
72
+ writer << "testing 1 2 3"
44
73
 
45
74
  selected = selector.select(0)
46
75
  expect(selected).to include(reader_monitor)
@@ -50,6 +79,14 @@ describe NIO::Monitor do
50
79
  expect(reader_monitor).not_to be_writable
51
80
  end
52
81
 
82
+ it "changes current interests with #interests=" do
83
+ client = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
84
+ monitor = selector.register(client, :r)
85
+ expect(monitor.interests).to eq(:r)
86
+ monitor.interests = :w
87
+ expect(monitor.interests).to eq(:w)
88
+ end
89
+
53
90
  it "closes" do
54
91
  expect(subject).not_to be_closed
55
92
  expect(selector.registered?(reader)).to be_truthy
@@ -66,4 +103,11 @@ describe NIO::Monitor do
66
103
  subject.close
67
104
  expect(subject).to be_closed
68
105
  end
106
+
107
+ it "changes the interest set after monitor closed" do
108
+ # check for changing the interests on the go after closed expected to fail
109
+ expect(subject.interests).not_to eq(:rw)
110
+ subject.close # forced shutdown
111
+ expect { subject.interests = :rw }.to raise_error(TypeError)
112
+ end
69
113
  end
@@ -1,6 +1,6 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
- describe "IO.pipe" do
3
+ RSpec.describe "IO.pipe" do
4
4
  let(:pair) { IO.pipe }
5
5
 
6
6
  let :unreadable_subject do
@@ -18,17 +18,17 @@ describe "IO.pipe" do
18
18
  let :unwritable_subject do
19
19
  reader, pipe = IO.pipe
20
20
 
21
- #HACK: On OS X 10.8, this str must be larger than PIPE_BUF. Otherwise,
21
+ # HACK: On OS X 10.8, this str must be larger than PIPE_BUF. Otherwise,
22
22
  # the write is atomic and select() will return writable but write()
23
23
  # will throw EAGAIN if there is too little space to write the string
24
24
  # TODO: Use FFI to lookup the platform-specific size of PIPE_BUF
25
- str = "JUNK IN THE TUBES" * 10000
25
+ str = "JUNK IN THE TUBES" * 10_000
26
26
  begin
27
27
  pipe.write_nonblock str
28
28
  _, writers = select [], [pipe], [], 0
29
29
  rescue Errno::EPIPE
30
30
  break
31
- end while writers and writers.include? pipe
31
+ end while writers && writers.include?(pipe)
32
32
 
33
33
  pipe
34
34
  end