nio4r 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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