nio4r 2.4.0 → 2.5.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/workflow.yml +47 -0
  3. data/.rubocop.yml +30 -11
  4. data/CHANGES.md +63 -0
  5. data/Gemfile +1 -1
  6. data/README.md +57 -30
  7. data/examples/echo_server.rb +2 -2
  8. data/ext/libev/Changes +90 -2
  9. data/ext/libev/README +2 -1
  10. data/ext/libev/ev.c +708 -247
  11. data/ext/libev/ev.h +33 -29
  12. data/ext/libev/ev_epoll.c +41 -28
  13. data/ext/libev/ev_iouring.c +694 -0
  14. data/ext/libev/ev_kqueue.c +15 -9
  15. data/ext/libev/ev_linuxaio.c +620 -0
  16. data/ext/libev/ev_poll.c +19 -14
  17. data/ext/libev/ev_port.c +8 -5
  18. data/ext/libev/ev_select.c +6 -6
  19. data/ext/libev/ev_vars.h +46 -1
  20. data/ext/libev/ev_win32.c +2 -2
  21. data/ext/libev/ev_wrap.h +72 -0
  22. data/ext/nio4r/.clang-format +16 -0
  23. data/ext/nio4r/bytebuffer.c +27 -28
  24. data/ext/nio4r/extconf.rb +9 -0
  25. data/ext/nio4r/libev.h +1 -3
  26. data/ext/nio4r/monitor.c +34 -31
  27. data/ext/nio4r/nio4r.h +7 -12
  28. data/ext/nio4r/org/nio4r/ByteBuffer.java +2 -0
  29. data/ext/nio4r/org/nio4r/Monitor.java +1 -0
  30. data/ext/nio4r/org/nio4r/Selector.java +13 -11
  31. data/ext/nio4r/selector.c +66 -51
  32. data/lib/nio.rb +20 -1
  33. data/lib/nio/bytebuffer.rb +4 -0
  34. data/lib/nio/monitor.rb +1 -1
  35. data/lib/nio/selector.rb +12 -10
  36. data/lib/nio/version.rb +1 -1
  37. data/nio4r.gemspec +10 -2
  38. data/spec/nio/bytebuffer_spec.rb +0 -1
  39. data/spec/nio/selectables/ssl_socket_spec.rb +3 -1
  40. data/spec/nio/selectables/udp_socket_spec.rb +2 -2
  41. data/spec/nio/selector_spec.rb +27 -5
  42. data/spec/spec_helper.rb +2 -0
  43. metadata +17 -12
  44. data/.travis.yml +0 -29
  45. data/Guardfile +0 -10
  46. data/LICENSE.txt +0 -20
  47. data/appveyor.yml +0 -40
data/ext/nio4r/extconf.rb CHANGED
@@ -4,6 +4,7 @@ require "rubygems"
4
4
 
5
5
  # Write a dummy Makefile on Windows because we use the pure Ruby implementation there
6
6
  if Gem.win_platform?
7
+ require "devkit" if RUBY_PLATFORM.include?("mingw")
7
8
  File.write("Makefile", "all install::\n")
8
9
  File.write("nio4r_ext.so", "")
9
10
  exit
@@ -13,6 +14,8 @@ require "mkmf"
13
14
 
14
15
  have_header("unistd.h")
15
16
 
17
+ $defs << "-DEV_USE_LINUXAIO" if have_header("linux/aio_abi.h")
18
+ $defs << "-DEV_USE_IOURING" if have_header("linux/io_uring.h")
16
19
  $defs << "-DEV_USE_SELECT" if have_header("sys/select.h")
17
20
  $defs << "-DEV_USE_POLL" if have_type("port_event_t", "poll.h")
18
21
  $defs << "-DEV_USE_EPOLL" if have_header("sys/epoll.h")
