nio4r 2.0.0.pre-java → 2.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +0 -1
  3. data/.rubocop.yml +31 -38
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +9 -19
  6. data/CHANGES.md +94 -42
  7. data/Gemfile +11 -3
  8. data/Guardfile +10 -0
  9. data/LICENSE.txt +1 -1
  10. data/README.md +43 -136
  11. data/Rakefile +2 -0
  12. data/examples/echo_server.rb +1 -0
  13. data/ext/libev/Changes +9 -13
  14. data/ext/libev/ev.c +100 -74
  15. data/ext/libev/ev.h +4 -9
  16. data/ext/libev/ev_epoll.c +6 -3
  17. data/ext/libev/ev_kqueue.c +8 -4
  18. data/ext/libev/ev_poll.c +6 -3
  19. data/ext/libev/ev_port.c +8 -4
  20. data/ext/libev/ev_select.c +4 -2
  21. data/ext/nio4r/bytebuffer.c +265 -257
  22. data/ext/nio4r/extconf.rb +3 -9
  23. data/ext/nio4r/monitor.c +93 -46
  24. data/ext/nio4r/nio4r.h +6 -16
  25. data/ext/nio4r/org/nio4r/ByteBuffer.java +193 -209
  26. data/ext/nio4r/org/nio4r/Monitor.java +164 -0
  27. data/ext/nio4r/org/nio4r/Nio4r.java +13 -391
  28. data/ext/nio4r/org/nio4r/Selector.java +278 -0
  29. data/ext/nio4r/selector.c +72 -64
  30. data/lib/nio.rb +3 -3
  31. data/lib/nio/bytebuffer.rb +179 -132
  32. data/lib/nio/monitor.rb +64 -4
  33. data/lib/nio/selector.rb +36 -13
  34. data/lib/nio/version.rb +1 -1
  35. data/nio4r.gemspec +25 -19
  36. data/spec/nio/acceptables_spec.rb +6 -4
  37. data/spec/nio/bytebuffer_spec.rb +323 -51
  38. data/spec/nio/monitor_spec.rb +122 -79
  39. data/spec/nio/selectables/pipe_spec.rb +5 -1
  40. data/spec/nio/selectables/ssl_socket_spec.rb +15 -12
  41. data/spec/nio/selectables/tcp_socket_spec.rb +42 -31
  42. data/spec/nio/selectables/udp_socket_spec.rb +2 -0
  43. data/spec/nio/selector_spec.rb +10 -4
  44. data/spec/spec_helper.rb +24 -3
  45. data/spec/support/selectable_examples.rb +7 -5
  46. data/tasks/extension.rake +2 -0
  47. data/tasks/rspec.rake +2 -0
  48. data/tasks/rubocop.rake +2 -0
  49. metadata +18 -15
  50. data/.rubocop_todo.yml +0 -35
