polyphony 0.47.4 → 0.49.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +321 -296
  3. data/Gemfile.lock +1 -1
  4. data/LICENSE +1 -1
  5. data/TODO.md +38 -29
  6. data/examples/core/supervisor.rb +3 -3
  7. data/examples/core/worker-thread.rb +3 -4
  8. data/examples/io/tcp_proxy.rb +32 -0
  9. data/examples/performance/line_splitting.rb +34 -0
  10. data/examples/performance/loop.rb +32 -0
  11. data/examples/performance/thread-vs-fiber/polyphony_server.rb +6 -0
  12. data/ext/polyphony/backend_common.h +2 -22
  13. data/ext/polyphony/backend_io_uring.c +38 -78
  14. data/ext/polyphony/backend_libev.c +22 -67
  15. data/ext/polyphony/event.c +1 -1
  16. data/ext/polyphony/polyphony.c +0 -2
  17. data/ext/polyphony/polyphony.h +5 -4
  18. data/ext/polyphony/queue.c +2 -2
  19. data/ext/polyphony/thread.c +9 -28
  20. data/lib/polyphony.rb +2 -1
  21. data/lib/polyphony/adapters/postgres.rb +3 -3
  22. data/lib/polyphony/adapters/process.rb +2 -0
  23. data/lib/polyphony/core/global_api.rb +14 -2
  24. data/lib/polyphony/core/thread_pool.rb +3 -1
  25. data/lib/polyphony/core/throttler.rb +1 -1
  26. data/lib/polyphony/core/timer.rb +72 -0
  27. data/lib/polyphony/extensions/fiber.rb +32 -8
  28. data/lib/polyphony/extensions/io.rb +8 -14
  29. data/lib/polyphony/extensions/openssl.rb +4 -4
  30. data/lib/polyphony/extensions/socket.rb +13 -10
  31. data/lib/polyphony/net.rb +3 -6
  32. data/lib/polyphony/version.rb +1 -1
  33. data/polyphony.gemspec +1 -1
  34. data/test/helper.rb +1 -0
  35. data/test/test_backend.rb +1 -1
  36. data/test/test_fiber.rb +64 -1
  37. data/test/test_global_api.rb +30 -0
  38. data/test/test_io.rb +26 -0
  39. data/test/test_socket.rb +32 -6
  40. data/test/test_supervise.rb +2 -1
  41. data/test/test_timer.rb +124 -0
  42. metadata +8 -4
  43. data/ext/polyphony/backend.h +0 -26
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.47.4)
4
+ polyphony (0.49.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2020 Sharon Rosner
3
+ Copyright (c) 2021 Sharon Rosner
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/TODO.md CHANGED
@@ -1,49 +1,58 @@
1
- - Graceful shutdown again:
1
+ - Check segfault when resetting a `cancel_after` timeout lots of times at very high rate
2
+ - Check why `throttled_loop` inside of `move_on_after` fails to stop
2
3
 
3
- - Add `Polyphony::GracefulShutdown` exception
4
- - Two exceptions for stopping fibers:
5
- - `Polyphony::GracefulShutdown` - graceful shutdown
6
- - `Polyphony::Terminate` - ungraceful shutdown
7
- - Fiber API:
8
- - `Fiber#shutdown_children` - graceful shutdown of all children
9
- - `Fiber#terminate_children` - ungraceful shutdown of all children
4
+ - Override stock `::SizedQueue` impl with Queue with capacity
10
5
 
11
- - Add `Fiber#graceful_shutdown?` method
12
- - Returns false unless a `Polyphony::GracefulShutdown` was raised
13
- - Override `Polyphony::Terminate#invoke` to reset the `@graceful_shutdown` fiber
14
- flag
6
+ - Add support for `break` and `StopIteration` in all loops (with tests)
15
7
 
16
- And then we have:
8
+ - Change `IO#gets` to use `String#split` to cut into lines, much faster (see
9
+ examples/performance/line_splitting.rb)
10
+
11
+ - More tight loops
12
+ - `IO#gets_loop`, `Socket#gets_loop`, `OpenSSL::Socket#gets_loop` (medium effort)
13
+ - `Fiber#receive_loop` (very little effort, should be implemented in C)
17
14
 
18
- ```ruby
19
- spin do
20
- loop { do_some_stuff }
21
- ensure
22
- return unless Fiber.current.graceful_shutdown?
23
15
 
24
- shutdown_gracefully
16
+ - Add `Backend#splice`, `Backend#splice_loop` for implementing stuff like proxying:
17
+
18
+ ```ruby
19
+ def two_way_proxy(socket1, socket2)
20
+ backend = Thread.current.backend
21
+ f1 = spin { backend.splice_loop(socket1, socket2) }
22
+ f2 = spin { backend.splice_loop(socket2, socket1) }
23
+ Fiber.await(f1, f2)
25
24
  end
26
25
  ```
27
26
 
28
- - When a fiber is stopped it should use `Polyphony::Terminate` to stop child
29
- fibers, *unless* it was stopped with a `Polyphony::GracefulShutdown` (which it
30
- can check with `@graceful_shutdown`).
31
-
32
- - More tight loops
33
- - IO#gets_loop, Socket#gets_loop, OpenSSL::Socket#gets_loop (medium effort)
34
- - Fiber#receive_loop (very little effort, should be implemented in C)
27
+ - Graceful shutdown again:
28
+ - What happens to children when doing a graceful shutdown?
29
+ - What are the implications of passing graceful shutdown flag to children?
30
+ - What about errors while doing a graceful shutdown?
31
+ - What about graceful restarts?
32
+ - Some interesting discussions:
33
+ - https://trio.discourse.group/search?q=graceful%20shutdown
34
+ - https://github.com/python-trio/trio/issues/147
35
+ - https://github.com/python-trio/trio/issues/143
36
+ - https://trio.discourse.group/t/graceful-shutdown/93/2
37
+ - https://250bpm.com/blog:146/
38
+ - https://www.rodrigoaraujo.me/posts/golang-pattern-graceful-shutdown-of-concurrent-events/
39
+ - https://github.com/tj/go-gracefully
40
+ - `Fiber#finalize_children` should pass graceful shutdown flag to children
41
+ - A good use case is an HTTP server that on graceful shutdown:
42
+ - stops listening
43
+ - waits for all ongoing requests to finish, optionally with a timeout
35
44
 
36
45
  ## Roadmap for Polyphony 1.0
37
46
 
38
47
  - check integration with rb-inotify
39
48
 
40
- - Check why worker-thread example doesn't work.
49
+ - Improve `#supervise`. It does not work as advertised, and seems to exhibit an
50
+ inconsistent behaviour (see supervisor example).
51
+
41
52
  - Add test that mimics the original design for Monocrono:
42
53
  - 256 fibers each waiting for a message
43
54
  - When message received do some blocking work using a `ThreadPool`
44
55
  - Send messages, collect responses, check for correctness
45
- - Improve `#supervise`. It does not work as advertised, and seems to exhibit an
46
- inconsistent behaviour (see supervisor example).
47
56
 
48
57
  - io_uring
49
58
  - Use playground.c to find out why we when submitting and waiting for
@@ -9,9 +9,9 @@ def my_sleep(t)
9
9
  puts "#{t} done"
10
10
  end
11
11
 
12
- spin { my_sleep(1) }
13
- spin { my_sleep(2) }
14
- spin { my_sleep(3) }
12
+ spin { my_sleep(0.1) }
13
+ spin { my_sleep(0.2) }
14
+ spin { my_sleep(0.3) }
15
15
  spin { puts "fiber count: #{Fiber.current.children.count}" }
16
16
  snooze
17
17
 
@@ -13,11 +13,9 @@ end
13
13
  $worker = Thread.new do
14
14
  Fiber.current.tag = :worker
15
15
  loop do
16
- client, block = receive
16
+ (client, block) = receive
17
17
  do_work(client, &block)
18
18
  end
19
- rescue Exception => e
20
- p e
21
19
  end
22
20
 
23
21
  def process(&block)
@@ -27,4 +25,5 @@ end
27
25
 
28
26
  sleep 0.1
29
27
 
30
- p process { 1 + 1 }
28
+ p process { 1 + 1 }
29
+ p process { 42 ** 2 }
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ server1 = TCPServer.open('127.0.0.1', 1234)
7
+ server2 = TCPServer.open('127.0.0.1', 1235)
8
+
9
+ puts "Pid: #{Process.pid}"
10
+ puts 'Proxying port 1234 => port 1235'
11
+
12
+ client1 = client2 = nil
13
+
14
+ f1 = spin {
15
+ client1 = server1.accept
16
+ loop do
17
+ if client2
18
+ Thread.current.backend.splice_loop(client1, client2)
19
+ end
20
+ end
21
+ }
22
+
23
+ f2 = spin {
24
+ client2 = server2.accept
25
+ loop do
26
+ if client1
27
+ Thread.current.backend.splice_loop(client2, client1)
28
+ end
29
+ end
30
+ }
31
+
32
+ Fiber.await(f1, f2)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "benchmark/ips"
4
+
5
+ def slice
6
+ str = ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40)
7
+ lines = []
8
+ while true
9
+ idx = str.index("\n")
10
+ break unless idx
11
+
12
+ lines << str.slice!(0, idx + 1)
13
+ end
14
+ raise unless lines.size == 4
15
+ raise unless str == ('*' * 40)
16
+ end
17
+
18
+ def split
19
+ str = ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40) + "\n" + ('*' * 40)
20
+ lines = str.split("\n")
21
+ if str[-1] == "\n"
22
+ str = ''
23
+ else
24
+ str = lines.pop
25
+ end
26
+ raise unless lines.size == 4
27
+ raise unless str == ('*' * 40)
28
+ end
29
+
30
+ Benchmark.ips do |x|
31
+ x.report("slice") { slice }
32
+ x.report("split") { split }
33
+ x.compare!
34
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark'
4
+
5
+ LIMIT = 1_000_0
6
+
7
+ def do_while
8
+ i = 0
9
+ while true
10
+ i += 1
11
+ break if i == LIMIT
12
+ end
13
+ end
14
+
15
+ def do_loop
16
+ i = 0
17
+ loop do
18
+ i += 1
19
+ break if i == LIMIT
20
+ end
21
+ end
22
+
23
+ GC.disable
24
+ Benchmark.bm do |x|
25
+ x.report('while') do
26
+ LIMIT.times { do_while }
27
+ end
28
+ x.report('loop') do
29
+ LIMIT.times { do_loop }
30
+ end
31
+ end
32
+
@@ -29,6 +29,12 @@ end
29
29
  server = TCPServer.open('0.0.0.0', 1234)
