nio4r 0.3.1 → 0.3.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.
data/CHANGES.md CHANGED
@@ -1,3 +1,13 @@
1
+ 0.3.2
2
+ -----
3
+ * NIO::Selector#select_each removed
4
+ * Remove event buffer
5
+ * Patch GIL unlock directly into libev
6
+
7
+ 0.3.1
8
+ -----
9
+ * Prevent CancelledKeyExceptions on JRuby
10
+
1
11
  0.3.0
2
12
  -----
3
13
  * NIO::Selector#select now takes a block and behaves like select_each
@@ -17,7 +17,7 @@ class EchoServer
17
17
 
18
18
  def run
19
19
  while true
20
- @selector.select_each { |monitor| monitor.value.call(monitor) }
20
+ @selector.select { |monitor| monitor.value.call(monitor) }
21
21
  end
22
22
  end
23
23
 
@@ -37,6 +37,10 @@
37
37
  * either the BSD or the GPL.
38
38
  */
39
39
 
40
+ /* ########## NIO4R PATCHERY HO! ########## */
41
+ #include "ruby.h"
42
+ /* ######################################## */
43
+
40
44
  /* this big block deduces configuration from config.h */
41
45
  #ifndef EV_STANDALONE
42
46
  # ifdef EV_CONFIG_H
@@ -2926,9 +2930,32 @@ time_update (EV_P_ ev_tstamp max_block)
2926
2930
  }
2927
2931
  }
2928
2932
 
2933
+ /* ########## NIO4R PATCHERY HO! ########## */
2934
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION)
2935
+ struct ev_poll_args {
2936
+ struct ev_loop *loop;
2937
+ ev_tstamp waittime;
2938
+ };
2939
+
2940
+ static
2941
+ VALUE ev_backend_poll(void *ptr)
2942
+ {
2943
+ struct ev_poll_args *args = (struct ev_poll_args *)ptr;
2944
+ struct ev_loop *loop = args->loop;
2945
+ backend_poll (EV_A_ args->waittime);
2946
+ }
2947
+ #endif
2948
+ /* ######################################## */
2949
+
2929
2950
  void
2930
2951
  ev_run (EV_P_ int flags)
2931
2952
  {
2953
+ /* ########## NIO4R PATCHERY HO! ########## */
2954
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION)
2955
+ struct ev_poll_args poll_args;
2956
+ #endif
2957
+ /* ######################################## */
2958
+
2932
2959
  #if EV_FEATURE_API
2933
2960
  ++loop_depth;
2934
2961
  #endif
@@ -3046,7 +3073,50 @@ ev_run (EV_P_ int flags)
3046
3073
  ++loop_count;
3047
3074
  #endif
3048
3075
  assert ((loop_done = EVBREAK_RECURSE, 1)); /* assert for side effect */
3076
+
3077
+ /*
3078
+ ########################## NIO4R PATCHERY HO! ##########################
3079
+
3080
+ According to the grandwizards of Ruby, locking and unlocking of the global
3081
+ interpreter lock are apparently too powerful a concept for a mere mortal to
3082
+ wield (although redefining what + and - do to numbers is totally cool).
3083
+ And so it came to pass that the only acceptable way to release the global
3084
+ interpreter lock is through a convoluted callback system that thakes a
3085
+ function pointer. While the grandwizard of libev foresaw this sort of scenario,
3086
+ he too attempted to place an API with callbacks on it, one that runs before
3087
+ the system call, and one that runs immediately after.
3088
+
3089
+ And so it came to pass that trying to wrap everything up in callbacks created
3090
+ two incompatible APIs, Ruby's which releases the global interpreter lock and
3091
+ reacquires it when the callback returns, and libev's, which wants two
3092
+ callbacks, one which runs before the polling operation starts, and one which
3093
+ runs after it finishes.
3094
+
3095
+ These two systems are incompatible as they both want to use callbacks to
3096
+ solve the same problem, however libev wants to use before/after callbacks,
3097
+ and Ruby wants to use an "around" callback. This presents a significant
3098
+ problem as these two patterns of callbacks are diametrical opposites of each
3099
+ other and thus cannot be composed.
3100
+
3101
+ And thus we are left with no choice but to patch the internals of libev in
3102
+ order to release a mutex at just the precise moment.
3103
+
3104
+ Let this be a lesson to the all: CALLBACKS FUCKING BLOW
3105
+
3106
+ #######################################################################
3107
+ */
3108
+
3109
+ #if defined(HAVE_RB_THREAD_BLOCKING_REGION)
3110
+ poll_args.loop = loop;
3111
+ poll_args.waittime = waittime;
3112
+ rb_thread_blocking_region(ev_backend_poll, (void *)&poll_args, RUBY_UBF_IO, 0);
3113
+ #else
3049
3114
  backend_poll (EV_A_ waittime);
