polyphony 0.45.0 → 0.45.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/CHANGELOG.md +10 -0
  4. data/Gemfile.lock +9 -1
  5. data/TODO.md +6 -7
  6. data/examples/adapters/redis_client.rb +3 -1
  7. data/examples/adapters/redis_pubsub_perf.rb +11 -8
  8. data/examples/adapters/sequel_mysql.rb +1 -1
  9. data/examples/adapters/sequel_pg.rb +24 -0
  10. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  11. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  12. data/examples/core/deferring-an-operation.rb +16 -0
  13. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  14. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  15. data/examples/core/handling-signals.rb +11 -0
  16. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  17. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  18. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  19. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  20. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  21. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  22. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  23. data/examples/core/supervisor.rb +20 -0
  24. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  25. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  26. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  27. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  28. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  29. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  30. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  31. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  32. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  33. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  34. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  35. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  36. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  37. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  38. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  39. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  40. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  41. data/examples/io/{xx-open.rb → open.rb} +0 -0
  42. data/examples/io/{xx-pry.rb → pry.rb} +0 -0
  43. data/examples/io/{xx-rack_server.rb → rack_server.rb} +0 -0
  44. data/examples/io/{xx-system.rb → system.rb} +1 -1
  45. data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
  46. data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
  47. data/examples/io/tunnel.rb +6 -1
  48. data/examples/io/{xx-zip.rb → zip.rb} +0 -0
  49. data/examples/performance/fiber_transfer.rb +2 -1
  50. data/examples/performance/fs_read.rb +5 -6
  51. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  52. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  53. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  54. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  55. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
  56. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
  57. data/examples/performance/thread_pool_perf.rb +6 -7
  58. data/ext/polyphony/backend.h +0 -1
  59. data/ext/polyphony/libev_backend.c +69 -68
  60. data/ext/polyphony/polyphony.c +0 -2
  61. data/ext/polyphony/polyphony.h +0 -13
  62. data/ext/polyphony/polyphony_ext.c +1 -2
  63. data/ext/polyphony/queue.c +3 -4
  64. data/ext/polyphony/ring_buffer.c +0 -1
  65. data/ext/polyphony/thread.c +3 -4
  66. data/lib/polyphony/adapters/fs.rb +1 -1
  67. data/lib/polyphony/adapters/redis.rb +1 -1
  68. data/lib/polyphony/core/global_api.rb +4 -4
  69. data/lib/polyphony/core/sync.rb +11 -9
  70. data/lib/polyphony/extensions/core.rb +1 -6
  71. data/lib/polyphony/extensions/io.rb +40 -6
  72. data/lib/polyphony/extensions/socket.rb +11 -2
  73. data/lib/polyphony/version.rb +1 -1
  74. data/polyphony.gemspec +2 -1
  75. data/test/test_io.rb +16 -0
  76. data/test/test_socket.rb +17 -0
  77. data/test/test_throttler.rb +1 -0
  78. metadata +58 -72
  79. data/examples/adapters/concurrent-ruby.rb +0 -9
  80. data/examples/core/04-handling-signals.rb +0 -19
  81. data/examples/core/xx-at_exit.rb +0 -29
  82. data/examples/core/xx-backend.rb +0 -102
  83. data/examples/core/xx-caller.rb +0 -12
  84. data/examples/core/xx-daemon.rb +0 -14
  85. data/examples/core/xx-deadlock.rb +0 -8
  86. data/examples/core/xx-deferring-an-operation.rb +0 -14
  87. data/examples/core/xx-exception-backtrace.rb +0 -40
  88. data/examples/core/xx-fork-cleanup.rb +0 -22
  89. data/examples/core/xx-fork-spin.rb +0 -42
  90. data/examples/core/xx-fork-terminate.rb +0 -27
  91. data/examples/core/xx-move_on.rb +0 -23
  92. data/examples/core/xx-queue-async.rb +0 -120
  93. data/examples/core/xx-readpartial.rb +0 -18
  94. data/examples/core/xx-signals.rb +0 -16
  95. data/examples/core/xx-sleep-forever.rb +0 -9
  96. data/examples/core/xx-sleeping.rb +0 -25
  97. data/examples/core/xx-snooze-starve.rb +0 -16
  98. data/examples/core/xx-spin-fork.rb +0 -49
  99. data/examples/core/xx-state-machine.rb +0 -51
  100. data/examples/core/xx-stop.rb +0 -20
  101. data/examples/core/xx-supervisors.rb +0 -21
  102. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  103. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  104. data/examples/core/xx-thread-snooze.rb +0 -34
  105. data/examples/core/xx-timer-gc.rb +0 -17
  106. data/examples/core/xx-trace.rb +0 -79
  107. data/examples/performance/xx-array.rb +0 -11
  108. data/examples/performance/xx-fiber-switch.rb +0 -9
  109. data/examples/performance/xx-snooze.rb +0 -15
  110. data/examples/xx-spin.rb +0 -32