@@ -20,7 +23,13 @@ $defs << "-DEV_USE_KQUEUE" if have_header("sys/event.h") && have_header("s
20
23
  $defs << "-DEV_USE_PORT" if have_type("port_event_t", "port.h")
21
24
  $defs << "-DHAVE_SYS_RESOURCE_H" if have_header("sys/resource.h")
22
25
 
26
+ $defs << "-DEV_STANDALONE" # prevent libev from assuming "config.h" exists
27
+
23
28
  CONFIG["optflags"] << " -fno-strict-aliasing" unless RUBY_PLATFORM =~ /mswin/
24
29
 
30
+ if RUBY_PLATFORM =~ /darwin/
31
+ $DLDFLAGS.gsub!(/\-arch\s+[^\s]+/, "")
32
+ end
33
+
25
34
  dir_config "nio4r_ext"
26
35
  create_makefile "nio4r_ext"
data/ext/nio4r/libev.h CHANGED
@@ -1,9 +1,7 @@
1
- #define EV_STANDALONE /* keeps ev from requiring config.h */
2
-
3
1
  #ifdef _WIN32
4
2
  #define EV_SELECT_IS_WINSOCKET 1
5
3
  #define EV_USE_MONOTONIC 0
6
4
  #define EV_USE_REALTIME 0
7
5
  #endif
8
6
 
9
- #include "../libev/ev.h"
7
+ #include "../libev/ev.h"
data/ext/nio4r/monitor.c CHANGED
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  #include "nio4r.h"
7
+ #include <assert.h>
7
8
 
8
9
  static VALUE mNIO = Qnil;
9
10
  static VALUE cNIO_Monitor = Qnil;
@@ -60,12 +61,14 @@ void Init_NIO_Monitor()
60
61
  static VALUE NIO_Monitor_allocate(VALUE klass)
61
62
  {
62
63
  struct NIO_Monitor *monitor = (struct NIO_Monitor *)xmalloc(sizeof(struct NIO_Monitor));
63
-
64
+ assert(monitor);
65
+ *monitor = (struct NIO_Monitor){.self = Qnil};
64
66
  return Data_Wrap_Struct(klass, NIO_Monitor_mark, NIO_Monitor_free, monitor);
65
67
  }
66
68
 
67
69
  static void NIO_Monitor_mark(struct NIO_Monitor *monitor)
68
70
  {
71
+ rb_gc_mark(monitor->self);
69
72
  }
70
73
 
71
74
  static void NIO_Monitor_free(struct NIO_Monitor *monitor)
@@ -84,15 +87,14 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
84
87
 
85
88
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
86
89
 
87
- if(interests_id == rb_intern("r")) {
90
+ if (interests_id == rb_intern("r")) {
88
91
  monitor->interests = EV_READ;
89
- } else if(interests_id == rb_intern("w")) {
92
+ } else if (interests_id == rb_intern("w")) {
90
93
  monitor->interests = EV_WRITE;
91
- } else if(interests_id == rb_intern("rw")) {
94
+ } else if (interests_id == rb_intern("rw")) {
92
95
  monitor->interests = EV_READ | EV_WRITE;
93
96
  } else {
94
- rb_raise(rb_eArgError, "invalid event type %s (must be :r, :w, or :rw)",
95
- RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
97
+ rb_raise(rb_eArgError, "invalid event type %s (must be :r, :w, or :rw)", RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
96
98
  }
97
99
 
98
100
  GetOpenFile(rb_convert_type(io, T_FILE, "IO", "to_io"), fptr);
@@ -112,7 +114,7 @@ static VALUE NIO_Monitor_initialize(VALUE self, VALUE io, VALUE interests, VALUE
112
114
  monitor->selector = selector;
113
115
 
114
116
  if (monitor->interests) {
115
- ev_io_start(selector->ev_loop, &monitor->ev_io);
117
+ ev_io_start(selector->ev_loop, &monitor->ev_io);
116
118
  }
117
119
 
118
120
  return Qnil;
@@ -127,17 +129,17 @@ static VALUE NIO_Monitor_close(int argc, VALUE *argv, VALUE self)
127
129
  rb_scan_args(argc, argv, "01", &deregister);
128
130
  selector = rb_ivar_get(self, rb_intern("selector"));
129
131
 
130
- if(selector != Qnil) {
132
+ if (selector != Qnil) {
131
133
  /* if ev_loop is 0, it means that the loop has been stopped already (see NIO_Selector_shutdown) */
132
- if(monitor->interests && monitor->selector->ev_loop) {
133
- ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
134
+ if (monitor->interests && monitor->selector->ev_loop) {
135
+ ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
134
136
  }
135
137
 
136
138
  monitor->selector = 0;
137
139
  rb_ivar_set(self, rb_intern("selector"), Qnil);
138
-
140
+
139
141
  /* Default value is true */
140
- if(deregister == Qtrue || deregister == Qnil) {
142
+ if (deregister == Qtrue || deregister == Qnil) {
141
143
  rb_funcall(selector, rb_intern("deregister"), 1, rb_ivar_get(self, rb_intern("io")));
142
144
  }
143
145
  }
@@ -165,7 +167,7 @@ static VALUE NIO_Monitor_interests(VALUE self)
165
167
 
166
168
  static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
167
169
  {
168
- if(NIL_P(interests)) {
170
+ if (NIL_P(interests)) {
169
171
  NIO_Monitor_update_interests(self, 0);
170
172
  } else {
171
173
  NIO_Monitor_update_interests(self, NIO_Monitor_symbol2interest(interests));
@@ -174,7 +176,8 @@ static VALUE NIO_Monitor_set_interests(VALUE self, VALUE interests)
174
176
  return rb_ivar_get(self, rb_intern("interests"));
175
177
  }
176
178
 
177
- static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest) {
179
+ static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest)
180
+ {
178
181
  struct NIO_Monitor *monitor;
179
182
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
180
183
 
@@ -184,7 +187,8 @@ static VALUE NIO_Monitor_add_interest(VALUE self, VALUE interest) {
184
187
  return rb_ivar_get(self, rb_intern("interests"));
185
188
  }
186
189
 
187
- static VALUE NIO_Monitor_remove_interest(VALUE self, VALUE interest) {
190
+ static VALUE NIO_Monitor_remove_interest(VALUE self, VALUE interest)
191
+ {
188
192
  struct NIO_Monitor *monitor;
189
193
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
190
194
 
@@ -214,11 +218,11 @@ static VALUE NIO_Monitor_readiness(VALUE self)
214
218
  struct NIO_Monitor *monitor;
215
219
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
216
220
 
217
- if((monitor->revents & (EV_READ | EV_WRITE)) == (EV_READ | EV_WRITE)) {
221
+ if ((monitor->revents & (EV_READ | EV_WRITE)) == (EV_READ | EV_WRITE)) {
218
222
  return ID2SYM(rb_intern("rw"));
219
- } else if(monitor->revents & EV_READ) {
223
+ } else if (monitor->revents & EV_READ) {
220
224
  return ID2SYM(rb_intern("r"));
221
- } else if(monitor->revents & EV_WRITE) {
225
+ } else if (monitor->revents & EV_WRITE) {
222
226
  return ID2SYM(rb_intern("w"));
223
227
  } else {
224
228
  return Qnil;
@@ -230,7 +234,7 @@ static VALUE NIO_Monitor_is_readable(VALUE self)
230
234
  struct NIO_Monitor *monitor;
231
235
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
232
236
 
233
- if(monitor->revents & EV_READ) {
237
+ if (monitor->revents & EV_READ) {
234
238
  return Qtrue;
235
239
  } else {
236
240
  return Qfalse;
@@ -242,7 +246,7 @@ static VALUE NIO_Monitor_is_writable(VALUE self)
242
246
  struct NIO_Monitor *monitor;
243
247
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
244
248
 
245
- if(monitor->revents & EV_WRITE) {
249
+ if (monitor->revents & EV_WRITE) {
246
250
  return Qtrue;
247
251
  } else {
248
252
  return Qfalse;
@@ -256,15 +260,14 @@ static int NIO_Monitor_symbol2interest(VALUE interests)
256
260
  ID interests_id;
257
261
  interests_id = SYM2ID(interests);
258
262
 
259
- if(interests_id == rb_intern("r")) {
263
+ if (interests_id == rb_intern("r")) {
260
264
  return EV_READ;
261
- } else if(interests_id == rb_intern("w")) {
265
+ } else if (interests_id == rb_intern("w")) {
262
266
  return EV_WRITE;
263
- } else if(interests_id == rb_intern("rw")) {
267
+ } else if (interests_id == rb_intern("rw")) {
264
268
  return EV_READ | EV_WRITE;
265
269
  } else {
266
- rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)",
267
- RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
270
+ rb_raise(rb_eArgError, "invalid interest type %s (must be :r, :w, or :rw)", RSTRING_PTR(rb_funcall(interests, rb_intern("inspect"), 0)));
268
271
  }
269
272
  }
270
273
 
@@ -274,12 +277,12 @@ static void NIO_Monitor_update_interests(VALUE self, int interests)
274
277
  struct NIO_Monitor *monitor;
275
278
  Data_Get_Struct(self, struct NIO_Monitor, monitor);
276
279
 
277
- if(NIO_Monitor_is_closed(self) == Qtrue) {
280
+ if (NIO_Monitor_is_closed(self) == Qtrue) {
278
281
  rb_raise(rb_eEOFError, "monitor is closed");
279
282
  }
280
283
 
281
- if(interests) {
282
- switch(interests) {
284
+ if (interests) {
285
+ switch (interests) {
283
286
  case EV_READ:
284
287
  interests_id = rb_intern("r");
285
288
  break;
@@ -298,9 +301,9 @@ static void NIO_Monitor_update_interests(VALUE self, int interests)
298
301
  rb_ivar_set(self, rb_intern("interests"), Qnil);
299
302
  }
300
303
 
301
- if(monitor->interests != interests) {
304
+ if (monitor->interests != interests) {
302
305
  // If the monitor currently has interests, we should stop it.
303
- if(monitor->interests) {
306
+ if (monitor->interests) {
304
307
  ev_io_stop(monitor->selector->ev_loop, &monitor->ev_io);
305
308
  }
306
309
 
@@ -309,7 +312,7 @@ static void NIO_Monitor_update_interests(VALUE self, int interests)
309
312
  ev_io_set(&monitor->ev_io, monitor->ev_io.fd, monitor->interests);
310
313
 
311
314
  // If we are interested in events, schedule the monitor back into the event loop:
312
- if(monitor->interests) {
315
+ if (monitor->interests) {
313
316
  ev_io_start(monitor->selector->ev_loop, &monitor->ev_io);
314
317
  }
315
318
  }
data/ext/nio4r/nio4r.h CHANGED
@@ -6,12 +6,11 @@
6
6
  #ifndef NIO4R_H
7
7
  #define NIO4R_H
8
8
 
9
+ #include "libev.h"
9
10
  #include "ruby.h"
10
11
  #include "ruby/io.h"
11
- #include "libev.h"
12
12
 
13
- struct NIO_Selector
14
- {
13
+ struct NIO_Selector {
15
14
  struct ev_loop *ev_loop;
16
15
  struct ev_timer timer; /* for timeouts */
17
16
  struct ev_io wakeup;
@@ -24,31 +23,27 @@ struct NIO_Selector
24
23
  VALUE ready_array;
25
24
  };
26
25
 
27
- struct NIO_callback_data
28
- {
26
+ struct NIO_callback_data {
29
27
  VALUE *monitor;
30
28
  struct NIO_Selector *selector;
31
29
  };
32
30
 
33
- struct NIO_Monitor
34
- {
31
+ struct NIO_Monitor {
35
32
  VALUE self;
36
33
  int interests, revents;
37
34
  struct ev_io ev_io;
38
35
  struct NIO_Selector *selector;
39
36
  };
40
37
 
41
- struct NIO_ByteBuffer
42
- {
38
+ struct NIO_ByteBuffer {
43
39
  char *buffer;
44
40
  int position, limit, capacity, mark;
45
41
  };
46
42
 
47
-
48
43
  #ifdef GetReadFile
49
- # define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
44
+ #define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
50
45
  #else
51
- # define FPTR_TO_FD(fptr) fptr->fd
46
+ #define FPTR_TO_FD(fptr) fptr->fd
52
47
  #endif /* GetReadFile */
53
48
 
54
49
  /* Thunk between libev callbacks in NIO::Monitors and NIO::Selectors */
@@ -1,6 +1,7 @@
1
1
  package org.nio4r;
2
2
 
3
3
  import java.io.IOException;
4
+ import java.io.Serializable;
4
5
  import java.nio.channels.Channel;
5
6
  import java.nio.channels.SelectableChannel;
6
7
  import java.nio.channels.ReadableByteChannel;
@@ -25,6 +26,7 @@ import org.jruby.runtime.Block;
25
26
  created by Upekshej
26
27
  */
27
28
  public class ByteBuffer extends RubyObject {
29
+ private static final long serialVersionUID = -6903439483039149324L;
28
30
  private java.nio.ByteBuffer byteBuffer;
29
31
 
30
32
  public static RaiseException newOverflowError(ThreadContext context, String message) {
@@ -13,6 +13,7 @@ import org.jruby.runtime.ThreadContext;
13
13
  import org.jruby.runtime.builtin.IRubyObject;
14
14
 
15
15
  public class Monitor extends RubyObject {
16
+ private static final long serialVersionUID = -3733782997115074794L;
16
17
  private SelectionKey key;
17
18
  private RubyIO io;
18
19
  private IRubyObject interests, selector, value, closed;
@@ -7,7 +7,6 @@ import java.io.IOException;
7
7
  import java.nio.channels.Channel;
8
8
  import java.nio.channels.SelectableChannel;
9
9
  import java.nio.channels.SelectionKey;
10
- import java.nio.channels.CancelledKeyException;
11
10
 
12
11
  import org.jruby.Ruby;
13
12
  import org.jruby.RubyArray;
@@ -19,10 +18,10 @@ import org.jruby.anno.JRubyMethod;
19
18
  import org.jruby.runtime.Block;
20
19
  import org.jruby.runtime.ThreadContext;
21
20
  import org.jruby.runtime.builtin.IRubyObject;
22
-
23
- import org.nio4r.Monitor;
21
+ import org.jruby.util.io.OpenFile;
24
22
 
25
23
  public class Selector extends RubyObject {
24
+ private static final long serialVersionUID = -14562818539414873L;
26
25
  private java.nio.channels.Selector selector;
27
26
  private HashMap<SelectableChannel,SelectionKey> cancelledKeys;
28
27
  private volatile boolean wakeupFired;
@@ -44,7 +43,7 @@ public class Selector extends RubyObject {
44
43
 
45
44
  @JRubyMethod
46
45
  public IRubyObject initialize(ThreadContext context, IRubyObject backend) {
47
- if(backend != context.runtime.newSymbol("java")) {
46
+ if(backend != context.runtime.newSymbol("java") && !backend.isNil()) {
48
47
  throw context.runtime.newArgumentError(":java is the only supported backend");
49
48
  }
50
49
 
@@ -136,7 +135,10 @@ public class Selector extends RubyObject {
136
135
  @JRubyMethod
137
136
  public IRubyObject deregister(ThreadContext context, IRubyObject io) {
138
137
  Ruby runtime = context.getRuntime();
139
- Channel rawChannel = RubyIO.convertToIO(context, io).getChannel();
138
+ OpenFile file = RubyIO.convertToIO(context, io).getOpenFileInitialized();
139
+ if (file.fd() == null)
140
+ return context.nil;
141
+ Channel rawChannel = file.channel();
140
142
 
141
143
  if(!(rawChannel instanceof SelectableChannel)) {
142
144
  throw runtime.newArgumentError("not a selectable IO object");
@@ -199,15 +201,15 @@ public class Selector extends RubyObject {
199
201
  return context.nil;
200
202
  }
201
203
 
202
- RubyArray array = null;
204
+ RubyArray<?> array = null;
203
205
 
204
206
  if(!block.isGiven()) {
205
207
  array = runtime.newArray(this.selector.selectedKeys().size());
206
208
  }
207
209
 
208
- Iterator selectedKeys = this.selector.selectedKeys().iterator();
210
+ Iterator<SelectionKey> selectedKeys = this.selector.selectedKeys().iterator();
209
211
  while(selectedKeys.hasNext()) {
210
- SelectionKey key = (SelectionKey)selectedKeys.next();
212
+ SelectionKey key = selectedKeys.next();
211
213
  processKey(key);
212
214
 
213
215
  selectedKeys.remove();
@@ -259,10 +261,10 @@ public class Selector extends RubyObject {
259
261
 
260
262
  /* Flush our internal buffer of cancelled keys */
261
263
  private void cancelKeys() {
262
- Iterator cancelledKeys = this.cancelledKeys.entrySet().iterator();
264
+ Iterator<Map.Entry<SelectableChannel, SelectionKey>> cancelledKeys = this.cancelledKeys.entrySet().iterator();
263
265
  while(cancelledKeys.hasNext()) {
264
- Map.Entry entry = (Map.Entry)cancelledKeys.next();
265
- SelectionKey key = (SelectionKey)entry.getValue();
266
+ Map.Entry<SelectableChannel, SelectionKey> entry = cancelledKeys.next();
267
+ SelectionKey key = entry.getValue();
266
268
  key.cancel();
267
269
  cancelledKeys.remove();
268
270
  }
data/ext/nio4r/selector.c CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  #include "nio4r.h"
7
7
  #ifdef HAVE_RUBYSIG_H
8
- # include "rubysig.h"
8
+ #include "rubysig.h"
9
9
  #endif
10
10
 
11
11
  #ifdef HAVE_UNISTD_H
@@ -14,11 +14,11 @@
14
14
  #include <io.h>
15
15
  #endif
16
16
 
17
- #include <fcntl.h>
18
17
  #include <assert.h>
18
+ #include <fcntl.h>
19
19
 
20
20
  static VALUE mNIO = Qnil;
21
- static VALUE cNIO_Monitor = Qnil;
21
+ static VALUE cNIO_Monitor = Qnil;
22
22
  static VALUE cNIO_Selector = Qnil;
23
23
 
24
24
  /* Allocator/deallocator */
@@ -80,7 +80,7 @@ void Init_NIO_Selector()
80
80
  rb_define_method(cNIO_Selector, "closed?", NIO_Selector_closed, 0);
81
81
  rb_define_method(cNIO_Selector, "empty?", NIO_Selector_is_empty, 0);
82
82
 
83
- cNIO_Monitor = rb_define_class_under(mNIO, "Monitor", rb_cObject);
83
+ cNIO_Monitor = rb_define_class_under(mNIO, "Monitor", rb_cObject);
84
84
  }
85
85
 
86
86
  /* Create the libev event loop and incoming event buffer */
@@ -95,13 +95,12 @@ static VALUE NIO_Selector_allocate(VALUE klass)
95
95
  safety. Pipes are nice and safe to use between threads.
96
96
 
97
97
  Note that Java NIO uses this same mechanism */
98
- if(pipe(fds) < 0) {
98
+ if (pipe(fds) < 0) {
99
99
  rb_sys_fail("pipe");
100
100
  }
101
101
 
102
102
  /* Use non-blocking reads/writes during wakeup, in case the buffer is full */
103
- if(fcntl(fds[0], F_SETFL, O_NONBLOCK) < 0 ||
104
- fcntl(fds[1], F_SETFL, O_NONBLOCK) < 0) {
103
+ if (fcntl(fds[0], F_SETFL, O_NONBLOCK) < 0 || fcntl(fds[1], F_SETFL, O_NONBLOCK) < 0) {
105
104
  rb_sys_fail("fcntl");
106
105
  }
107
106
 
@@ -127,7 +126,7 @@ static VALUE NIO_Selector_allocate(VALUE klass)
127
126
  /* NIO selectors store all Ruby objects in instance variables so mark is a stub */
128
127
  static void NIO_Selector_mark(struct NIO_Selector *selector)
129
128
  {
130
- if(selector->ready_array != Qnil) {
129
+ if (selector->ready_array != Qnil) {
131
130
  rb_gc_mark(selector->ready_array);
132
131
  }
133
132
  }
@@ -136,14 +135,14 @@ static void NIO_Selector_mark(struct NIO_Selector *selector)
136
135
  Called by both NIO::Selector#close and the finalizer below */
137
136
  static void NIO_Selector_shutdown(struct NIO_Selector *selector)
138
137
  {
139
- if(selector->closed) {
138
+ if (selector->closed) {
140
139
  return;
141
140
  }
142
141
 
143
142
  close(selector->wakeup_reader);
144
143
  close(selector->wakeup_writer);
145
144
 
146
- if(selector->ev_loop) {
145
+ if (selector->ev_loop) {
147
146
  ev_loop_destroy(selector->ev_loop);
148
147
  selector->ev_loop = 0;
149
148
  }
@@ -159,30 +158,39 @@ static void NIO_Selector_free(struct NIO_Selector *selector)
159
158
  }
160
159
 
161
160
  /* Return an array of symbols for supported backends */
162
- static VALUE NIO_Selector_supported_backends(VALUE klass) {
161
+ static VALUE NIO_Selector_supported_backends(VALUE klass)
162
+ {
163
163
  unsigned int backends = ev_supported_backends();
164
164
  VALUE result = rb_ary_new();
165
165
 
166
- if(backends & EVBACKEND_EPOLL) {
166
+ if (backends & EVBACKEND_EPOLL) {
167
167
  rb_ary_push(result, ID2SYM(rb_intern("epoll")));
168
168
  }
169
169
 
170
- if(backends & EVBACKEND_POLL) {
170
+ if (backends & EVBACKEND_POLL) {
171
171
  rb_ary_push(result, ID2SYM(rb_intern("poll")));
172
172
  }
173
173
 
174
- if(backends & EVBACKEND_KQUEUE) {
174
+ if (backends & EVBACKEND_KQUEUE) {
175
175
  rb_ary_push(result, ID2SYM(rb_intern("kqueue")));
176
176
  }
177
177
 
178
- if(backends & EVBACKEND_SELECT) {
178
+ if (backends & EVBACKEND_SELECT) {
179
179
  rb_ary_push(result, ID2SYM(rb_intern("select")));
180
180
  }
181
181
 
182
- if(backends & EVBACKEND_PORT) {
182
+ if (backends & EVBACKEND_PORT) {
183
183
  rb_ary_push(result, ID2SYM(rb_intern("port")));
184
184
  }
185
185
 
186
+ if (backends & EVBACKEND_LINUXAIO) {
187
+ rb_ary_push(result, ID2SYM(rb_intern("linuxaio")));
188
+ }
189
+
190
+ if (backends & EVBACKEND_IOURING) {
191
+ rb_ary_push(result, ID2SYM(rb_intern("io_uring")));
192
+ }
193
+
186
194
  return result;
187
195
  }
188
196
 
@@ -201,27 +209,29 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
201
209
 
202
210
  rb_scan_args(argc, argv, "01", &backend);
203
211
 
204
- if(backend != Qnil) {
205
- if(!rb_ary_includes(NIO_Selector_supported_backends(CLASS_OF(self)), backend)) {
206
- rb_raise(rb_eArgError, "unsupported backend: %s",
207
- RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
212
+ if (backend != Qnil) {
213
+ if (!rb_ary_includes(NIO_Selector_supported_backends(CLASS_OF(self)), backend)) {
214
+ rb_raise(rb_eArgError, "unsupported backend: %s", RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
208
215
  }
209
216
 
210
217
  backend_id = SYM2ID(backend);
211
218
 
212
- if(backend_id == rb_intern("epoll")) {
219
+ if (backend_id == rb_intern("epoll")) {
213
220
  flags = EVBACKEND_EPOLL;
214
- } else if(backend_id == rb_intern("poll")) {
221
+ } else if (backend_id == rb_intern("poll")) {
215
222
  flags = EVBACKEND_POLL;
216
- } else if(backend_id == rb_intern("kqueue")) {
223
+ } else if (backend_id == rb_intern("kqueue")) {
217
224
  flags = EVBACKEND_KQUEUE;
218
- } else if(backend_id == rb_intern("select")) {
225
+ } else if (backend_id == rb_intern("select")) {
219
226
  flags = EVBACKEND_SELECT;
220
- } else if(backend_id == rb_intern("port")) {
227
+ } else if (backend_id == rb_intern("port")) {
221
228
  flags = EVBACKEND_PORT;
229
+ } else if (backend_id == rb_intern("linuxaio")) {
230
+ flags = EVBACKEND_LINUXAIO;
231
+ } else if (backend_id == rb_intern("io_uring")) {
232
+ flags = EVBACKEND_IOURING;
222
233
  } else {
223
- rb_raise(rb_eArgError, "unsupported backend: %s",
224
- RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
234
+ rb_raise(rb_eArgError, "unsupported backend: %s", RSTRING_PTR(rb_funcall(backend, rb_intern("inspect"), 0)));
225
235
  }
226
236
  }
227
237
 
@@ -229,7 +239,7 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
229
239
  assert(!selector->ev_loop);
230
240
 
231
241
  selector->ev_loop = ev_loop_new(flags);
232
- if(!selector->ev_loop) {
242
+ if (!selector->ev_loop) {
233
243
  rb_raise(rb_eIOError, "error initializing event loop");
234
244
  }
235
245
 
@@ -245,11 +255,12 @@ static VALUE NIO_Selector_initialize(int argc, VALUE *argv, VALUE self)
245
255
  return Qnil;
246
256
  }
247
257
 
248
- static VALUE NIO_Selector_backend(VALUE self) {
258
+ static VALUE NIO_Selector_backend(VALUE self)
259
+ {
249
260
  struct NIO_Selector *selector;
250
261
 
251
262
  Data_Get_Struct(self, struct NIO_Selector, selector);
252
- if(selector->closed) {
263
+ if (selector->closed) {
253
264
  rb_raise(rb_eIOError, "selector is closed");
254
265
  }
255
266
 
@@ -264,6 +275,10 @@ static VALUE NIO_Selector_backend(VALUE self) {
264
275
  return ID2SYM(rb_intern("select"));
265
276
  case EVBACKEND_PORT:
266
277
  return ID2SYM(rb_intern("port"));
278
+ case EVBACKEND_LINUXAIO:
279
+ return ID2SYM(rb_intern("linuxaio"));
280
+ case EVBACKEND_IOURING:
281
+ return ID2SYM(rb_intern("io_uring"));
267
282
  }
268
283
 
269
284
  return ID2SYM(rb_intern("unknown"));
@@ -277,7 +292,7 @@ static VALUE NIO_Selector_synchronize(VALUE self, VALUE (*func)(VALUE *args), VA
277
292
  current_thread = rb_thread_current();
278
293
  lock_holder = rb_ivar_get(self, rb_intern("lock_holder"));
279
294
 
280
- if(lock_holder != current_thread) {
295
+ if (lock_holder != current_thread) {
281
296
  lock = rb_ivar_get(self, rb_intern("lock"));
282
297
  rb_funcall(lock, rb_intern("lock"), 0);
283
298
  rb_ivar_set(self, rb_intern("lock_holder"), current_thread);
@@ -306,7 +321,7 @@ static VALUE NIO_Selector_unlock(VALUE self)
306
321
  /* Register an IO object with the selector for the given interests */
307
322
  static VALUE NIO_Selector_register(VALUE self, VALUE io, VALUE interests)
308
323
  {
309
- VALUE args[3] = {self, io, interests};
324
+ VALUE args[3] = { self, io, interests };
310
325
  return NIO_Selector_synchronize(self, NIO_Selector_register_synchronized, args);
311
326
  }
312
327
 
@@ -322,14 +337,14 @@ static VALUE NIO_Selector_register_synchronized(VALUE *args)
322
337
  interests = args[2];
323
338
 
324
339
  Data_Get_Struct(self, struct NIO_Selector, selector);
325
- if(selector->closed) {
340
+ if (selector->closed) {
326
341
  rb_raise(rb_eIOError, "selector is closed");
327
342
  }
328
343
 
329
344
  selectables = rb_ivar_get(self, rb_intern("selectables"));
330
345
  monitor = rb_hash_lookup(selectables, io);
331
346
 
332
- if(monitor != Qnil)
347
+ if (monitor != Qnil)
333
348
  rb_raise(rb_eArgError, "this IO is already registered with selector");
334
349
 
335
350
  /* Create a new NIO::Monitor */
@@ -346,7 +361,7 @@ static VALUE NIO_Selector_register_synchronized(VALUE *args)
346
361
  /* Deregister an IO object from the selector */
347
362
  static VALUE NIO_Selector_deregister(VALUE self, VALUE io)
348
363
  {
349
- VALUE args[2] = {self, io};
364
+ VALUE args[2] = { self, io };
350
365
  return NIO_Selector_synchronize(self, NIO_Selector_deregister_synchronized, args);
351
366
  }
352
367
 
@@ -361,7 +376,7 @@ static VALUE NIO_Selector_deregister_synchronized(VALUE *args)
361
376
  selectables = rb_ivar_get(self, rb_intern("selectables"));
362
377
  monitor = rb_hash_delete(selectables, io);
363
378
 
364
- if(monitor != Qnil) {
379
+ if (monitor != Qnil) {
365
380
  rb_funcall(monitor, rb_intern("close"), 1, Qfalse);
366
381
  }
367
382
 
@@ -385,7 +400,7 @@ static VALUE NIO_Selector_select(int argc, VALUE *argv, VALUE self)
385
400
 
386
401
  rb_scan_args(argc, argv, "01", &timeout);
387
402
 
388
- if(timeout != Qnil && NUM2DBL(timeout) < 0) {
403
+ if (timeout != Qnil && NUM2DBL(timeout) < 0) {
389
404
  rb_raise(rb_eArgError, "time interval must be positive");
390
405
  }
391
406
 
@@ -404,26 +419,26 @@ static VALUE NIO_Selector_select_synchronized(VALUE *args)
404
419
 
405
420
  Data_Get_Struct(args[0], struct NIO_Selector, selector);
406
421
 
407
- if(selector->closed) {
422
+ if (selector->closed) {
408
423
  rb_raise(rb_eIOError, "selector is closed");
409
424
  }
410
425
 
411
- if(!rb_block_given_p()) {
426
+ if (!rb_block_given_p()) {
412
427
  selector->ready_array = rb_ary_new();
413
428
  }
414
429
 
415
430
  ready = NIO_Selector_run(selector, args[1]);
416
431
 
417
432
  /* Timeout */
418
- if(ready < 0) {
419
- if(!rb_block_given_p()) {
433
+ if (ready < 0) {
434
+ if (!rb_block_given_p()) {
420
435
  selector->ready_array = Qnil;
421
436
  }
422
437
 
423
438
  return Qnil;
424
439
  }
425
440
 
426
- if(rb_block_given_p()) {
441
+ if (rb_block_given_p()) {
427
442
  return INT2NUM(ready);
428
443
  } else {
429
444
  ready_array = selector->ready_array;
@@ -441,12 +456,12 @@ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
441
456
  selector->selecting = 1;
442
457
  selector->wakeup_fired = 0;
443
458
 
444
- if(timeout == Qnil) {
459
+ if (timeout == Qnil) {
445
460
  /* Don't fire a wakeup timeout if we weren't passed one */
446
461
  ev_timer_stop(selector->ev_loop, &selector->timer);
447
462
  } else {
448
463
  timeout_val = NUM2DBL(timeout);
449
- if(timeout_val == 0) {
464
+ if (timeout_val == 0) {
450
465
  /* If we've been given an explicit timeout of 0, perform a non-blocking
451
466
  select operation */
452
467
  ev_run_flags = EVRUN_NOWAIT;
@@ -462,7 +477,7 @@ static int NIO_Selector_run(struct NIO_Selector *selector, VALUE timeout)
462
477
  result = selector->ready_count;
463
478
  selector->selecting = selector->ready_count = 0;
464
479
 
465
- if(result > 0 || selector->wakeup_fired) {
480
+ if (result > 0 || selector->wakeup_fired) {
466
481
  selector->wakeup_fired = 0;
467
482
  return result;
468
483
  } else {
@@ -476,7 +491,7 @@ static VALUE NIO_Selector_wakeup(VALUE self)
476
491
  struct NIO_Selector *selector;
477
492
  Data_Get_Struct(self, struct NIO_Selector, selector);
478
493
 
479
- if(selector->closed) {
494
+ if (selector->closed) {
480
495
  rb_raise(rb_eIOError, "selector is closed");
481
496
  }
482
497
 
@@ -489,7 +504,7 @@ static VALUE NIO_Selector_wakeup(VALUE self)
489
504
  /* Close the selector and free system resources */
490
505
  static VALUE NIO_Selector_close(VALUE self)
491
506
  {
492
- VALUE args[1] = {self};
507
+ VALUE args[1] = { self };
493
508
  return NIO_Selector_synchronize(self, NIO_Selector_close_synchronized, args);
494
509
  }
495
510
 
@@ -507,7 +522,7 @@ static VALUE NIO_Selector_close_synchronized(VALUE *args)
507
522
  /* Is the selector closed? */
508
523
  static VALUE NIO_Selector_closed(VALUE self)
509
524
  {
510
- VALUE args[1] = {self};
525
+ VALUE args[1] = { self };
511
526
  return NIO_Selector_synchronize(self, NIO_Selector_closed_synchronized, args);
512
527
  }
513
528
 
@@ -528,7 +543,6 @@ static VALUE NIO_Selector_is_empty(VALUE self)
528
543
  return rb_funcall(selectables, rb_intern("empty?"), 0) == Qtrue ? Qtrue : Qfalse;
529
544
  }
530
545
 
531
-
532
546
  /* Called whenever a timeout fires on the event loop */
533
547
  static void NIO_Selector_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents)
534
548
  {
@@ -542,7 +556,8 @@ static void NIO_Selector_wakeup_callback(struct ev_loop *ev_loop, struct ev_io *
542
556
  selector->selecting = 0;
543
557
 
544
558
  /* Drain the wakeup pipe, giving us level-triggered behavior */
545
- while(read(selector->wakeup_reader, buffer, 128) > 0);
559
+ while (read(selector->wakeup_reader, buffer, 128) > 0)
560
+ ;
546
561
  }
547
562
 
548
563
  /* libev callback fired whenever a monitor gets an event */
@@ -558,7 +573,7 @@ void NIO_Selector_monitor_callback(struct ev_loop *ev_loop, struct ev_io *io, in
558
573
  selector->ready_count++;
559
574
  monitor_data->revents = revents;
560
575
 
561
- if(rb_block_given_p()) {
576
+ if (rb_block_given_p()) {
562
577
  rb_yield(monitor);
563
578
  } else {
564
579
  assert(selector->ready_array != Qnil);