3115
+ #endif
3116
+ /*
3117
+ ############################# END PATCHERY ############################
3118
+ */
3119
+
3050
3120
  assert ((loop_done = EVBREAK_CANCEL, 1)); /* assert for side effect */
3051
3121
 
3052
3122
  pipe_write_wanted = 0; /* just an optimisation, no fence needed */
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  #include "nio4r.h"
7
- #include <assert.h>
8
7
 
9
8
  static VALUE mNIO = Qnil;
10
9
  static VALUE cNIO_Monitor = Qnil;
@@ -101,7 +100,7 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
101
100
  }
102
101
 
103
102
  GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
104
- ev_io_init(&monitor->ev_io, NIO_Monitor_callback, FPTR_TO_FD(fptr), monitor->interests);
103
+ ev_io_init(&monitor->ev_io, NIO_Selector_monitor_callback, FPTR_TO_FD(fptr), monitor->interests);
105
104
 
106
105
  rb_ivar_set(self, rb_intern("io"), io);
107
106
  rb_ivar_set(self, rb_intern("interests"), interests);
@@ -215,15 +214,4 @@ static VALUE NIO_Monitor_is_writable(VALUE self)
215
214
  } else {
216
215
  return Qfalse;
217
216
  }
218
- }
219
-
220
- /* libev callback fired whenever this monitor gets events */
221
- static void NIO_Monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents)
222
- {
223
- struct NIO_Monitor *monitor = (struct NIO_Monitor *)io->data;
224
-
225
- assert(monitor->selector != 0);
226
- monitor->revents = revents;
227
-
228
- NIO_Selector_handle_event(monitor->selector, monitor->self, revents);
229
- }
217
+ }
@@ -19,8 +19,8 @@ struct NIO_Selector
19
19
  int wakeup_reader, wakeup_writer;
20
20
  int closed, selecting;
21
21
  int ready_count;
22
- int ready_buffer_size;
23
- VALUE *ready_buffer;
22
+
23
+ VALUE ready_array;
24
24
  };
25
25
 
26
26
  struct NIO_callback_data
@@ -50,6 +50,6 @@ struct NIO_Monitor
50
50
  #endif /* GetReadFile */
51
51
 
52
52
  /* Thunk between libev callbacks in NIO::Monitors and NIO::Selectors */
53
- void NIO_Selector_handle_event(struct NIO_Selector *selector, VALUE monitor, int revents);
53
+ void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
54
54
 
55
55
  #endif /* NIO4R_H */