@@ -15,7 +15,7 @@ end
15
15
 
16
16
  reader = spin do
17
17
  puts 'received from echo server:'
18
- while (data = socket.readpartial(8192))
18
+ socket.read_loop do |data|
19
19
  STDOUT << data
20
20
  end
21
21
  end
@@ -11,8 +11,8 @@ writer = spin do
11
11
  end
12
12
  end
13
13
 
14
- spin do
15
- while (data = socket.readpartial(8192))
14
+ reader = spin do
15
+ socket.read_loop do |data|
16
16
  STDOUT << 'received: ' + data
17
17
  end
18
18
  writer.interrupt
@@ -11,6 +11,6 @@ spin do
11
11
  o.close
12
12
  end
13
13
 
14
- while (data = i.readpartial(8192))
14
+ i.read_loop do |data|
15
15
  STDOUT << "You said: #{data}"
16
16
  end
@@ -17,7 +17,7 @@ begin
17
17
  scope.when_cancelled do
18
18
  client.write "Disconnecting due to inactivity\n"
19
19
  end
20
- while (data = client.readpartial(8192))
20
+ client.read_loop do |data|
21
21
  scope.reset_timeout
22
22
  client.write "You said: #{data}"
23
23
  end
@@ -16,23 +16,14 @@ end
16
16
  zones = %w{
17
17
  Europe/London Europe/Paris Europe/Bucharest America/New_York Asia/Bangkok
18
18
  }
19
- # zones.each do |tzone|
20
- # spin do
21
- # time = get_time(tzone)
22
- # puts "Time in #{tzone}: #{time}"
23
- # end
24
- # end
25
-
26
- # suspend
27
19
 
28
20
  def get_times(zones)
29
- Polyphony::Supervisor.new do |s|
30
- zones.each do |tzone|
31
- s.spin { [tzone, get_time(tzone)] }
32
- end
21
+ fibers = zones.map do |tzone|
22
+ spin { [tzone, get_time(tzone)] }
33
23
  end
24
+ Fiber.await(*fibers)
34
25
  end
35
26
 
36
- get_times(zones).await.each do |tzone, time|
27
+ get_times(zones).each do |tzone, time|
37
28
  puts "Time in #{tzone}: #{time}"
38
29
  end
File without changes
File without changes
File without changes
@@ -7,5 +7,5 @@ timer = spin do
7
7
  throttled_loop(5) { STDOUT << '.' }
8
8
  end
9
9
 
10
- puts system('ruby -e "sleep 1; puts :done; STDOUT.close"')
10
+ puts system('ruby -e "puts :sleeping; STDOUT.flush; sleep 1; puts :done"')
11
11
  timer.stop
@@ -3,6 +3,11 @@
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
5
 
6
+ if ARGV.size < 2
7
+ puts "Usage: ruby examples/tunnel.rb <port1> <port2>"
8
+ exit
9
+ end
10
+
6
11
  Ports = ARGV[0..1]
7
12
  EndPoints = []
8
13
 
@@ -24,7 +29,7 @@ def endpoint_loop(idx, peer_idx)
24
29
  conn.binmode