@@ -0,0 +1,164 @@
1
+ package org.nio4r;
2
+
3
+ import java.nio.channels.Channel;
4
+ import java.nio.channels.SelectableChannel;
5
+ import java.nio.channels.SelectionKey;
6
+
7
+ import org.jruby.Ruby;
8
+ import org.jruby.RubyClass;
9
+ import org.jruby.RubyIO;
10
+ import org.jruby.RubyObject;
11
+ import org.jruby.anno.JRubyMethod;
12
+ import org.jruby.runtime.ThreadContext;
13
+ import org.jruby.runtime.builtin.IRubyObject;
14
+
15
+ public class Monitor extends RubyObject {
16
+ private SelectionKey key;
17
+ private RubyIO io;
18
+ private IRubyObject interests, selector, value, closed;
19
+
20
+ public Monitor(final Ruby ruby, RubyClass rubyClass) {
21
+ super(ruby, rubyClass);
22
+ }
23
+
24
+ @JRubyMethod
25
+ public IRubyObject initialize(ThreadContext context, IRubyObject selectable, IRubyObject interests, IRubyObject selector) {
26
+ this.io = RubyIO.convertToIO(context, selectable);
27
+ this.interests = interests;
28
+ this.selector = selector;
29
+
30
+ this.value = context.nil;
31
+ this.closed = context.getRuntime().getFalse();
32
+
33
+ return context.nil;
34
+ }
35
+
36
+ public void setSelectionKey(SelectionKey key) {
37
+ this.key = key;
38
+ key.attach(this);
39
+ }
40
+
41
+ @JRubyMethod
42
+ public IRubyObject io(ThreadContext context) {
43
+ return io;
44
+ }
45
+
46
+ @JRubyMethod
47
+ public IRubyObject selector(ThreadContext context) {
48
+ return selector;
49
+ }
50
+
51
+ @JRubyMethod(name = "interests")
52
+ public IRubyObject getInterests(ThreadContext context) {
53
+ return interests;
54
+ }
55
+
56
+ @JRubyMethod(name = "interests=")
57
+ public IRubyObject setInterests(ThreadContext context, IRubyObject interests) {
58
+ if(this.closed == context.getRuntime().getTrue()) {
59
+ throw context.getRuntime().newEOFError("monitor is closed");
60
+ }
61
+
62
+ Ruby ruby = context.getRuntime();
63
+ SelectableChannel channel = (SelectableChannel)io.getChannel();
64
+
65
+ key.interestOps(Nio4r.symbolToInterestOps(ruby, channel, interests));
66
+ this.interests = interests;
67
+
68
+ return this.interests;
69
+ }
70
+
71
+ @JRubyMethod(name = "add_interest")
72
+ public IRubyObject addInterest(ThreadContext context, IRubyObject interest) {
73
+ if(this.closed == context.getRuntime().getTrue()) {
74
+ throw context.getRuntime().newEOFError("monitor is closed");
75
+ }
76
+
77
+ Ruby ruby = context.getRuntime();
78
+ SelectableChannel channel = (SelectableChannel)io.getChannel();
79
+ int newInterestOps = key.interestOps() | Nio4r.symbolToInterestOps(ruby, channel, interest);
80
+
81
+ key.interestOps(newInterestOps);
82
+ this.interests = Nio4r.interestOpsToSymbol(ruby, newInterestOps);
83
+
84
+ return this.interests;
85
+ }
86
+
87
+ @JRubyMethod(name = "remove_interest")
88
+ public IRubyObject removeInterest(ThreadContext context, IRubyObject interest) {
89
+ if(this.closed == context.getRuntime().getTrue()) {
90
+ throw context.getRuntime().newEOFError("monitor is closed");
91
+ }
92
+
93
+ Ruby ruby = context.getRuntime();
94
+ SelectableChannel channel = (SelectableChannel)io.getChannel();
95
+ int newInterestOps = key.interestOps() & ~Nio4r.symbolToInterestOps(ruby, channel, interest);
96
+
97
+ key.interestOps(newInterestOps);
98
+ this.interests = Nio4r.interestOpsToSymbol(ruby, newInterestOps);
99
+
100
+ return this.interests;
101
+ }
102
+
103
+ @JRubyMethod
104
+ public IRubyObject readiness(ThreadContext context) {
105
+ return Nio4r.interestOpsToSymbol(context.getRuntime(), key.readyOps());
106
+ }
107
+
108
+ @JRubyMethod(name = "readable?")
109
+ public IRubyObject isReadable(ThreadContext context) {
110
+ Ruby runtime = context.getRuntime();
111
+ int readyOps = this.key.readyOps();
112
+
113
+ if((readyOps & SelectionKey.OP_READ) != 0 || (readyOps & SelectionKey.OP_ACCEPT) != 0) {
114
+ return runtime.getTrue();
115
+ } else {
116
+ return runtime.getFalse();
117
+ }
118
+ }
119
+
120
+ @JRubyMethod(name = {"writable?", "writeable?"})
121
+ public IRubyObject writable(ThreadContext context) {
122
+ Ruby runtime = context.getRuntime();
123
+ int readyOps = this.key.readyOps();
124
+
125
+ if((readyOps & SelectionKey.OP_WRITE) != 0 || (readyOps & SelectionKey.OP_CONNECT) != 0) {
126
+ return runtime.getTrue();
127
+ } else {
128
+ return runtime.getFalse();
129
+ }
130
+ }
131
+
132
+ @JRubyMethod(name = "value")
133
+ public IRubyObject getValue(ThreadContext context) {
134
+ return this.value;
135
+ }
136
+
137
+ @JRubyMethod(name = "value=")
138
+ public IRubyObject setValue(ThreadContext context, IRubyObject obj) {
139
+ this.value = obj;
140
+ return context.nil;
141
+ }
142
+
143
+ @JRubyMethod
144
+ public IRubyObject close(ThreadContext context) {
145
+ return close(context, context.getRuntime().getTrue());
146
+ }
147
+
148
+ @JRubyMethod
149
+ public IRubyObject close(ThreadContext context, IRubyObject deregister) {
150
+ Ruby runtime = context.getRuntime();
151
+ this.closed = runtime.getTrue();
152
+
153
+ if(deregister == runtime.getTrue()) {
154
+ selector.callMethod(context, "deregister", io);
155
+ }
156
+
157
+ return context.nil;
158
+ }
159
+
160
+ @JRubyMethod(name = "closed?")
161
+ public IRubyObject isClosed(ThreadContext context) {
162
+ return this.closed;
163
+ }
164
+ }
@@ -1,27 +1,19 @@
1
1
  package org.nio4r;