@@ -134,13 +134,13 @@ public class Nio4r implements Library {
134
134
  @JRubyMethod
135
135
  public IRubyObject register(ThreadContext context, IRubyObject io, IRubyObject interests) {
136
136
  Ruby runtime = context.getRuntime();
137
- Channel raw_channel = RubyIO.convertToIO(context, io).getChannel();
137
+ Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
138
138
 
139
- if(!(raw_channel instanceof SelectableChannel)) {
139
+ if(!(rawChannel instanceof SelectableChannel)) {
140
140
  throw runtime.newArgumentError("not a selectable IO object");
141
141
  }
142
142
 
143
- SelectableChannel channel = (SelectableChannel)raw_channel;
143
+ SelectableChannel channel = (SelectableChannel)rawChannel;
144
144
 
145
145
  try {
146
146
  channel.configureBlocking(false);
@@ -175,13 +175,13 @@ public class Nio4r implements Library {
175
175
  @JRubyMethod
176
176
  public IRubyObject deregister(ThreadContext context, IRubyObject io) {
177
177
  Ruby runtime = context.getRuntime();
178
- Channel raw_channel = RubyIO.convertToIO(context, io).getChannel();
178
+ Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
179
179
 
180
- if(!(raw_channel instanceof SelectableChannel)) {
180
+ if(!(rawChannel instanceof SelectableChannel)) {
181
181
  throw runtime.newArgumentError("not a selectable IO object");
182
182
  }
183
183
 
184
- SelectableChannel channel = (SelectableChannel)raw_channel;
184
+ SelectableChannel channel = (SelectableChannel)rawChannel;
185
185
  SelectionKey key = channel.keyFor(this.selector);
186
186
 
187
187
  if(key == null)
@@ -197,13 +197,13 @@ public class Nio4r implements Library {
197
197
  @JRubyMethod(name = "registered?")
198
198
  public IRubyObject isRegistered(ThreadContext context, IRubyObject io) {
199
199
  Ruby runtime = context.getRuntime();
200
- Channel raw_channel = RubyIO.convertToIO(context, io).getChannel();
200
+ Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
201
201
 
202
- if(!(raw_channel instanceof SelectableChannel)) {
202
+ if(!(rawChannel instanceof SelectableChannel)) {
203
203
  throw runtime.newArgumentError("not a selectable IO object");
204
204
  }
205
205
 
206
- SelectableChannel channel = (SelectableChannel)raw_channel;
206
+ SelectableChannel channel = (SelectableChannel)rawChannel;
207
207
  SelectionKey key = channel.keyFor(this.selector);
208
208
 
209
209
  if(key == null)
@@ -256,40 +256,9 @@ public class Nio4r implements Library {
256
256
  }
257
257
  }
258
258
 
259
- @JRubyMethod
260
- public synchronized IRubyObject select_each(ThreadContext context, Block block) {
261
- return select_each(context, context.nil, block);
262
- }
263
-
264
- @JRubyMethod
265
- public synchronized IRubyObject select_each(ThreadContext context, IRubyObject timeout, Block block) {
266
- Ruby runtime = context.getRuntime();
267
- int ready = doSelect(runtime, timeout);
268
-
269
- /* Timeout or wakeup */
270
- if(ready <= 0)
271
- return context.nil;
272
-
273
- Iterator selectedKeys = this.selector.selectedKeys().iterator();
274
- while (selectedKeys.hasNext()) {
275
- SelectionKey key = (SelectionKey)selectedKeys.next();
276
- processKey(key);
277
- selectedKeys.remove();
278
- block.call(context, (IRubyObject)key.attachment());
279
- }
280
-
281
- return context.nil;
282
- }
283
-
259
+ /* Run the selector */
284
260
  private int doSelect(Ruby runtime, IRubyObject timeout) {
285
- Iterator cancelledKeys = this.cancelledKeys.entrySet().iterator();
286
- while(cancelledKeys.hasNext()) {
287
- Map.Entry entry = (Map.Entry)cancelledKeys.next();
288
- SelectionKey key = (SelectionKey)entry.getValue();
289
- key.cancel();
290
- cancelledKeys.remove();
291
- }
292
-
261
+ cancelKeys();
293
262
  try {
294
263
  if(timeout.isNil()) {
295
264
  return this.selector.select();
@@ -308,6 +277,17 @@ public class Nio4r implements Library {
308
277
  }
309
278
  }
310
279
 
280
+ /* Flush our internal buffer of cancelled keys */
281
+ private void cancelKeys() {
282
+ Iterator cancelledKeys = this.cancelledKeys.entrySet().iterator();
283
+ while(cancelledKeys.hasNext()) {
284
+ Map.Entry entry = (Map.Entry)cancelledKeys.next();
285
+ SelectionKey key = (SelectionKey)entry.getValue();
286
+ key.cancel();
287
+ cancelledKeys.remove();
288
+ }
289
+ }
290
+
311
291
  // Remove connect interest from connected sockets
312
292
  // See: http://stackoverflow.com/questions/204186/java-nio-select-returns-without-selected-keys-why
313
293
  private void processKey(SelectionKey key) {
@@ -7,6 +7,7 @@
7
7
  #include "rubysig.h"
8
8
  #include <unistd.h>
9
9
  #include <fcntl.h>
10
+ #include <assert.h>
10
11
 
11
12
  static VALUE mNIO = Qnil;
12
13
  static VALUE cNIO_Monitor = Qnil;
@@ -24,7 +25,6 @@ static VALUE NIO_Selector_register(VALUE self, VALUE selectable, VALUE interest)
24
25
  static VALUE NIO_Selector_deregister(VALUE self, VALUE io);
25
26
  static VALUE NIO_Selector_is_registered(VALUE self, VALUE io);
26
27
  static VALUE NIO_Selector_select(int argc, VALUE *argv, VALUE self);
27
- static VALUE NIO_Selector_select_each(int argc, VALUE *argv, VALUE self);
28
28
  static VALUE NIO_Selector_wakeup(VALUE self);
29
29
  static VALUE NIO_Selector_close(VALUE self);
30
30
  static VALUE NIO_Selector_closed(VALUE self);
@@ -35,9 +35,7 @@ static VALUE NIO_Selector_unlock(VALUE lock);
35
35
  static VALUE NIO_Selector_register_synchronized(VALUE *args);
36
36
  static VALUE NIO_Selector_deregister_synchronized(VALUE *args);
37
37
  static VALUE NIO_Selector_select_synchronized(VALUE *args);
38
- static VALUE NIO_Selector_select_each_synchronized(VALUE *args);
39
- static int NIO_Selector_fill_ready_buffer(VALUE *args);
40
- static VALUE NIO_Selector_run_evloop(void *ptr);
38
+ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout);
41
39
  static void NIO_Selector_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents);
42
40
  static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents);
43
41
 
@@ -59,7 +57,6 @@ void Init_NIO_Selector()
59
57
  rb_define_method(cNIO_Selector, "deregister", NIO_Selector_deregister, 1);
60
58
  rb_define_method(cNIO_Selector, "registered?", NIO_Selector_is_registered, 1);
61
59
  rb_define_method(cNIO_Selector, "select", NIO_Selector_select, -1);
62
- rb_define_method(cNIO_Selector, "select_each", NIO_Selector_select_each, -1);
63
60
  rb_define_method(cNIO_Selector, "wakeup", NIO_Selector_wakeup, 0);
64
61
  rb_define_method(cNIO_Selector, "close", NIO_Selector_close, 0);
65
62
  rb_define_method(cNIO_Selector, "closed?", NIO_Selector_closed, 0);
@@ -99,8 +96,7 @@ static VALUE NIO_Selector_allocate(VALUE klass)
99
96
  ev_io_start(selector->ev_loop, &selector->wakeup);
100
97
 
101
98
  selector->closed = selector->selecting = selector->ready_count = 0;
102
- selector->ready_buffer_size = INITIAL_READY_BUFFER;
103
- selector->ready_buffer = (VALUE *)xmalloc(sizeof(VALUE) * INITIAL_READY_BUFFER);
99
+ selector->ready_array = Qnil;
104
100
 
105
101
  return Data_Wrap_Struct(klass, NIO_Selector_mark, NIO_Selector_free, selector);
106
102
  }
@@ -108,6 +104,9 @@ static VALUE NIO_Selector_allocate(VALUE klass)
108
104
  /* NIO selectors store all Ruby objects in instance variables so mark is a stub */
109
105
  static void NIO_Selector_mark(struct NIO_Selector *selector)
110
106
  {
107
+ if(selector->ready_array != Qnil) {
108
+ rb_gc_mark(selector->ready_array);
109
+ }
111
110
  }
112
111
 
113
112
  /* Free a Selector's system resources.
@@ -133,8 +132,6 @@ static void NIO_Selector_shutdown(struct NIO_Selector *selector)
133
132
  static void NIO_Selector_free(struct NIO_Selector *selector)
134
133
  {
135
134
  NIO_Selector_shutdown(selector);
136
-
137
- xfree(selector->ready_buffer);
138
135
  xfree(selector);
139
136
  }
140
137
 
@@ -271,81 +268,36 @@ static VALUE NIO_Selector_select(int argc, VALUE *argv, VALUE self)
271
268
  return NIO_Selector_synchronize(self, NIO_Selector_select_synchronized, args);
272
269
  }
273
270
 
274
- /* Select from all registered IO objects */
275
- static VALUE NIO_Selector_select_each(int argc, VALUE *argv, VALUE self)
276
- {
277
- VALUE timeout, array;
278
- VALUE args[2];
279
-
280
- if(!rb_block_given_p()) {
281
- rb_raise(rb_eArgError, "no block given");
282
- }
283
-
284
- rb_scan_args(argc, argv, "01", &timeout);
285
-
286
- if(timeout != Qnil && NUM2DBL(timeout) < 0) {
287
- rb_raise(rb_eArgError, "time interval must be positive");
288
- }
289
-
290
- args[0] = self;
291
- args[1] = timeout;
292
-
293
- return NIO_Selector_synchronize(self, NIO_Selector_select_each_synchronized, args);
294
- }
295
-
296
271
  /* Internal implementation of select with the selector lock held */
297
272
  static VALUE NIO_Selector_select_synchronized(VALUE *args)
298
273
  {
274
+ int i, ready;
275
+ VALUE ready_array;
299
276
  struct NIO_Selector *selector;
300
- int i, ready = NIO_Selector_fill_ready_buffer(args);
301
277
 
302
278
  Data_Get_Struct(args[0], struct NIO_Selector, selector);
279
+ if(!rb_block_given_p()) {
280
+ selector->ready_array = rb_ary_new();
281
+ }
303
282
 
283
+ ready = NIO_Selector_run(selector, args[1]);
304
284
  if(ready > 0) {
305
285
  if(rb_block_given_p()) {
306
- for(i = 0; i < ready; i++) {
307
- rb_yield(selector->ready_buffer[i]);
308
- }
309
-
310
286
  return INT2NUM(ready);
311
287
  } else {
312
- /* new4 memcpys the ready buffer */
313
- return rb_ary_new4(ready, selector->ready_buffer);
314
- }
315
- } else {
316
- return Qnil;
317
- }
318
- }
319
-
320
- /* Internal implementation of select with the selector lock held */
321
- static VALUE NIO_Selector_select_each_synchronized(VALUE *args)
322
- {
323
- struct NIO_Selector *selector;
324
- int i, ready = NIO_Selector_fill_ready_buffer(args);
325
-
326
- Data_Get_Struct(args[0], struct NIO_Selector, selector);
327
-
328
- if(ready > 0) {
329
- for(i = 0; i < ready; i++) {
330
- rb_yield(selector->ready_buffer[i]);
288
+ ready_array = selector->ready_array;
289
+ selector->ready_array = Qnil;
290
+ return ready_array;
331
291
  }
332
-
333
- return INT2NUM(ready);
334
292
  } else {
293
+ selector->ready_array = Qnil;
335
294
  return Qnil;
336
295
  }
337
296
  }
338
297
 
339
- static int NIO_Selector_fill_ready_buffer(VALUE *args)
298
+ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
340
299
  {
341
- VALUE self, timeout;
342
- struct NIO_Selector *selector;
343
300
  int result;
344
-
345
- self = args[0];
346
- timeout = args[1];
347
-
348
- Data_Get_Struct(self, struct NIO_Selector, selector);
349
301
  selector->selecting = 1;
350
302
 
351
303
  #if defined(HAVE_RB_THREAD_BLOCKING_REGION) || defined(HAVE_RB_THREAD_ALONE)
@@ -363,8 +315,8 @@ static int NIO_Selector_fill_ready_buffer(VALUE *args)
363
315
  #endif
364
316
 
365
317
  #if defined(HAVE_RB_THREAD_BLOCKING_REGION)
366
- /* Ruby 1.9 lets us release the GIL and make a blocking I/O call */
367
- rb_thread_blocking_region(NIO_Selector_run_evloop, selector, RUBY_UBF_IO, 0);
318
+ /* libev is patched to release the GIL when it makes its system call */
319
+ ev_loop(selector->ev_loop, EVLOOP_ONESHOT);
368
320
  #elif defined(HAVE_RB_THREAD_ALONE)
369
321
  /* If we're the only thread we can make a blocking system call */
370
322
  if(rb_thread_alone()) {
@@ -375,7 +327,7 @@ static int NIO_Selector_fill_ready_buffer(VALUE *args)
375
327
 
376
328
  #if !defined(HAVE_RB_THREAD_BLOCKING_REGION)
377
329
  TRAP_BEG;
378
- NIO_Selector_run_evloop(selector);
330
+ ev_loop(selector->ev_loop, EVLOOP_ONESHOT);
379
331
  TRAP_END;
380
332
  } else {
381
333
  /* We need to busy wait as not to stall the green thread scheduler
@@ -386,7 +338,7 @@ static int NIO_Selector_fill_ready_buffer(VALUE *args)
386
338
  /* Loop until we receive events */
387
339
  while(selector->selecting && !selector->ready_count) {
388
340
  TRAP_BEG;
389
- NIO_Selector_run_evloop(selector);
341
+ ev_loop(selector->ev_loop, EVLOOP_ONESHOT);
390
342
  TRAP_END;
391
343
 
392
344
  /* Run the next green thread */
@@ -407,16 +359,6 @@ static int NIO_Selector_fill_ready_buffer(VALUE *args)
407
359
  return result;
408
360
  }
409
361
 
410
- /* Run the libev event loop */
411
- static VALUE NIO_Selector_run_evloop(void *ptr)
412
- {
413
- struct NIO_Selector *selector = (struct NIO_Selector *)ptr;
414
-
415
- ev_loop(selector->ev_loop, EVLOOP_ONESHOT);
416
-
417
- return Qnil;
418
- }
419
-
420
362
  /* Wake the selector up from another thread */
421
363
  static VALUE NIO_Selector_wakeup(VALUE self)
422
364
  {
@@ -428,7 +370,6 @@ static VALUE NIO_Selector_wakeup(VALUE self)
428
370
  }
429
371
 
430
372
  write(selector->wakeup_writer, "\0", 1);
431
-
432
373
  return Qnil;
433
374
  }
434
375
 
@@ -470,27 +411,21 @@ static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *
470
411
  while(read(selector->wakeup_reader, buffer, 128) > 0);
471
412
  }
472
413
 
473
- /* This gets called from individual monitors. We must be careful here because
474
- the GIL isn't held, so we must rely only on standard C and can't touch
475
- anything Ruby-related.
476
-
477
- It's scary because there's a VALUE here, and VALUEs are a Ruby thing,
478
- however we're not going to dereference that VALUE or attempt to do anything
479
- with it. We just treat it as completely opaque until we have the GIL back.
480
-
481
- In order for this function to even get called, the monitor the VALUE points to
482
- must be attached to this Selector, and if it's attached to this Selector
483
- then we hold a reference to it in the @selectables instance variable, so
484
- there's no danger of this monitor getting garbage collected before we have
485
- the GIL back as we hold a reference. */
486
- void NIO_Selector_handle_event(struct NIO_Selector *selector, VALUE monitor, int revents)
414
+ /* libev callback fired whenever a monitor gets an event */
415
+ void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, int revents)
487
416
  {
488
- /* Grow the ready buffer if it's too small */
489
- if(selector->ready_count >= selector->ready_buffer_size) {
490
- selector->ready_buffer_size *= 2;
491
- selector->ready_buffer = (VALUE *)xrealloc(selector->ready_buffer, sizeof(VALUE) * selector->ready_buffer_size);
492
- }
417
+ struct NIO_Monitor *monitor_data = (struct NIO_Monitor *)io->data;
418
+ struct NIO_Selector *selector = monitor_data->selector;
419
+ VALUE monitor = monitor_data->self;
493
420
 
494
- selector->ready_buffer[selector->ready_count] = monitor;
421
+ assert(selector != 0);
495
422
  selector->ready_count++;
423
+ monitor_data->revents = revents;
424
+
425
+ if(rb_block_given_p()) {
426
+ rb_yield(monitor);
427
+ } else {
428
+ assert(selector->ready_array != Qnil);
429
+ rb_ary_push(selector->ready_array, monitor);
430
+ }
496
431
  }
@@ -107,14 +107,6 @@ module NIO
107
107
  end
108
108
  end
109
109
 
110
- # Select for ready monitors, successively yielding each one in a block
111
- def select_each(timeout = nil, &block)
112
- selected = select(timeout)
113
- return unless selected
114
- selected.each(&block)
115
- selected.size
116
- end
117
-
118
110
  # Wake up a thread that's in the middle of selecting on this selector, if
119
111
  # any such thread exists.
120
112
  #
@@ -1,3 +1,3 @@
1
1
  module NIO
2
- VERSION = "0.3.1"
2
+ VERSION = "0.3.2"
3
3
  end
@@ -39,14 +39,18 @@ describe "NIO selectables" do
39
39
  describe "IO.pipe" do
40
40
  let(:pair) { IO.pipe }
41
41
 
42
- let :unreadable_subject do pair.first end
42
+ let :unreadable_subject do
43
+ pair.first
44
+ end
43
45
  let :readable_subject do
44
46
  pipe, peer = pair
45
47
  peer << "data"
46
48
  pipe
47
49
  end
48
50
 
49
- let :writable_subject do pair.last end
51
+ let :writable_subject do
52
+ pair.last
53
+ end
50
54
  let :unwritable_subject do
51
55
  reader, pipe = IO.pipe
52
56
 
@@ -138,45 +138,6 @@ describe NIO::Selector do
138
138
  end
139
139
  end
140
140
 
141
- context "select_each" do
142
- it "iterates across ready selectables" do
143
- readable1, writer = IO.pipe
144
- writer << "ohai"
145
-
146
- readable2, writer = IO.pipe
147
- writer << "ohai"
148
-
149
- unreadable, _ = IO.pipe
150
-
151
- monitor1 = subject.register(readable1, :r)
152
- monitor2 = subject.register(readable2, :r)
153
- monitor3 = subject.register(unreadable, :r)
154
-
155
- readables = []
156
- subject.select_each { |monitor| readables << monitor }
157
-
158
- readables.should include(monitor1)
159
- readables.should include(monitor2)
160
- readables.should_not include(monitor3)
161
- end
162
-
163
- it "allows new monitors to be registered in the select_each block" do
164
- server = TCPServer.new("localhost", 10001)
165
-
166
- monitor = subject.register(server, :r)
167
- connector = TCPSocket.open("localhost", 10001)
168
-
169
- block_fired = false
170
- subject.select_each do |monitor|
171
- block_fired = true
172
- socket = server.accept
173
- subject.register(socket, :r).should be_a NIO::Monitor
174
- end
175
-
176
- block_fired.should be_true
177
- end
178
- end
179
-
180
141
  it "closes" do
181
142
  subject.close
182
143
  subject.should be_closed
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nio4r
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-12 00:00:00.000000000 Z
12
+ date: 2012-03-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake-compiler
16
- requirement: &70256512025560 !ruby/object:Gem::Requirement
16
+ requirement: &70242529573760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *70256512025560
24
+ version_requirements: *70242529573760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &70256512024940 !ruby/object:Gem::Requirement
27
+ requirement: &70242529573340 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *70256512024940
35
+ version_requirements: *70242529573340
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rspec
38
- requirement: &70256512040740 !ruby/object:Gem::Requirement
38
+ requirement: &70242529572920 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *70256512040740
46
+ version_requirements: *70242529572920
47
47
  description: New IO for Ruby
48
48
  email:
49
49
  - tony.arcieri@gmail.com