25
30
  EndPoints[idx] = conn
26
31
  log "Client connected on port #{port} (#{conn.remote_address.inspect})"
27
- while data = conn.readpartial(8192)
32
+ conn.read_loop do |data|
28
33
  peer = EndPoints[peer_idx]
29
34
  if peer
30
35
  peer << data
File without changes
@@ -6,7 +6,8 @@ class Fiber
6
6
  attr_accessor :next
7
7
  end
8
8
 
9
- # This program shows how the performance
9
+ # This program shows how the performance of Fiber.transfer degrades as the fiber
10
+ # count increases
10
11
 
11
12
  def run(num_fibers)
12
13
  count = 0
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
- require 'polyphony/fs'
5
+ require 'polyphony/adapters/fs'
6
6
 
7
7
  def raw_read_file(x)
8
8
  t0 = Time.now
@@ -14,7 +14,7 @@ def threaded_read_file(x, y)
14
14
  t0 = Time.now
15
15
  threads = []
16
16
  y.times do
17
- threads << Thread.new { x.times { IO.orig_read(PATH) } }
17
+ threads << Thread.new { x.times { IO.orig_read(__FILE__) } }
18
18
  end
19
19
  threads.each(&:join)
20
20
  puts "threaded_read_file: #{Time.now - t0}"
@@ -22,11 +22,10 @@ end
22
22
 
23
23
  def thread_pool_read_file(x, y)
24
24
  t0 = Time.now
25
- supervise do |s|
26
- y.times do
27
- s.spin { x.times { IO.read(PATH) } }
28
- end
25
+ y.times do
26
+ spin { x.times { IO.read(__FILE__) } }
29
27
  end
28
+ Fiber.current.await_all_children
30
29
  puts "thread_pool_read_file: #{Time.now - t0}"
31
30
  end
32
31
 
@@ -12,4 +12,5 @@ end
12
12
  t0 = Time.now
13
13
  X.times { f.transfer }
14
14
  dt = Time.now - t0
15
- puts "#{X / dt.to_f}/s"
15
+ puts "#{X / dt.to_f}/s"
16
+ puts fs.size
@@ -21,11 +21,10 @@ end
21
21
  t0 = Time.now
22
22
  results = []
23
23
  move_on_after(3) do
24
- supervise do |s|
25
- 10.times do
26
- s.spin { get_time(results) }
27
- end
24
+ 10.times do
25
+ spin { get_time(results) }
28
26
  end
27
+ supervise
29
28
  puts 'done'
30
29
  end
31
30
 
@@ -24,7 +24,7 @@ def handle_client(socket)
24
24
  parser.on_message_complete = proc do |env|
25
25
  reqs << Object.new # parser
26
26
  end
27
- while (data = socket.readpartial(8192)) do
27
+ socket.read_loop do |data|
28
28
  parser << data
29
29
  while (req = reqs.shift)
30
30
  handle_request(socket, req)
@@ -13,7 +13,7 @@ def handle_client(socket)
13
13
  parser.on_message_complete = proc do |env|
14
14
  reqs << Object.new # parser
15
15
  end
16
- while (data = socket.readpartial(8192)) do
16
+ socket.read_loop |data|
17
17
  parser << data
18
18
  while (req = reqs.shift)
19
19
  handle_request(socket, req)
@@ -11,11 +11,7 @@ def handle_client(client)
11
11
  headers = "Content-Length: #{data.bytesize}\r\n"
12
12
  client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
13
13
  end
14
- loop do
15
- while data = client.readpartial(8192) rescue nil
16
- parser << data
17
- end
18
- end
14
+ client.read_loop { |data| parser << data }
19
15
  client.close
20
16
  end
21
17
  end
@@ -10,7 +10,7 @@ def lengthy_op
10
10
  # Digest::SHA256.digest(IO.read('doc/Promise.html'))
11
11
  end
12
12
 
13
- X = 100
13
+ X = 10000
14
14
 
15
15
  def compare_performance
16
16
  t0 = Time.now