2
2
 
3
- import java.util.Iterator;
4
- import java.util.Map;
5
- import java.util.HashMap;
6
- import java.io.IOException;
7
- import java.nio.channels.Channel;
8
- import java.nio.channels.SocketChannel;
9
3
  import java.nio.channels.SelectableChannel;
10
4
  import java.nio.channels.SelectionKey;
5
+ import java.nio.channels.SocketChannel;
6
+
11
7
  import org.jruby.Ruby;
12
- import org.jruby.RubyModule;
13
8
  import org.jruby.RubyClass;
14
- import org.jruby.RubyObject;
15
- import org.jruby.RubyIO;
16
- import org.jruby.RubyNumeric;
17
- import org.jruby.RubyArray;
18
- import org.jruby.anno.JRubyMethod;
9
+ import org.jruby.RubyModule;
19
10
  import org.jruby.runtime.ObjectAllocator;
20
- import org.jruby.runtime.ThreadContext;
21
11
  import org.jruby.runtime.load.Library;
22
12
  import org.jruby.runtime.builtin.IRubyObject;
23
- import org.jruby.runtime.Block;
13
+
24
14
  import org.nio4r.ByteBuffer;
15
+ import org.nio4r.Monitor;
16
+ import org.nio4r.Selector;
25
17
 
26
18
  public class Nio4r implements Library {
27
19
  private Ruby ruby;
@@ -54,6 +46,11 @@ public class Nio4r implements Library {
54
46
  }, nio);
55
47
 
56
48
  byteBuffer.defineAnnotatedMethods(ByteBuffer.class);
49
+ byteBuffer.includeModule(ruby.getEnumerable());
50
+
51
+ ruby.defineClassUnder("OverflowError", ruby.getIOError(), ruby.getIOError().getAllocator(), byteBuffer);
52
+ ruby.defineClassUnder("UnderflowError", ruby.getIOError(), ruby.getIOError().getAllocator(), byteBuffer);
53
+ ruby.defineClassUnder("MarkUnsetError", ruby.getIOError(), ruby.getIOError().getAllocator(), byteBuffer);
57
54
  }
58
55
 
59
56
  public static int symbolToInterestOps(Ruby ruby, SelectableChannel channel, IRubyObject interest) {
@@ -98,385 +95,10 @@ public class Nio4r implements Library {
98
95
  case SelectionKey.OP_READ | SelectionKey.OP_CONNECT:
99
96
  case SelectionKey.OP_READ | SelectionKey.OP_WRITE:
100
97
  return ruby.newSymbol("rw");
98
+ case 0:
99
+ return ruby.getNil();
101
100
  default:
102
101
  throw ruby.newArgumentError("unknown interest op combination");
103
102
  }
104
103
  }