30
30
  puts "pid #{Process.pid} Polyphony (#{Thread.current.backend.kind}) listening on port 1234"
31
31
 
32
+ spin_loop(interval: 10) do
33
+ p Thread.current.fiber_scheduling_stats
34
+ end
35
+
36
+ GC.disable
37
+
32
38
  server.accept_loop do |c|
33
39
  spin { handle_client(c) }
34
40
  end
@@ -3,26 +3,6 @@
3
3
  #include "ruby.h"
4
4
  #include "ruby/io.h"
5
5
 
6
- VALUE cTCPSocket;
7
- VALUE cTCPServer;
8
- VALUE cUNIXSocket;
9
- VALUE cUNIXServer;
10
-
11
- void Init_SocketClasses() {
12
- rb_require("socket");
13
- cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
14
- cTCPServer = rb_const_get(rb_cObject, rb_intern("TCPServer"));
15
- cUNIXSocket = rb_const_get(rb_cObject, rb_intern("UNIXSocket"));
16
- cUNIXServer = rb_const_get(rb_cObject, rb_intern("UNIXServer"));
17
- }
18
-
19
- VALUE ConnectionSocketClass(VALUE server) {
20
- if (RTEST(rb_obj_is_kind_of(server, cTCPServer))) return cTCPSocket;
21
- if (RTEST(rb_obj_is_kind_of(server, cUNIXServer))) return cUNIXSocket;
22
-
23
- rb_raise(rb_eRuntimeError, "Invalid server class");
24
- }
25
-
26
6
  //////////////////////////////////////////////////////////////////////