@@ -35,20 +35,19 @@ def compare_performance
35
35
 
36
36
  acc = 0
37
37
  count = 0
38
- 10.times do |_i|
38
+ 1.times do |_i|
39
39
  t0 = Time.now
40
- supervise do |s|
41
- X.times do
42
- s.spin { Polyphony::ThreadPool.process { lengthy_op } }
43
- end
40
+ X.times do
41
+ spin { Polyphony::ThreadPool.process { lengthy_op } }
44
42
  end
43
+ Fiber.current.await_all_children
45
44
  thread_pool_perf = X / (Time.now - t0)
46
45
  acc += thread_pool_perf
47
46
  count += 1
48
47
  end
49
48
  avg_perf = acc / count
50
49
  puts format(
51
- 'avg thread pool performance: %g (X %0.2f)',
50
+ 'spin X thread pool performance: %g (X %0.2f)',
52
51
  avg_perf,
53
52
  avg_perf / native_perf
54
53
  )
@@ -7,7 +7,6 @@
7
7
 
8
8
  // VALUE LibevBackend_accept(VALUE self, VALUE sock);
9
9
  // VALUE LibevBackend_accept_loop(VALUE self, VALUE sock);
10
- // VALUE libev_backend_await(VALUE self);
11
10
  // VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port);
12
11
  // VALUE LibevBackend_finalize(VALUE self);
13
12
  // VALUE LibevBackend_post_fork(VALUE self);
