polyphony 0.47.2 → 0.48.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +317 -293
  3. data/Gemfile.lock +1 -1
  4. data/TODO.md +46 -3
  5. data/examples/core/supervisor.rb +3 -3
  6. data/examples/core/worker-thread.rb +3 -4
  7. data/examples/io/tcp_proxy.rb +32 -0
  8. data/examples/io/unix_socket.rb +26 -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 -2
  13. data/ext/polyphony/backend_io_uring.c +42 -83
  14. data/ext/polyphony/backend_libev.c +32 -77
  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/adapters/postgres.rb +3 -3
  21. data/lib/polyphony/core/global_api.rb +19 -16
  22. data/lib/polyphony/core/resource_pool.rb +1 -12
  23. data/lib/polyphony/core/thread_pool.rb +3 -1
  24. data/lib/polyphony/core/throttler.rb +1 -1
  25. data/lib/polyphony/extensions/fiber.rb +34 -8
  26. data/lib/polyphony/extensions/io.rb +8 -14
  27. data/lib/polyphony/extensions/openssl.rb +4 -4
  28. data/lib/polyphony/extensions/socket.rb +68 -16
  29. data/lib/polyphony/version.rb +1 -1
  30. data/polyphony.gemspec +1 -1
  31. data/test/helper.rb +1 -0
  32. data/test/test_backend.rb +1 -1
  33. data/test/test_fiber.rb +64 -0
  34. data/test/test_global_api.rb +41 -1
  35. data/test/test_io.rb +26 -0
  36. data/test/test_resource_pool.rb +0 -21
  37. data/test/test_signal.rb +18 -0
  38. data/test/test_socket.rb +27 -2
  39. data/test/test_supervise.rb +2 -1
  40. metadata +7 -4
  41. data/ext/polyphony/backend.h +0 -26
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.47.2)
4
+ polyphony (0.48.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/TODO.md CHANGED
@@ -1,12 +1,55 @@
1
+ - Override stock `SizedQueue` impl with Queue with capacity
2
+
3
+ - Add support for `break` and `StopIteration` in all loops (with tests)
4
+
5
+ - Change `IO#gets` to use `String#split` to cut into lines, much faster (see
6
+ examples/performance/line_splitting.rb)
7
+
8
+ - More tight loops
9
+ - `IO#gets_loop`, `Socket#gets_loop`, `OpenSSL::Socket#gets_loop` (medium effort)
10
+ - `Fiber#receive_loop` (very little effort, should be implemented in C)
11
+
12
+
13
+ - Add `Backend#splice`, `Backend#splice_loop` for implementing stuff like proxying:
14
+
15
+ ```ruby
16
+ def two_way_proxy(socket1, socket2)
17
+ backend = Thread.current.backend
18
+ f1 = spin { backend.splice_loop(socket1, socket2) }
19
+ f2 = spin { backend.splice_loop(socket2, socket1) }
20
+ Fiber.await(f1, f2)
21
+ end
22
+ ```
23
+
24
+ - Graceful shutdown again:
25
+ - What happens to children when doing a graceful shutdown?
26
+ - What are the implications of passing graceful shutdown flag to children?
27
+ - What about errors while doing a graceful shutdown?
28
+ - What about graceful restarts?
29
+ - Some interesting discussions:
30
+ - https://trio.discourse.group/search?q=graceful%20shutdown
31
+ - https://github.com/python-trio/trio/issues/147
32
+ - https://github.com/python-trio/trio/issues/143
33
+ - https://trio.discourse.group/t/graceful-shutdown/93/2
34
+ - https://250bpm.com/blog:146/
35
+ - https://www.rodrigoaraujo.me/posts/golang-pattern-graceful-shutdown-of-concurrent-events/
36
+ - https://github.com/tj/go-gracefully
37
+ - `Fiber#finalize_children` should pass graceful shutdown flag to children
38
+ - A good use case is an HTTP server that on graceful shutdown:
39
+ - stops listening
40
+ - waits for all ongoing requests to finish, optionally with a timeout
41
+
1
42
  ## Roadmap for Polyphony 1.0
2
43
 
3
- - Check why worker-thread example doesn't work.
44
+ - check integration with rb-inotify
45
+
46
+ - Improve `#supervise`. It does not work as advertised, and seems to exhibit an
47
+ inconsistent behaviour (see supervisor example).
48
+
4
49
  - Add test that mimics the original design for Monocrono:
5
50
  - 256 fibers each waiting for a message
6
51
  - When message received do some blocking work using a `ThreadPool`
7
52
  - Send messages, collect responses, check for correctness
8
- - Improve `#supervise`. It does not work as advertised, and seems to exhibit an
9
- inconsistent behaviour (see supervisor example).
10
53
 
11
54
  - io_uring
12
55
  - 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,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+ require 'fileutils'
6
+
7
+ unix_path = '/tmp/polyphony-unix-socket'
8
+
9
+ FileUtils.rm unix_path rescue nil
10
+ server = UNIXServer.new(unix_path)
11
+ spin do
12
+ server.accept_loop do |socket|
13
+ p [:accept, socket]
14
+ spin do
15
+ while (line = socket.gets)
16
+ socket.puts line
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ snooze
23
+ client = UNIXSocket.new('/tmp/polyphony-unix-socket')
24
+ p [:connected, client]
25
+ client.puts 'hello!'
26
+ p client.gets
@@ -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
@@ -70,9 +70,9 @@ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
70
70
 
71
71
  inline VALUE backend_await(Backend_t *backend) {
72
72
  VALUE ret;
73
- backend->ref_count++;
73
+ backend->pending_count++;
74
74
  ret = Thread_switch_fiber(rb_thread_current());
75
- backend->ref_count--;
75
+ backend->pending_count--;
76
76
  RB_GC_GUARD(ret);
77
77
  return ret;
78
78
  }
@@ -27,15 +27,17 @@ static int pidfd_open(pid_t pid, unsigned int flags) {
27
27
  return syscall(__NR_pidfd_open, pid, flags);
28
28
  }
29
29
 
30
- VALUE cTCPSocket;
31
30
  VALUE SYM_io_uring;
32
31
 
33
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
34
39
  struct io_uring ring;
35
40
  op_context_store_t store;
36
- int waiting_for_cqe;
37
- unsigned int ref_count;
38
- unsigned int run_no_wait_count;
39
41
  unsigned int pending_sqes;
40
42
  unsigned int prepared_limit;
41
43
  int event_fd;
@@ -66,11 +68,11 @@ static VALUE Backend_initialize(VALUE self) {
66
68
  Backend_t *backend;
67
69
  GetBackend(self, backend);
68
70
 
69
- backend->waiting_for_cqe = 0;
70
- backend->ref_count = 0;
71
- backend->run_no_wait_count = 0;
71
+ backend->currently_polling = 0;
72
+ backend->pending_count = 0;
73
+ backend->poll_no_wait_count = 0;
72
74
  backend->pending_sqes = 0;
73
- backend->prepared_limit = 1024;
75
+ backend->prepared_limit = 256;
74
76
 
75
77
  context_store_initialize(&backend->store);
76
78
  io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
@@ -96,46 +98,19 @@ VALUE Backend_post_fork(VALUE self) {
96
98
  io_uring_queue_exit(&backend->ring);
97
99
  io_uring_queue_init(backend->prepared_limit, &backend->ring, 0);
98
100
  context_store_free(&backend->store);
99
- backend->waiting_for_cqe = 0;
100
- backend->ref_count = 0;
101
- backend->run_no_wait_count = 0;
101
+ backend->currently_polling = 0;
102
+ backend->pending_count = 0;
103
+ backend->poll_no_wait_count = 0;
102
104
  backend->pending_sqes = 0;
103
105
 
104
106
  return self;
105
107
  }
106
108
 
107
- VALUE Backend_ref(VALUE self) {
108
- Backend_t *backend;
109
- GetBackend(self, backend);
110
-
111
- backend->ref_count++;
112
- return self;
113
- }
114
-
115
- VALUE Backend_unref(VALUE self) {
109
+ unsigned int Backend_pending_count(VALUE self) {
116
110
  Backend_t *backend;
117
111
  GetBackend(self, backend);
118
112
 
119
- backend->ref_count--;
120
- return self;
121
- }
122
-
123
- int Backend_ref_count(VALUE self) {
124
- Backend_t *backend;
125
- GetBackend(self, backend);
126
-
127
- return backend->ref_count;
128
- }
129
-
130
- void Backend_reset_ref_count(VALUE self) {
131
- Backend_t *backend;
132
- GetBackend(self, backend);
133
-
134
- backend->ref_count = 0;
135
- }
136
-
137
- VALUE Backend_pending_count(VALUE self) {
138
- return INT2NUM(0);
113
+ return backend->pending_count;
139
114
  }
140
115
 
141
116
  typedef struct poll_context {
@@ -159,7 +134,7 @@ static inline bool cq_ring_needs_flush(struct io_uring *ring) {
159
134
 
160
135
  void io_uring_backend_handle_completion(struct io_uring_cqe *cqe, Backend_t *backend) {
161
136
  op_context_t *ctx = io_uring_cqe_get_data(cqe);
162
- if (ctx == 0) return;
137
+ if (!ctx) return;
163
138
 
164
139
  ctx->result = cqe->res;
165
140
 
@@ -212,9 +187,9 @@ void io_uring_backend_poll(Backend_t *backend) {
212
187
  io_uring_submit(&backend->ring);
213
188
  }
214
189
 
215
- backend->waiting_for_cqe = 1;
190
+ backend->currently_polling = 1;
216
191
  rb_thread_call_without_gvl(io_uring_backend_poll_without_gvl, (void *)&poll_ctx, RUBY_UBF_IO, 0);
217
- backend->waiting_for_cqe = 0;
192
+ backend->currently_polling = 0;
218
193
  if (poll_ctx.result < 0) return;
219
194
 
220
195
  io_uring_backend_handle_completion(poll_ctx.cqe, backend);
@@ -227,14 +202,14 @@ VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue
227
202
  GetBackend(self, backend);
228
203
 
229
204
  if (is_nowait) {
230
- backend->run_no_wait_count++;
231
- 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;
232
207
 
233
208
  long runnable_count = Runqueue_len(runqueue);
234
- if (backend->run_no_wait_count < runnable_count) return self;
209
+ if (backend->poll_no_wait_count < runnable_count) return self;
235
210
  }
236
211
 
237
- backend->run_no_wait_count = 0;
212
+ backend->poll_no_wait_count = 0;
238
213
 
239
214
  if (is_nowait && backend->pending_sqes) {
240
215
  backend->pending_sqes = 0;
@@ -253,7 +228,7 @@ VALUE Backend_wakeup(VALUE self) {
253
228
  Backend_t *backend;
254
229
  GetBackend(self, backend);
255
230
 
256
- if (backend->waiting_for_cqe) {
231
+ if (backend->currently_polling) {
257
232
  // Since we're currently blocking while waiting for a completion, we add a
258
233
  // NOP which would cause the io_uring_enter syscall to return
259
234
  struct io_uring_sqe *sqe = io_uring_get_sqe(&backend->ring);
@@ -285,12 +260,12 @@ int io_uring_backend_defer_submit_and_await(
285
260
  VALUE switchpoint_result = Qnil;
286
261
 
287
262
  io_uring_sqe_set_data(sqe, ctx);
288
- io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
263
+ // io_uring_sqe_set_flags(sqe, IOSQE_ASYNC);
289
264
  io_uring_backend_defer_submit(backend);
290
265
 
291
- backend->ref_count++;
266
+ backend->pending_count++;
292
267
  switchpoint_result = backend_await(backend);
293
- backend->ref_count--;
268
+ backend->pending_count--;
294
269
 
295
270
  if (!ctx->completed) {
296
271
  ctx->result = -ECANCELED;
@@ -352,7 +327,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
352
327
 
353
328
  if (result < 0)
354
329
  rb_syserr_fail(-result, strerror(-result));
355
- else if (result == 0)
330
+ else if (!result)
356
331
  break; // EOF
357
332
  else {
358
333
  total += result;
@@ -374,7 +349,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof)
374
349
  io_set_read_length(str, total, shrinkable);
375
350
  io_enc_str(str, fptr);
376
351
 
377
- if (total == 0) return Qnil;
352
+ if (!total) return Qnil;
378
353
 
379
354
  return str;
380
355
  }
@@ -411,7 +386,7 @@ VALUE Backend_read_loop(VALUE self, VALUE io) {
411
386
 
412
387
  if (result < 0)
413
388
  rb_syserr_fail(-result, strerror(-result));
414
- else if (result == 0)
389
+ else if (!result)
415
390
  break; // EOF
416
391
  else {
417
392
  total = result;
@@ -582,7 +557,7 @@ VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length) {
582
557
  io_set_read_length(str, total, shrinkable);
583
558
  io_enc_str(str, fptr);
584
559
 
585
- if (total == 0) return Qnil;
560
+ if (!total) return Qnil;
586
561
 
587
562
  return str;
588
563
  }
@@ -619,7 +594,7 @@ VALUE Backend_recv_loop(VALUE self, VALUE io) {
619
594
 
620
595
  if (result < 0)
621
596
  rb_syserr_fail(-result, strerror(-result));
622
- else if (result == 0)
597
+ else if (!result)
623
598
  break; // EOF
624
599
  else {
625
600
  total = result;
@@ -669,15 +644,15 @@ VALUE Backend_send(VALUE self, VALUE io, VALUE str) {
669
644
  return INT2NUM(len);
670
645
  }
671
646
 
672
- VALUE io_uring_backend_accept(Backend_t *backend, VALUE sock, int loop) {
647
+ VALUE io_uring_backend_accept(Backend_t *backend, VALUE server_socket, VALUE socket_class, int loop) {
673
648
  rb_io_t *fptr;
674
649
  struct sockaddr addr;
675
650
  socklen_t len = (socklen_t)sizeof addr;
676
- VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
677
651
  VALUE socket = Qnil;
678
- if (underlying_sock != Qnil) sock = underlying_sock;
652
+ VALUE underlying_sock = rb_ivar_get(server_socket, ID_ivar_io);
653
+ if (underlying_sock != Qnil) server_socket = underlying_sock;
679
654
 
680
- GetOpenFile(sock, fptr);
655
+ GetOpenFile(server_socket, fptr);
681
656
  while (1) {
682
657
  VALUE resume_value = Qnil;
683
658
  op_context_t *ctx = OP_CONTEXT_ACQUIRE(&backend->store, OP_ACCEPT);
@@ -695,7 +670,7 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE sock, int loop) {
695
670
  else {
696
671
  rb_io_t *fp;
697
672
 
698
- socket = rb_obj_alloc(cTCPSocket);
673
+ socket = rb_obj_alloc(socket_class);
699
674
  MakeOpenFile(socket, fp);
700
675
  rb_update_max_fd(fd);
701
676
  fp->fd = fd;
@@ -718,16 +693,16 @@ VALUE io_uring_backend_accept(Backend_t *backend, VALUE sock, 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,19 +920,12 @@ VALUE Backend_kind(VALUE self) {
945
920
  }
946
921
 
947
922
  void Init_Backend() {
948
- rb_require("socket");
949
- cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
950
-
951
923
  VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
952
924
  rb_define_alloc_func(cBackend, Backend_allocate);
953
925
 
954
926
  rb_define_method(cBackend, "initialize", Backend_initialize, 0);
955
927
  rb_define_method(cBackend, "finalize", Backend_finalize, 0);
956
928
  rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
957
- rb_define_method(cBackend, "pending_count", Backend_pending_count, 0);
958
-
959
- rb_define_method(cBackend, "ref", Backend_ref, 0);
960
- rb_define_method(cBackend, "unref", Backend_unref, 0);
961
929
 
962
930
  rb_define_method(cBackend, "poll", Backend_poll, 3);
963
931
  rb_define_method(cBackend, "break", Backend_wakeup, 0);
@@ -968,8 +936,8 @@ void Init_Backend() {
968
936
  rb_define_method(cBackend, "recv", Backend_recv, 3);
969
937
  rb_define_method(cBackend, "recv_loop", Backend_recv_loop, 1);
970
938
  rb_define_method(cBackend, "send", Backend_send, 2);
971
- rb_define_method(cBackend, "accept", Backend_accept, 1);
972
- 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);
973
941
  rb_define_method(cBackend, "connect", Backend_connect, 3);
974
942
  rb_define_method(cBackend, "wait_io", Backend_wait_io, 2);
975
943
  rb_define_method(cBackend, "sleep", Backend_sleep, 1);
@@ -981,15 +949,6 @@ void Init_Backend() {
981
949
  rb_define_method(cBackend, "kind", Backend_kind, 0);
982
950
 
983
951
  SYM_io_uring = ID2SYM(rb_intern("io_uring"));
984
-
985
- __BACKEND__.pending_count = Backend_pending_count;
986
- __BACKEND__.poll = Backend_poll;
987
- __BACKEND__.ref = Backend_ref;
988
- __BACKEND__.ref_count = Backend_ref_count;
989
- __BACKEND__.reset_ref_count = Backend_reset_ref_count;
990
- __BACKEND__.unref = Backend_unref;
991
- __BACKEND__.wait_event = Backend_wait_event;
992
- __BACKEND__.wakeup = Backend_wakeup;
993
952
  }
994
953
 
995
954
  #endif // POLYPHONY_BACKEND_LIBURING