27
7
  //////////////////////////////////////////////////////////////////////
28
8
  // the following is copied verbatim from the Ruby source code (io.c)
@@ -90,9 +70,9 @@ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
90
70
 
91
71
  inline VALUE backend_await(Backend_t *backend) {
92
72
  VALUE ret;
93
- backend->ref_count++;
73
+ backend->pending_count++;
94
74
  ret = Thread_switch_fiber(rb_thread_current());
95
- backend->ref_count--;
75
+ backend->pending_count--;
96
76
  RB_GC_GUARD(ret);
97
77
  return ret;
98
78
  }
@@ -30,11 +30,14 @@ static int pidfd_open(pid_t pid, unsigned int flags) {
30
30
  VALUE SYM_io_uring;
31
31
 
32
32
  typedef struct Backend_t {
33
+ // common fields
34
+ unsigned int currently_polling;
35
+ unsigned int pending_count;
36
+ unsigned int poll_no_wait_count;
37
+
38
+ // implementation-specific fields
33
39
  struct io_uring ring;
34
40
  op_context_store_t store;
35
- int waiting_for_cqe;
36
- unsigned int ref_count;
37
- unsigned int run_no_wait_count;
38
41
  unsigned int pending_sqes;
39
42
  unsigned int prepared_limit;
40
43
  int event_fd;
@@ -65,11 +68,11 @@ static VALUE Backend_initialize(VALUE self) {
65
68
  Backend_t *backend;
66
69
  GetBackend(self, backend);
67
70
 
68
- backend->waiting_for_cqe = 0;
69
- backend->ref_count = 0;
70
- backend->run_no_wait_count = 0;
71
+ backend->currently_polling = 0;
72
+ backend->pending_count = 0;
73
+ backend->poll_no_wait_count = 0;
71
74
  backend->pending_sqes = 0;
72
- backend->prepared_limit = 1024;
75
+ backend->prepared_limit = 2048;
73
76
 
74
77
  context_store_initialize(&backend->store);
75
78
  io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
@@ -95,46 +98,19 @@ VALUE Backend_post_fork(VALUE self) {
95
98
  io_uring_queue_exit(&backend->ring);
96
99
  io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
97
100
  context_store_free(&backend->store);
98
- backend->waiting_for_cqe = 0;
99
- backend->ref_count = 0;
100
- backend->run_no_wait_count = 0;
101
+ backend->currently_polling = 0;
102
+ backend->pending_count = 0;
103
+ backend->poll_no_wait_count = 0;
101
104
  backend->pending_sqes = 0;
102
105
 
103
106
  return self;
104
107
  }
105
108
 
106
- VALUE Backend_ref(VALUE self) {
107
- Backend_t *backend;
108
- GetBackend(self, backend);
109
-
110
- backend->ref_count++;
111
- return self;
112
- }
113
-
114
- VALUE Backend_unref(VALUE self) {
115
- Backend_t *backend;
116
- GetBackend(self, backend);
117
-
118
- backend->ref_count--;
119
- return self;
120
- }
121
-
122
- int Backend_ref_count(VALUE self) {
123
- Backend_t *backend;
124
- GetBackend(self, backend);
125
-
126
- return backend->ref_count;
127
- }
128
-
129
- void Backend_reset_ref_count(VALUE self) {
109
+ unsigned int Backend_pending_count(VALUE self) {
130
110
  Backend_t *backend;
131
111
  GetBackend(self, backend);
132
112
 
133
- backend->ref_count = 0;
134
- }
135
-
136
- VALUE Backend_pending_count(VALUE self) {
137
- return INT2NUM(0);
113
+ return backend->pending_count;
138
114
  }
139
115
 
140
116
  typedef struct poll_context {
@@ -158,7 +134,7 @@ static inline bool cq_ring_needs_flush(struct io_uring *ring) {
158
134
 
159
135
  void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
160
136
  op_context_t *ctx = io_uring_cqe_get_data(cqe);
161
- if (ctx == 0) return;
137
+ if (!ctx) return;
162
138
 
163
139
  ctx->result = cqe->res;
164
140
 
@@ -211,9 +187,9 @@ void io_uring_backend_poll(Backend_t *backend) {
211
187
  io_uring_submit(&backend->ring);
212
188
  }
213
189
 
214
- backend->waiting_for_cqe = 1;
190
+ backend->currently_polling = 1;
215
191
  rb_thread_call_without_gvl(io_uring_backend_poll_without_gvl, (void *)&poll_ctx, RUBY_UBF_IO, 0);
216
- backend->waiting_for_cqe = 0;
192
+ backend->currently_polling = 0;
217
193
  if (poll_ctx.result < 0) return;
218
194
 
219
195
  io_uring_backend_handle_completion(poll_ctx.cqe, backend);
@@ -226,14 +202,14 @@ VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue
226
202
  GetBackend(self, backend);
227
203
 
228
204
  if (is_nowait) {
229
- backend->run_no_wait_count++;
230
- if (backend->run_no_wait_count < 10) return self;
205
+ backend->poll_no_wait_count++;
206
+ if (backend->poll_no_wait_count < 10) return self;
231
207
 
232
208
  long runnable_count = Runqueue_len(runqueue);
233
- if (backend->run_no_wait_count < runnable_count) return self;
209
+ if (backend->poll_no_wait_count < runnable_count) return self;
234
210
  }
235
211
 
236
- backend->run_no_wait_count = 0;
212
+ backend->poll_no_wait_count = 0;
237
213
 
238
214
  if (is_nowait && backend->pending_sqes) {
239
215
  backend->pending_sqes = 0;
@@ -252,7 +228,7 @@ VALUE Backend_wakeup(VALUE self) {
252
228
  Backend_t *backend;
253
229
  GetBackend(self, backend);
254
230
 
255
- if (backend->waiting_for_cqe) {
231
+ if (backend->currently_polling) {
256
232
  // Since we're currently blocking while waiting for a completion, we add a
257
233
  // NOP which would cause the io_uring_enter syscall to return
258
234
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
@@ -284,12 +260,12 @@ int io_uring_backend_defer_submit_and_await(
284
260
  VALUE switchpoint_result = Qnil;
285
261
 
286
262
  io_uring_sqe_set_data(sqe, ctx);
287
- io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
263
+ // io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
288
264
  io_uring_backend_defer_submit(backend);
289
265
 
290
- backend->ref_count++;
266
+ backend->pending_count++;
291
267
  switchpoint_result = backend_await(backend);
292
- backend->ref_count--;
268
+ backend->pending_count--;
293
269
 
294
270
  if (!ctx->completed) {
295
271
  ctx->result = -ECANCELED;
@@ -351,7 +327,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
351
327
 
352
328
  if (result < 0)
353
329
  rb_syserr_fail(-result, strerror(-result));
354
- else if (result == 0)
330
+ else if (!result)
355
331
  break; // EOF
356
332
  else {
357
333
  total += result;
@@ -373,7 +349,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
373
349
  io_set_read_length(str, total, shrinkable);
374
350
  io_enc_str(str, fptr);
375
351
 
376
- if (total == 0) return Qnil;
352
+ if (!total) return Qnil;
377
353
 
378
354
  return str;
379
355
  }
@@ -410,7 +386,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
410
386
 
411
387
  if (result < 0)
412
388
  rb_syserr_fail(-result, strerror(-result));
413
- else if (result == 0)
389
+ else if (!result)
414
390
  break; // EOF
415
391
  else {
416
392
  total = result;
@@ -581,7 +557,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
581
557
  io_set_read_length(str, total, shrinkable);
582
558
  io_enc_str(str, fptr);
583
559
 
584
- if (total == 0) return Qnil;
560
+ if (!total) return Qnil;
585
561
 
586
562
  return str;
587
563
  }
@@ -618,7 +594,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io) {
618
594
 
619
595
  if (result < 0)
620
596
  rb_syserr_fail(-result, strerror(-result));
621
- else if (result == 0)
597
+ else if (!result)
622
598
  break; // EOF
623
599
  else {
624
600
  total = result;
@@ -668,12 +644,11 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str) {
668
644
  return INT2NUM(len);
669
645
  }
670
646
 
671
- VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, int loop) {
647
+ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE socket_class, int loop) {
672
648
  rb_io_t *fptr;
673
649
  struct sockaddr addr;
674
650
  socklen_t len = (socklen_t)sizeof addr;
675
651
  VALUE socket = Qnil;
676
- VALUE socket_class = ConnectionSocketClass(server_socket);
677
652
  VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
678
653
  if (underlying_sock != Qnil) server_socket = underlying_sock;
679
654
 
@@ -718,16 +693,16 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, int loop)
718
693
  return Qnil;
719
694
  }
720
695
 
721
- VALUE Backend_accept(VALUE self, VALUE sock) {
696
+ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
722
697
  Backend_t *backend;
723
698
  GetBackend(self, backend);
724
- return io_uring_backend_accept(backend, sock, 0);
699
+ return io_uring_backend_accept(backend, server_socket, socket_class, 0);
725
700
  }
726
701
 
727
- VALUE Backend_accept_loop(VALUE self, VALUE sock) {
702
+ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
728
703
  Backend_t *backend;
729
704
  GetBackend(self, backend);
730
- io_uring_backend_accept(backend, sock, 1);
705
+ io_uring_backend_accept(backend, server_socket, socket_class, 1);
731
706
  return self;
732
707
  }
733
708
 
@@ -945,18 +920,12 @@ VALUE Backend_kind(VALUE self) {
945
920
  }
946
921
 
947
922
  void Init_Backend() {
948
- Init_SocketClasses();
949
-
950
923
  VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
951
924
  rb_define_alloc_func(cBackend, Backend_allocate);
952
925
 
953
926
  rb_define_method(cBackend, "initialize", Backend_initialize, 0);
954
927
  rb_define_method(cBackend, "finalize", Backend_finalize, 0);
955
928
  rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
956
- rb_define_method(cBackend, "pending_count", Backend_pending_count, 0);
957
-
958
- rb_define_method(cBackend, "ref", Backend_ref, 0);
959
- rb_define_method(cBackend, "unref", Backend_unref, 0);
960
929
 
961
930
  rb_define_method(cBackend, "poll", Backend_poll, 3);
962
931
  rb_define_method(cBackend, "break", Backend_wakeup, 0);
@@ -967,8 +936,8 @@ void Init_Backend() {
967
936
  rb_define_method(cBackend, "recv", Backend_recv, 3);
968
937
  rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
969
938
  rb_define_method(cBackend, "send", Backend_send, 2);
970
- rb_define_method(cBackend, "accept", Backend_accept, 1);
971
- rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 1);
939
+ rb_define_method(cBackend, "accept", Backend_accept, 2);
940
+ rb_define_method(cBackend, "accept_loop", Backend_accept_loop, 2);
972
941
  rb_define_method(cBackend, "connect", Backend_connect, 3);
973
942
  rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
974
943
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
@@ -980,15 +949,6 @@ void Init_Backend() {
980
949
  rb_define_method(cBackend, "kind", Backend_kind, 0);
981
950
 
982
951
  SYM_io_uring = ID2SYM(rb_intern("io_uring"));
983
-
984
- __BACKEND__.pending_count = Backend_pending_count;
985
- __BACKEND__.poll = Backend_poll;
986
- __BACKEND__.ref = Backend_ref;
987
- __BACKEND__.ref_count = Backend_ref_count;
988
- __BACKEND__.reset_ref_count = Backend_reset_ref_count;
989
- __BACKEND__.unref = Backend_unref;
990
- __BACKEND__.wait_event = Backend_wait_event;
991
- __BACKEND__.wakeup = Backend_wakeup;
992
952
  }
993
953
 
994
954
  #endif // POLYPHONY_BACKEND_LIBURING