@@ -31,7 +31,7 @@ static const rb_data_type_t LibevBackend_type = {
31
31
 
32
32
  static VALUE LibevBackend_allocate(VALUE klass) {
33
33
  LibevBackend_t *backend = ALLOC(LibevBackend_t);
34
-
34
+
35
35
  return TypedData_Wrap_Struct(klass, &LibevBackend_type, backend);
36
36
  }
37
37
 
@@ -93,7 +93,7 @@ VALUE LibevBackend_ref(VALUE self) {
93
93
  GetLibevBackend(self, backend);
94
94
 
95
95
  backend->ref_count++;
96
- return self;
96
+ return self;
97
97
  }
98
98
 
99
99
  VALUE LibevBackend_unref(VALUE self) {
@@ -101,7 +101,7 @@ VALUE LibevBackend_unref(VALUE self) {
101
101
  GetLibevBackend(self, backend);
102
102
 
103
103
  backend->ref_count--;
104
- return self;
104
+ return self;
105
105
  }
106
106
 
107
107
  int LibevBackend_ref_count(VALUE self) {
@@ -139,7 +139,7 @@ VALUE LibevBackend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE que
139
139
  }
140
140
 
141
141
  backend->run_no_wait_count = 0;
142
-
142
+
143
143
  COND_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
144
144
  backend->running = 1;
145
145
  ev_run(backend->ev_loop, is_nowait ? EVRUN_NOWAIT : EVRUN_ONCE);
@@ -253,25 +253,32 @@ inline VALUE libev_await(LibevBackend_t *backend) {
253
253
  return ret;
254
254
  }
255
255
 
256
- VALUE libev_backend_await(VALUE self) {
257
- LibevBackend_t *backend;
258
- GetLibevBackend(self, backend);
259
- return libev_await(backend);
260
- }
261
-
262
- VALUE libev_io_wait(LibevBackend_t *backend, struct libev_io *watcher, rb_io_t *fptr, int flags) {
256
+ VALUE libev_wait_fd_with_watcher(LibevBackend_t *backend, int fd, struct libev_io *watcher, int events) {
263
257
  VALUE switchpoint_result;
264
258
 
265
259
  if (watcher->fiber == Qnil) {
266
260
  watcher->fiber = rb_fiber_current();
267
- ev_io_init(&watcher->io, LibevBackend_io_callback, fptr->fd, flags);
261
+ ev_io_init(&watcher->io, LibevBackend_io_callback, fd, events);
268
262
  }
269
263
  ev_io_start(backend->ev_loop, &watcher->io);
264
+
270
265
  switchpoint_result = libev_await(backend);
266
+
271
267
  ev_io_stop(backend->ev_loop, &watcher->io);
268
+ RB_GC_GUARD(switchpoint_result);
269
+ return switchpoint_result;
270
+ }
271
+
272
+ VALUE libev_wait_fd(LibevBackend_t *backend, int fd, int events, int raise_exception) {
273
+ struct libev_io watcher;
274
+ VALUE switchpoint_result = Qnil;
275
+ watcher.fiber = Qnil;
276
+
277
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fd, &watcher, events);
272
278
 
279
+ if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
273
280
  RB_GC_GUARD(switchpoint_result);
274
- return switchpoint_result;
281
+ return switchpoint_result;
275
282
  }
276
283
 
277
284
  VALUE libev_snooze() {
@@ -288,20 +295,19 @@ ID ID_ivar_is_nonblocking;
288
295
  // benchmarks (with a "hello world" HTTP server) show throughput is improved
289
296
  // by 10-13%.
290
297
  inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
298
+ VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
299
+ if (is_nonblocking == Qtrue) return;
300
+
301
+ rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
302
+
291
303
  #ifdef _WIN32
292
- return rb_w32_set_nonblock(fptr->fd);
304
+ rb_w32_set_nonblock(fptr->fd);
293
305
  #elif defined(F_GETFL)
294
- VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
295
- if (is_nonblocking == Qnil) {
296
- rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
297
- int oflags = fcntl(fptr->fd, F_GETFL);
298
- if (oflags == -1) return;
299
- if (oflags & O_NONBLOCK) return;
300
- oflags |= O_NONBLOCK;
301
- fcntl(fptr->fd, F_SETFL, oflags);
302
- }
306
+ int oflags = fcntl(fptr->fd, F_GETFL);
307
+ if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
308
+ oflags |= O_NONBLOCK;
309
+ fcntl(fptr->fd, F_SETFL, oflags);
303
310
  #endif
304
- return;
305
311
  }
306
312
 
307
313
  VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
@@ -323,7 +329,7 @@ VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_
323
329
  rb_io_check_byte_readable(fptr);
324
330
  io_set_nonblock(fptr, io);
325
331
  watcher.fiber = Qnil;
326
-
332
+
327
333
  OBJ_TAINT(str);
328
334
 
329
335
  // Apparently after reopening a closed file, the file position is not reset,
@@ -340,12 +346,14 @@ VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_
340
346
  if (n < 0) {
341
347
  int e = errno;
342
348
  if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
343
-
344
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
349
+
350
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
351
+
345
352
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
346
353
  }
347
354
  else {
348
355
  switchpoint_result = libev_snooze();
356
+
349
357
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
350
358
 
351
359
  if (n == 0) break; // EOF
@@ -354,7 +362,7 @@ VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_
354
362
 
355
363
  if (total == len) {
356
364
  if (!dynamic_len) break;
357
-
365
+
358
366
  rb_str_resize(str, total);
359
367
  rb_str_modify_expand(str, len);
360
368
  buf = RSTRING_PTR(str) + total;
@@ -364,11 +372,12 @@ VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_
364
372
  else buf += n;
365
373
  }
366
374
  }
367
- if (total == 0) return Qnil;
368
375
 
369
376
  io_set_read_length(str, total, shrinkable);
370
377
  io_enc_str(str, fptr);
371
-
378
+
379
+ if (total == 0) return Qnil;
380
+
372
381
  RB_GC_GUARD(watcher.fiber);
373
382
  RB_GC_GUARD(switchpoint_result);
374
383
 
@@ -429,22 +438,17 @@ VALUE LibevBackend_read_loop(VALUE self, VALUE io) {
429
438
  int e = errno;
430
439
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
431
440
 
432
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
441
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
433
442
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
434
443
  }
435
444
  else {
436
445
  switchpoint_result = libev_snooze();
437
- if (TEST_EXCEPTION(switchpoint_result)) goto error;
438
446
 
439
- if (n == 0) break; // EOF
447
+ if (TEST_EXCEPTION(switchpoint_result)) goto error;
440
448
 
449
+ if (n == 0) break; // EOF
441
450
  total = n;
442
451
  YIELD_STR();
443
- Fiber_make_runnable(rb_fiber_current(), Qnil);
444
- switchpoint_result = Thread_switch_fiber(rb_thread_current());
445
- if (TEST_EXCEPTION(switchpoint_result)) {
446
- goto error;
447
- }
448
452
  }
449
453
  }
450
454
 
@@ -479,7 +483,9 @@ VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
479
483
  if (n < 0) {
480
484
  int e = errno;
481
485
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
482
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_WRITE);
486
+
487
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
488
+
483
489
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
484
490
  }