105
-
106
- public class Selector extends RubyObject {
107
- private java.nio.channels.Selector selector;
108
- private HashMap<SelectableChannel,SelectionKey> cancelledKeys;
109
-
110
- public Selector(final Ruby ruby, RubyClass rubyClass) {
111
- super(ruby, rubyClass);
112
- }
113
-
114
- @JRubyMethod
115
- public IRubyObject initialize(ThreadContext context) {
116
- this.cancelledKeys = new HashMap<SelectableChannel,SelectionKey>();
117
- try {
118
- this.selector = java.nio.channels.Selector.open();
119
- } catch(IOException ie) {
120
- throw context.runtime.newIOError(ie.getLocalizedMessage());
121
- }
122
-
123
- return context.nil;
124
- }
125
-
126
- @JRubyMethod
127
- public IRubyObject close(ThreadContext context) {
128
- try {
129
- this.selector.close();
130
- } catch(IOException ie) {
131
- throw context.runtime.newIOError(ie.getLocalizedMessage());
132
- }
133
-
134
- return context.nil;
135
- }
136
-
137
- @JRubyMethod(name = "closed?")
138
- public IRubyObject isClosed(ThreadContext context) {
139
- Ruby runtime = context.getRuntime();
140
- return this.selector.isOpen() ? runtime.getFalse() : runtime.getTrue();
141
- }
142
-
143
- @JRubyMethod(name = "empty?")
144
- public IRubyObject isEmpty(ThreadContext context) {
145
- Ruby runtime = context.getRuntime();
146
- return this.selector.keys().isEmpty() ? runtime.getTrue() : runtime.getFalse();
147
- }
148
-
149
- @JRubyMethod
150
- public IRubyObject register(ThreadContext context, IRubyObject io, IRubyObject interests) {
151
- Ruby runtime = context.getRuntime();
152
- Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
153
-
154
- if(!this.selector.isOpen()) {
155
- throw context.getRuntime().newIOError("selector is closed");
156
- }
157
-
158
- if(!(rawChannel instanceof SelectableChannel)) {
159
- throw runtime.newArgumentError("not a selectable IO object");
160
- }
161
-
162
- SelectableChannel channel = (SelectableChannel)rawChannel;
163
-
164
- try {
165
- channel.configureBlocking(false);
166
- } catch(IOException ie) {
167
- throw runtime.newIOError(ie.getLocalizedMessage());
168
- }
169
-
170
- int interestOps = Nio4r.symbolToInterestOps(runtime, channel, interests);
171
- SelectionKey key;
172
-
173
- key = this.cancelledKeys.remove(channel);
174
-
175
- if(key != null) {
176
- key.interestOps(interestOps);
177
- } else {
178
- try {
179
- key = channel.register(this.selector, interestOps);
180
- } catch(java.lang.IllegalArgumentException ia) {
181
- throw runtime.newArgumentError("mode not supported for this object: " + interests);
182
- } catch(java.nio.channels.ClosedChannelException cce) {
183
- throw context.runtime.newIOError(cce.getLocalizedMessage());
184
- }
185
- }
186
-
187
- RubyClass monitorClass = runtime.getModule("NIO").getClass("Monitor");
188
- Monitor monitor = (Monitor)monitorClass.newInstance(context, io, interests, this, null);
189
- monitor.setSelectionKey(key);
190
-
191
- return monitor;
192
- }
193
-
194
- @JRubyMethod
195
- public IRubyObject deregister(ThreadContext context, IRubyObject io) {
196
- Ruby runtime = context.getRuntime();
197
- Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
198
-
199
- if(!(rawChannel instanceof SelectableChannel)) {
200
- throw runtime.newArgumentError("not a selectable IO object");
201
- }
202
-
203
- SelectableChannel channel = (SelectableChannel)rawChannel;
204
- SelectionKey key = channel.keyFor(this.selector);
205
-
206
- if(key == null)
207
- return context.nil;
208
-
209
- Monitor monitor = (Monitor)key.attachment();
210
- monitor.close(context, runtime.getFalse());
211
- cancelledKeys.put(channel, key);
212
-
213
- return monitor;
214
- }
215
-
216
- @JRubyMethod(name = "registered?")
217
- public IRubyObject isRegistered(ThreadContext context, IRubyObject io) {
218
- Ruby runtime = context.getRuntime();
219
- Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
220
-
221
- if(!(rawChannel instanceof SelectableChannel)) {
222
- throw runtime.newArgumentError("not a selectable IO object");
223
- }
224
-
225
- SelectableChannel channel = (SelectableChannel)rawChannel;
226
- SelectionKey key = channel.keyFor(this.selector);
227
-
228
- if(key == null)
229
- return context.nil;
230
-
231
-
232
- if(((Monitor)key.attachment()).isClosed(context) == runtime.getTrue()) {
233
- return runtime.getFalse();
234
- } else {
235
- return runtime.getTrue();
236
- }
237
- }
238
-
239
- @JRubyMethod
240
- public synchronized IRubyObject select(ThreadContext context, Block block) {
241
- return select(context, context.nil, block);
242
- }
243
-
244
- @JRubyMethod
245
- public synchronized IRubyObject select(ThreadContext context, IRubyObject timeout, Block block) {
246
- Ruby runtime = context.getRuntime();
247
-
248
- if(!this.selector.isOpen()) {
249
- throw context.getRuntime().newIOError("selector is closed");
250
- }
251
-
252
- int ready = doSelect(runtime, context, timeout);
253
-
254
- /* Timeout or wakeup */
255
- if(ready <= 0)
256
- return context.nil;
257
-
258
- RubyArray array = null;
259
- if(!block.isGiven()) {
260
- array = runtime.newArray(this.selector.selectedKeys().size());
261
- }
262
-
263
- Iterator selectedKeys = this.selector.selectedKeys().iterator();
264
- while(selectedKeys.hasNext()) {
265
- SelectionKey key = (SelectionKey)selectedKeys.next();
266
- processKey(key);
267
- selectedKeys.remove();
268
-
269
- if(block.isGiven()) {
270
- block.call(context, (IRubyObject)key.attachment());
271
- } else {
272
- array.add(key.attachment());
273
- }
274
- }
275
-
276
- if(block.isGiven()) {
277
- return RubyNumeric.int2fix(runtime, ready);
278
- } else {
279
- return array;
280
- }
281
- }
282
-
283
- /* Run the selector */
284
- private int doSelect(Ruby runtime, ThreadContext context, IRubyObject timeout) {
285
- int result;
286
-
287
- cancelKeys();
288
- try {
289
- context.getThread().beforeBlockingCall();
290
- if(timeout.isNil()) {
291
- result = this.selector.select();
292
- } else {
293
- double t = RubyNumeric.num2dbl(timeout);
294
- if(t == 0) {
295
- result = this.selector.selectNow();
296
- } else if(t < 0) {
297
- throw runtime.newArgumentError("time interval must be positive");
298
- } else {
299
- long timeoutMilliSeconds = (long)(t * 1000);
300
- if(timeoutMilliSeconds == 0) {
301
- result = this.selector.selectNow();
302
- } else {
303
- result = this.selector.select(timeoutMilliSeconds);
304
- }
305
- }
306
- }
307
- context.getThread().afterBlockingCall();
308
- return result;
309
- } catch(IOException ie) {
310
- throw runtime.newIOError(ie.getLocalizedMessage());
311
- }
312
- }
313
-
314
- /* Flush our internal buffer of cancelled keys */
315
- private void cancelKeys() {
316
- Iterator cancelledKeys = this.cancelledKeys.entrySet().iterator();
317
- while(cancelledKeys.hasNext()) {
318
- Map.Entry entry = (Map.Entry)cancelledKeys.next();
319
- SelectionKey key = (SelectionKey)entry.getValue();
320
- key.cancel();
321
- cancelledKeys.remove();
322
- }
323
- }
324
-
325
- // Remove connect interest from connected sockets
326
- // See: http://stackoverflow.com/questions/204186/java-nio-select-returns-without-selected-keys-why
327
- private void processKey(SelectionKey key) {
328
- if((key.readyOps() & SelectionKey.OP_CONNECT) != 0) {
329
- int interestOps = key.interestOps();
330
-
331
- interestOps &= ~SelectionKey.OP_CONNECT;
332
- interestOps |= SelectionKey.OP_WRITE;
333
-
334
- key.interestOps(interestOps);
335
- }
336
- }
337
-
338
- @JRubyMethod
339
- public IRubyObject wakeup(ThreadContext context) {
340
- if(!this.selector.isOpen()) {
341
- throw context.getRuntime().newIOError("selector is closed");
342
- }
343
-
344
- this.selector.wakeup();
345
- return context.nil;
346
- }
347
- }
348
-
349
- public class Monitor extends RubyObject {
350
- private SelectionKey key;
351
- private RubyIO io;
352
- private IRubyObject interests, selector, value, closed;
353
-
354
- public Monitor(final Ruby ruby, RubyClass rubyClass) {
355
- super(ruby, rubyClass);
356
- }
357
-
358
- @JRubyMethod
359
- public IRubyObject initialize(ThreadContext context, IRubyObject selectable, IRubyObject interests, IRubyObject selector) {
360
- this.io = RubyIO.convertToIO(context, selectable);
361
- this.interests = interests;
362
- this.selector = selector;
363
-
364
- this.value = context.nil;
365
- this.closed = context.getRuntime().getFalse();
366
-
367
- return context.nil;
368
- }
369
-
370
- public void setSelectionKey(SelectionKey key) {
371
- this.key = key;
372
- key.attach(this);
373
- }
374
-
375
- @JRubyMethod(name = "interests=")
376
- public IRubyObject setInterests(ThreadContext context, IRubyObject interests) {
377
- if(this.closed == context.getRuntime().getTrue()) {
378
- throw context.getRuntime().newTypeError("monitor is already closed");
379
- }
380
-
381
- int interestOps = 0;
382
- Ruby runtime = context.getRuntime();
383
- Channel rawChannel = io.getChannel();
384
- SelectableChannel channel = (SelectableChannel)rawChannel;
385
-
386
- this.interests = interests;
387
-
388
- if(interests == ruby.newSymbol("r")) {
389
- interestOps = SelectionKey.OP_READ;
390
- } else if(interests == ruby.newSymbol("w")) {
391
- interestOps = SelectionKey.OP_WRITE;
392
- } else if(interests == ruby.newSymbol("rw")) {
393
- interestOps = SelectionKey.OP_READ|SelectionKey.OP_WRITE;
394
- }
395
-
396
- if((interestOps & ~(channel.validOps())) == 0) {
397
- key.interestOps(interestOps);
398
- } else {
399
- throw context.getRuntime().newArgumentError("given interests not supported for this IO object");
400
- }
401
-
402
- return this.interests;
403
- }
404
-
405
- @JRubyMethod
406
- public IRubyObject io(ThreadContext context) {
407
- return io;
408
- }
409
-
410
- @JRubyMethod
411
- public IRubyObject selector(ThreadContext context) {
412
- return selector;
413
- }
414
-
415
- @JRubyMethod
416
- public IRubyObject interests(ThreadContext context) {
417
- return interests;
418
- }
419
-
420
- @JRubyMethod
421
- public IRubyObject readiness(ThreadContext context) {
422
- return Nio4r.interestOpsToSymbol(context.getRuntime(), key.readyOps());
423
- }
424
-
425
- @JRubyMethod(name = "readable?")
426
- public IRubyObject isReadable(ThreadContext context) {
427
- Ruby runtime = context.getRuntime();
428
- int readyOps = this.key.readyOps();
429
-
430
- if((readyOps & SelectionKey.OP_READ) != 0 || (readyOps & SelectionKey.OP_ACCEPT) != 0) {
431
- return runtime.getTrue();
432
- } else {
433
- return runtime.getFalse();
434
- }
435
- }
436
-
437
- @JRubyMethod(name = {"writable?", "writeable?"})
438
- public IRubyObject writable(ThreadContext context) {
439
- Ruby runtime = context.getRuntime();
440
- int readyOps = this.key.readyOps();
441
-
442
- if((readyOps & SelectionKey.OP_WRITE) != 0 || (readyOps & SelectionKey.OP_CONNECT) != 0) {
443
- return runtime.getTrue();
444
- } else {
445
- return runtime.getFalse();
446
- }
447
- }
448
-
449
- @JRubyMethod(name = "value")
450
- public IRubyObject getValue(ThreadContext context) {
451
- return this.value;
452
- }
453
-
454
- @JRubyMethod(name = "value=")
455
- public IRubyObject setValue(ThreadContext context, IRubyObject obj) {
456
- this.value = obj;
457
- return context.nil;
458
- }
459
-
460
- @JRubyMethod
461
- public IRubyObject close(ThreadContext context) {
462
- return close(context, context.getRuntime().getTrue());
463
- }
464
-
465
- @JRubyMethod
466
- public IRubyObject close(ThreadContext context, IRubyObject deregister) {
467
- Ruby runtime = context.getRuntime();
468
- this.closed = runtime.getTrue();
469
-
470
- if(deregister == runtime.getTrue()) {
471
- selector.callMethod(context, "deregister", io);
472
- }
473
-
474
- return context.nil;
475
- }
476
-
477
- @JRubyMethod(name = "closed?")
478
- public IRubyObject isClosed(ThreadContext context) {
479
- return this.closed;
480
- }
481
- }
482
104
  }