nio4r 2.0.0.pre-java → 2.1.0-java
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.
- checksums.yaml +4 -4
- data/.rspec +0 -1
- data/.rubocop.yml +31 -38
- data/.ruby-version +1 -0
- data/.travis.yml +9 -19
- data/CHANGES.md +94 -42
- data/Gemfile +11 -3
- data/Guardfile +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +43 -136
- data/Rakefile +2 -0
- data/examples/echo_server.rb +1 -0
- data/ext/libev/Changes +9 -13
- data/ext/libev/ev.c +100 -74
- data/ext/libev/ev.h +4 -9
- data/ext/libev/ev_epoll.c +6 -3
- data/ext/libev/ev_kqueue.c +8 -4
- data/ext/libev/ev_poll.c +6 -3
- data/ext/libev/ev_port.c +8 -4
- data/ext/libev/ev_select.c +4 -2
- data/ext/nio4r/bytebuffer.c +265 -257
- data/ext/nio4r/extconf.rb +3 -9
- data/ext/nio4r/monitor.c +93 -46
- data/ext/nio4r/nio4r.h +6 -16
- data/ext/nio4r/org/nio4r/ByteBuffer.java +193 -209
- data/ext/nio4r/org/nio4r/Monitor.java +164 -0
- data/ext/nio4r/org/nio4r/Nio4r.java +13 -391
- data/ext/nio4r/org/nio4r/Selector.java +278 -0
- data/ext/nio4r/selector.c +72 -64
- data/lib/nio.rb +3 -3
- data/lib/nio/bytebuffer.rb +179 -132
- data/lib/nio/monitor.rb +64 -4
- data/lib/nio/selector.rb +36 -13
- data/lib/nio/version.rb +1 -1
- data/nio4r.gemspec +25 -19
- data/spec/nio/acceptables_spec.rb +6 -4
- data/spec/nio/bytebuffer_spec.rb +323 -51
- data/spec/nio/monitor_spec.rb +122 -79
- data/spec/nio/selectables/pipe_spec.rb +5 -1
- data/spec/nio/selectables/ssl_socket_spec.rb +15 -12
- data/spec/nio/selectables/tcp_socket_spec.rb +42 -31
- data/spec/nio/selectables/udp_socket_spec.rb +2 -0
- data/spec/nio/selector_spec.rb +10 -4
- data/spec/spec_helper.rb +24 -3
- data/spec/support/selectable_examples.rb +7 -5
- data/tasks/extension.rake +2 -0
- data/tasks/rspec.rake +2 -0
- data/tasks/rubocop.rake +2 -0
- metadata +18 -15
- 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.
|
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
|
-
|
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
|
}
|