485
491
  else {
@@ -490,6 +496,7 @@ VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
490
496
 
491
497
  if (watcher.fiber == Qnil) {
492
498
  switchpoint_result = libev_snooze();
499
+
493
500
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
494
501
  }
495
502
 
@@ -535,7 +542,8 @@ VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
535
542
  int e = errno;
536
543
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
537
544
 
538
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_WRITE);
545
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
546
+
539
547
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
540
548
  }
541
549
  else {
@@ -558,6 +566,7 @@ VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
558
566
  }
559
567
  if (watcher.fiber == Qnil) {
560
568
  switchpoint_result = libev_snooze();
569
+
561
570
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
562
571
  }
563
572
 
@@ -575,10 +584,10 @@ VALUE LibevBackend_write_m(int argc, VALUE *argv, VALUE self) {
575
584
  if (argc < 2)
576
585
  // TODO: raise ArgumentError
577
586
  rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
578
-
587
+
579
588
  return (argc == 2) ?
580
589
  LibevBackend_write(self, argv[0], argv[1]) :
581
- LibevBackend_writev(self, argv[0], argc - 1, argv + 1);
590
+ LibevBackend_writev(self, argv[0], argc - 1, argv + 1);
582
591
  }
583
592
 
584
593
  ///////////////////////////////////////////////////////////////////////////
@@ -604,13 +613,15 @@ VALUE LibevBackend_accept(VALUE self, VALUE sock) {
604
613
  int e = errno;
605
614
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
606
615
 
607
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
616
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
617
+
608
618
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
609
619
  }
610
620
  else {
611
621
  VALUE socket;
612
622
  rb_io_t *fp;
613
623
  switchpoint_result = libev_snooze();
624
+
614
625
  if (TEST_EXCEPTION(switchpoint_result)) {
615
626
  close(fd); // close fd since we're raising an exception
616
627
  goto error;
@@ -624,7 +635,7 @@ VALUE LibevBackend_accept(VALUE self, VALUE sock) {
624
635
  rb_io_ascii8bit_binmode(socket);
625
636
  io_set_nonblock(fp, socket);
626
637
  rb_io_synchronized(fp);
627
-
638
+
628
639
  // if (rsock_do_not_reverse_lookup) {
629
640
  // fp->mode |= FMODE_NOREVLOOKUP;
630
641
  // }
@@ -660,17 +671,19 @@ VALUE LibevBackend_accept_loop(VALUE self, VALUE sock) {
660
671
  int e = errno;
661
672
  if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
662
673
 
663
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_READ);
674
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
675
+
664
676
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
665
677
  }
666
678
  else {
667
679
  rb_io_t *fp;
668
680
  switchpoint_result = libev_snooze();
681
+
669
682
  if (TEST_EXCEPTION(switchpoint_result)) {
670
683
  close(fd); // close fd since we're raising an exception
671
684
  goto error;
672
685
  }
673
-
686
+
674
687
  socket = rb_obj_alloc(cTCPSocket);
675
688
  MakeOpenFile(socket, fp);
676
689
  rb_update_max_fd(fd);
@@ -708,7 +721,7 @@ VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
708
721
  io_set_nonblock(fptr, sock);
709
722
  watcher.fiber = Qnil;
710
723
 
711
- addr.sin_family = AF_INET;
724
+ addr.sin_family = AF_INET;
712
725
  addr.sin_addr.s_addr = inet_addr(host_buf);
713
726
  addr.sin_port = htons(NUM2INT(port));
714
727
 
@@ -716,11 +729,14 @@ VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
716
729
  if (result < 0) {
717
730
  int e = errno;
718
731
  if (e != EINPROGRESS) rb_syserr_fail(e, strerror(e));
719
- switchpoint_result = libev_io_wait(backend, &watcher, fptr, EV_WRITE);
732
+
733
+ switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
734
+
720
735
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
721
736
  }
722
737
  else {
723
738
  switchpoint_result = libev_snooze();
739
+
724
740
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
725
741
  }
726
742
  RB_GC_GUARD(switchpoint_result);
@@ -729,21 +745,6 @@ error:
729
745
  return RAISE_EXCEPTION(switchpoint_result);
730
746
  }
731
747
 
732
- VALUE libev_wait_fd(LibevBackend_t *backend, int fd, int events, int raise_exception) {
733
- struct libev_io watcher;
734
- VALUE switchpoint_result = Qnil;
735
-
736
- watcher.fiber = rb_fiber_current();
737
- ev_io_init(&watcher.io, LibevBackend_io_callback, fd, events);
738
- ev_io_start(backend->ev_loop, &watcher.io);
739
- switchpoint_result = libev_await(backend);
740
- ev_io_stop(backend->ev_loop, &watcher.io);
741
-
742
- if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
743
- RB_GC_GUARD(switchpoint_result);
744
- return switchpoint_result;
745
- }
746
-
747
748
  VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write) {
748
749
  LibevBackend_t *backend;
749
750
  rb_io_t *fptr;
@@ -752,7 +753,7 @@ VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write) {
752
753
  if (underlying_io != Qnil) io = underlying_io;
753
754
  GetLibevBackend(self, backend);
754
755
  GetOpenFile(io, fptr);
755
-
756
+
756
757
  return libev_wait_fd(backend, fptr->fd, events, 1);
757
758
  }
758
759
 
@@ -780,7 +781,6 @@ VALUE LibevBackend_sleep(VALUE self, VALUE duration) {
780
781
  switchpoint_result = libev_await(backend);
781
782
 
782
783
  ev_timer_stop(backend->ev_loop, &watcher.timer);
783
-
784
784
  TEST_RESUME_EXCEPTION(switchpoint_result);
785
785
  RB_GC_GUARD(watcher.fiber);
786
786
  RB_GC_GUARD(switchpoint_result);
@@ -811,10 +811,10 @@ VALUE LibevBackend_waitpid(VALUE self, VALUE pid) {
811
811
  watcher.fiber = rb_fiber_current();
812
812
  ev_child_init(&watcher.child, LibevBackend_child_callback, NUM2INT(pid), 0);
813
813
  ev_child_start(backend->ev_loop, &watcher.child);
814
-
814
+
815
815
  switchpoint_result = libev_await(backend);
816
- ev_child_stop(backend->ev_loop, &watcher.child);
817
816
 
817
+ ev_child_stop(backend->ev_loop, &watcher.child);
818
818
  TEST_RESUME_EXCEPTION(switchpoint_result);
819
819
  RB_GC_GUARD(watcher.fiber);
820
820
  RB_GC_GUARD(switchpoint_result);
@@ -838,9 +838,10 @@ VALUE LibevBackend_wait_event(VALUE self, VALUE raise) {
838
838
 
839
839
  ev_async_init(&async, LibevBackend_async_callback);
840
840
  ev_async_start(backend->ev_loop, &async);
841
+
841
842
  switchpoint_result = libev_await(backend);
842
- ev_async_stop(backend->ev_loop, &async);
843
843
 
844
+ ev_async_stop(backend->ev_loop, &async);
844
845
  if (RTEST(raise)) TEST_RESUME_EXCEPTION(switchpoint_result);
845
846
  RB_GC_GUARD(switchpoint_result);
846
847
  return switchpoint_result;