polyphony 0.47.5.1 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4b0d95763e1c95248c83f2b649bdafa609e5a3877ea381afa1ce7253b340904
4
- data.tar.gz: c25589fd2a4433d21778281a631b364b5505ce27c9fe3f349d2a357a3dd30f97
3
+ metadata.gz: 3a699d313072b1beba17c900491dd2a4f454bc8faea69eb157634e98cba7ee90
4
+ data.tar.gz: 3d8579b2c927c34876560ce878e960b9bc48a857ce43890dc069b4f0fa5ad75f
5
5
  SHA512:
6
- metadata.gz: 2637f2f6aa6531e6b8bc62035a028caffd027d65668b1a1f6b957c9f89045d148b790003856ece2213ccf882e1eab12068578cce8ba0c8882213f3e8f9a125f3
7
- data.tar.gz: '0009c9eae3b3fc52239d26bc836d7a1b4d2bd24d922c02f9a986fbed5d26f76b618777422efe9909aaff27164cc53de9d7083f9b784bc5534b387e6735dc7be6'
6
+ metadata.gz: d6efca5f42f21fe25ab5e6064675c2806dcad9d86e2e80c908987fcce855dd520ab51c4913e5a9001d3e4a84880a6606d124fa46dedff7c2e437a1ef6e156a82
7
+ data.tar.gz: 73ad6c59d4f7e9f8f0d317f480be1ba33c1a70dcf130a717693c2bb5a9ef3e226bfff3bdb635461b505bd2e9bbec7a2174c6a206bee2a94709ba9739ab087956
@@ -1,3 +1,9 @@
1
+ ## 0.48.0
2
+
3
+ - Implement graceful shutdown
4
+ - Add support for `break` / `StopIteration` in `spin_loop`
5
+ - Fix `IO#gets`, `IO#readpartial`
6
+
1
7
  ## 0.47.5.1
2
8
 
3
9
  - Add missing `Socket#accept_loop` method
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.47.5.1)
4
+ polyphony (0.48.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/TODO.md CHANGED
@@ -1,29 +1,43 @@
1
- - Graceful shutdown again:
1
+ - Override stock `SizedQueue` impl with Queue with capacity
2
+
3
+ - Add support for `break` and `StopIteration` in all loops (with tests)
2
4
 
3
- - Fiber API:
4
- - `Fiber#terminate(graceul)` - with a graceful flag
5
- - `Fiber#terminate_all_children(graceful)` - with a graceful flag
6
- - `Fiber#shutdown_all_children(graceful)` - with a graceful flag
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)
7
11
 
8
- - Set graceful termination in `@graceful_shutdown`
9
- - Add `Fiber#graceful_shutdown?` method
10
- - Returns `@graceful_shutdown`
11
12
 
12
- And then we have:
13
+ - Add `Backend#splice`, `Backend#splice_loop` for implementing stuff like proxying:
13
14
 
14
15
  ```ruby
15
- spin do
16
- loop { do_some_stuff }
17
- ensure
18
- shutdown_gracefully if Fiber.current.graceful_shutdown?
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)
19
21
  end
20
22
  ```
21
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
22
37
  - `Fiber#finalize_children` should pass graceful shutdown flag to children
23
-
24
- - More tight loops
25
- - IO#gets_loop, Socket#gets_loop, OpenSSL::Socket#gets_loop (medium effort)
26
- - Fiber#receive_loop (very little effort, should be implemented in C)
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
27
41
 
28
42
  ## Roadmap for Polyphony 1.0
29
43
 
@@ -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
@@ -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
  }
@@ -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 = 256;
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) {
109
+ unsigned int Backend_pending_count(VALUE self) {
115
110
  Backend_t *backend;
116
111
  GetBackend(self, backend);
117
112
 
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) {
130
- Backend_t *backend;
131
- GetBackend(self, backend);
132
-
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;
@@ -950,10 +926,6 @@ void Init_Backend() {
950
926
  rb_define_method(cBackend, "initialize", Backend_initialize, 0);
951
927
  rb_define_method(cBackend, "finalize", Backend_finalize, 0);
952
928
  rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
953
- rb_define_method(cBackend, "pending_count", Backend_pending_count, 0);
954
-
955
- rb_define_method(cBackend, "ref", Backend_ref, 0);
956
- rb_define_method(cBackend, "unref", Backend_unref, 0);
957
929
 
958
930
  rb_define_method(cBackend, "poll", Backend_poll, 3);
959
931
  rb_define_method(cBackend, "break", Backend_wakeup, 0);
@@ -977,15 +949,6 @@ void Init_Backend() {
977
949
  rb_define_method(cBackend, "kind", Backend_kind, 0);
978
950
 
979
951
  SYM_io_uring = ID2SYM(rb_intern("io_uring"));
980
-
981
- __BACKEND__.pending_count = Backend_pending_count;
982
- __BACKEND__.poll = Backend_poll;
983
- __BACKEND__.ref = Backend_ref;
984
- __BACKEND__.ref_count = Backend_ref_count;
985
- __BACKEND__.reset_ref_count = Backend_reset_ref_count;
986
- __BACKEND__.unref = Backend_unref;
987
- __BACKEND__.wait_event = Backend_wait_event;
988
- __BACKEND__.wakeup = Backend_wakeup;
989
952
  }
990
953
 
991
954
  #endif // POLYPHONY_BACKEND_LIBURING
@@ -40,11 +40,14 @@ inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
40
40
  }
41
41
 
42
42
  typedef struct Backend_t {
43
+ // common fields
44
+ unsigned int currently_polling;
45
+ unsigned int pending_count;
46
+ unsigned int poll_no_wait_count;
47
+
48
+ // implementation-specific fields
43
49
  struct ev_loop *ev_loop;
44
50
  struct ev_async break_async;
45
- int running;
46
- int ref_count;
47
- int run_no_wait_count;
48
51
  } Backend_t;
49
52
 
50
53
  static size_t Backend_size(const void *ptr) {
@@ -83,9 +86,9 @@ static VALUE Backend_initialize(VALUE self) {
83
86
  ev_async_start(backend->ev_loop, &backend->break_async);
84
87
  ev_unref(backend->ev_loop); // don't count the break_async watcher
85
88
 
86
- backend->running = 0;
87
- backend->ref_count = 0;
88
- backend->run_no_wait_count = 0;
89
+ backend->currently_polling = 0;
90
+ backend->pending_count = 0;
91
+ backend->poll_no_wait_count = 0;
89
92
 
90
93
  return Qnil;
91
94
  }
@@ -116,42 +119,11 @@ VALUE Backend_post_fork(VALUE self) {
116
119
  return self;
117
120
  }
118
121
 
119
- VALUE Backend_ref(VALUE self) {
120
- Backend_t *backend;
121
- GetBackend(self, backend);
122
-
123
- backend->ref_count++;
124
- return self;
125
- }
126
-
127
- VALUE Backend_unref(VALUE self) {
128
- Backend_t *backend;
129
- GetBackend(self, backend);
130
-
131
- backend->ref_count--;
132
- return self;
133
- }
134
-
135
- int Backend_ref_count(VALUE self) {
136
- Backend_t *backend;
137
- GetBackend(self, backend);
138
-
139
- return backend->ref_count;
140
- }
141
-
142
- void Backend_reset_ref_count(VALUE self) {
122
+ unsigned int Backend_pending_count(VALUE self) {
143
123
  Backend_t *backend;
144
124
  GetBackend(self, backend);
145
125
 
146
- backend->ref_count = 0;
147
- }
148
-
149
- VALUE Backend_pending_count(VALUE self) {
150
- int count;
151
- Backend_t *backend;
152
- GetBackend(self, backend);
153
- count = ev_pending_count(backend->ev_loop);
154
- return INT2NUM(count);
126
+ return backend->pending_count;
155
127
  }
156
128
 
157
129
  VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue) {
@@ -160,19 +132,19 @@ VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue
160
132
  GetBackend(self, backend);
161
133
 
162
134
  if (is_nowait) {
163
- backend->run_no_wait_count++;
164
- if (backend->run_no_wait_count < 10) return self;
135
+ backend->poll_no_wait_count++;
136
+ if (backend->poll_no_wait_count < 10) return self;
165
137
 
166
138
  long runnable_count = Runqueue_len(runqueue);
167
- if (backend->run_no_wait_count < runnable_count) return self;
139
+ if (backend->poll_no_wait_count < runnable_count) return self;
168
140
  }
169
141
 
170
- backend->run_no_wait_count = 0;
142
+ backend->poll_no_wait_count = 0;
171
143
 
172
144
  COND_TRACE(2, SYM_fiber_event_poll_enter, current_fiber);
173
- backend->running = 1;
145
+ backend->currently_polling = 1;
174
146
  ev_run(backend->ev_loop, is_nowait ? EVRUN_NOWAIT : EVRUN_ONCE);
175
- backend->running = 0;
147
+ backend->currently_polling = 0;
176
148
  COND_TRACE(2, SYM_fiber_event_poll_leave, current_fiber);
177
149
 
178
150
  return self;
@@ -182,7 +154,7 @@ VALUE Backend_wakeup(VALUE self) {
182
154
  Backend_t *backend;
183
155
  GetBackend(self, backend);
184
156
 
185
- if (backend->running) {
157
+ if (backend->currently_polling) {
186
158
  // Since the loop will run until at least one event has occurred, we signal
187
159
  // the selector's associated async watcher, which will cause the ev loop to
188
160
  // return. In contrast to using `ev_break` to break out of the loop, which
@@ -854,10 +826,6 @@ void Init_Backend() {
854
826
  rb_define_method(cBackend, "initialize", Backend_initialize, 0);
855
827
  rb_define_method(cBackend, "finalize", Backend_finalize, 0);
856
828
  rb_define_method(cBackend, "post_fork", Backend_post_fork, 0);
857
- rb_define_method(cBackend, "pending_count", Backend_pending_count, 0);
858
-
859
- rb_define_method(cBackend, "ref", Backend_ref, 0);
860
- rb_define_method(cBackend, "unref", Backend_unref, 0);
861
829
 
862
830
  rb_define_method(cBackend, "poll", Backend_poll, 3);
863
831
  rb_define_method(cBackend, "break", Backend_wakeup, 0);
@@ -882,15 +850,6 @@ void Init_Backend() {
882
850
 
883
851
  ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
884
852
  SYM_libev = ID2SYM(rb_intern("libev"));
885
-
886
- __BACKEND__.pending_count = Backend_pending_count;
887
- __BACKEND__.poll = Backend_poll;
888
- __BACKEND__.ref = Backend_ref;
889
- __BACKEND__.ref_count = Backend_ref_count;
890
- __BACKEND__.reset_ref_count = Backend_reset_ref_count;
891
- __BACKEND__.unref = Backend_unref;
892
- __BACKEND__.wait_event = Backend_wait_event;
893
- __BACKEND__.wakeup = Backend_wakeup;
894
853
  }
895
854
 
896
855
  #endif // POLYPHONY_BACKEND_LIBEV
@@ -66,7 +66,7 @@ VALUE Event_await(VALUE self) {
66
66
 
67
67
  VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
68
68
  event->waiting_fiber = rb_fiber_current();
69
- VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
69
+ VALUE switchpoint_result = Backend_wait_event(backend, Qnil);
70
70
  event->waiting_fiber = Qnil;
71
71
 
72
72
  RAISE_IF_EXCEPTION(switchpoint_result);
@@ -22,8 +22,6 @@ ID ID_R;
22
22
  ID ID_W;
23
23
  ID ID_RW;
24
24
 
25
- backend_interface_t backend_interface;
26
-
27
25
  VALUE Polyphony_snooze(VALUE self) {
28
26
  VALUE ret;
29
27
  VALUE fiber = rb_fiber_current();
@@ -4,7 +4,6 @@
4
4
  #include <execinfo.h>
5
5
 
6
6
  #include "ruby.h"
7
- #include "backend.h"
8
7
  #include "runqueue_ring_buffer.h"
9
8
 
10
9
  // debugging
@@ -32,9 +31,6 @@
32
31
  // Fiber#transfer
33
32
  #define FIBER_TRANSFER(fiber, value) rb_funcall(fiber, ID_transfer, 1, value)
34
33
 
35
- extern backend_interface_t backend_interface;
36
- #define __BACKEND__ (backend_interface)
37
-
38
34
  extern VALUE mPolyphony;
39
35
  extern VALUE cQueue;
40
36
  extern VALUE cEvent;
@@ -92,6 +88,11 @@ void Runqueue_clear(VALUE self);
92
88
  long Runqueue_len(VALUE self);
93
89
  int Runqueue_empty_p(VALUE self);
94
90
 
91
+ unsigned int Backend_pending_count(VALUE self);
92
+ VALUE Backend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue);
93
+ VALUE Backend_wait_event(VALUE self, VALUE raise_on_exception);
94
+ VALUE Backend_wakeup(VALUE self);
95
+
95
96
  VALUE Thread_schedule_fiber(VALUE thread, VALUE fiber, VALUE value);
96
97
  VALUE Thread_schedule_fiber_with_priority(VALUE thread, VALUE fiber, VALUE value);
97
98
  VALUE Thread_switch_fiber(VALUE thread);
@@ -86,7 +86,7 @@ inline void capped_queue_block_push(Queue_t *queue) {
86
86
  if (queue->capacity > queue->values.count) Fiber_make_runnable(fiber, Qnil);
87
87
 
88
88
  ring_buffer_push(&queue->push_queue, fiber);
89
- switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
89
+ switchpoint_result = Backend_wait_event(backend, Qnil);
90
90
  ring_buffer_delete(&queue->push_queue, fiber);
91
91
 
92
92
  RAISE_IF_EXCEPTION(switchpoint_result);
@@ -131,7 +131,7 @@ VALUE Queue_shift(VALUE self) {
131
131
  if (queue->values.count) Fiber_make_runnable(fiber, Qnil);
132
132
 
133
133
  ring_buffer_push(&queue->shift_queue, fiber);
134
- VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
134
+ VALUE switchpoint_result = Backend_wait_event(backend, Qnil);
135
135
  ring_buffer_delete(&queue->shift_queue, fiber);
136
136
 
137
137
  RAISE_IF_EXCEPTION(switchpoint_result);
@@ -17,16 +17,6 @@ static VALUE Thread_setup_fiber_scheduling(VALUE self) {
17
17
  return self;
18
18
  }
19
19
 
20
- int Thread_fiber_ref_count(VALUE self) {
21
- VALUE backend = rb_ivar_get(self, ID_ivar_backend);
22
- return NUM2INT(__BACKEND__.ref_count(backend));
23
- }
24
-
25
- inline void Thread_fiber_reset_ref_count(VALUE self) {
26
- VALUE backend = rb_ivar_get(self, ID_ivar_backend);
27
- __BACKEND__.reset_ref_count(backend);
28
- }
29
-
30
20
  static VALUE SYM_scheduled_fibers;
31
21
  static VALUE SYM_pending_watchers;
32
22
 
@@ -39,7 +29,7 @@ static VALUE Thread_fiber_scheduling_stats(VALUE self) {
39
29
  long scheduled_count = Runqueue_len(runqueue);
40
30
  rb_hash_aset(stats, SYM_scheduled_fibers, INT2NUM(scheduled_count));
41
31
 
42
- pending_count = __BACKEND__.pending_count(backend);
32
+ pending_count = Backend_pending_count(backend);
43
33
  rb_hash_aset(stats, SYM_pending_watchers, INT2NUM(pending_count));
44
34
 
45
35
  return stats;
@@ -64,7 +54,7 @@ void schedule_fiber(VALUE self, VALUE fiber, VALUE value, int prioritize) {
64
54
  // happen, not knowing that it there's already a fiber ready to run in its
65
55
  // run queue.
66
56
  VALUE backend = rb_ivar_get(self,ID_ivar_backend);
67
- __BACKEND__.wakeup(backend);
57
+ Backend_wakeup(backend);
68
58
  }
69
59
  }
70
60
  }
@@ -84,25 +74,24 @@ VALUE Thread_switch_fiber(VALUE self) {
84
74
  VALUE runqueue = rb_ivar_get(self, ID_ivar_runqueue);
85
75
  runqueue_entry next;
86
76
  VALUE backend = rb_ivar_get(self, ID_ivar_backend);
87
- int ref_count;
88
- int backend_was_polled = 0;
77
+ unsigned int pending_count = Backend_pending_count(backend);
78
+ unsigned int backend_was_polled = 0;
89
79
 
90
80
  if (__tracing_enabled__ && (rb_ivar_get(current_fiber, ID_ivar_running) != Qfalse))
91
81
  TRACE(2, SYM_fiber_switchpoint, current_fiber);
92
82
 
93
- ref_count = __BACKEND__.ref_count(backend);
94
83
  while (1) {
95
84
  next = Runqueue_shift(runqueue);
96
85
  if (next.fiber != Qnil) {
97
- if (backend_was_polled == 0 && ref_count > 0) {
86
+ if (!backend_was_polled && pending_count) {
98
87
  // this prevents event starvation in case the run queue never empties
99
- __BACKEND__.poll(backend, Qtrue, current_fiber, runqueue);
88
+ Backend_poll(backend, Qtrue, current_fiber, runqueue);
100
89
  }
101
90
  break;
102
91
  }
103
- if (ref_count == 0) break;
92
+ if (pending_count == 0) break;
104
93
 
105
- __BACKEND__.poll(backend, Qnil, current_fiber, runqueue);
94
+ Backend_poll(backend, Qnil, current_fiber, runqueue);
106
95
  backend_was_polled = 1;
107
96
  }
108
97
 
@@ -118,20 +107,13 @@ VALUE Thread_switch_fiber(VALUE self) {
118
107
  next.value : FIBER_TRANSFER(next.fiber, next.value);
119
108
  }
120
109
 
121
- VALUE Thread_reset_fiber_scheduling(VALUE self) {
122
- VALUE queue = rb_ivar_get(self, ID_ivar_runqueue);
123
- Runqueue_clear(queue);
124
- Thread_fiber_reset_ref_count(self);
125
- return self;
126
- }
127
-
128
110
  VALUE Thread_fiber_schedule_and_wakeup(VALUE self, VALUE fiber, VALUE resume_obj) {
129
111
  VALUE backend = rb_ivar_get(self, ID_ivar_backend);
130
112
  if (fiber != Qnil) {
131
113
  Thread_schedule_fiber_with_priority(self, fiber, resume_obj);
132
114
  }
133
115
 
134
- if (__BACKEND__.wakeup(backend) == Qnil) {
116
+ if (Backend_wakeup(backend) == Qnil) {
135
117
  // we're not inside the ev_loop, so we just do a switchpoint
136
118
  Thread_switch_fiber(self);
137
119
  }
@@ -146,7 +128,6 @@ VALUE Thread_debug(VALUE self) {
146
128
 
147
129
  void Init_Thread() {
148
130
  rb_define_method(rb_cThread, "setup_fiber_scheduling", Thread_setup_fiber_scheduling, 0);
149
- rb_define_method(rb_cThread, "reset_fiber_scheduling", Thread_reset_fiber_scheduling, 0);
150
131
  rb_define_method(rb_cThread, "fiber_scheduling_stats", Thread_fiber_scheduling_stats, 0);
151
132
  rb_define_method(rb_cThread, "schedule_and_wakeup", Thread_fiber_schedule_and_wakeup, 2);
152
133
 
@@ -11,7 +11,7 @@ module ::PG
11
11
 
12
12
  def self.connect_async(conn)
13
13
  socket_io = conn.socket_io
14
- loop do
14
+ while true
15
15
  res = conn.connect_poll
16
16
  case res
17
17
  when PGRES_POLLING_FAILED then raise Error, conn.error_message
@@ -23,7 +23,7 @@ module ::PG
23
23
  end
24
24
 
25
25
  def self.connect_sync(conn)
26
- loop do
26
+ while true
27
27
  res = conn.connect_poll
28
28
  case res
29
29
  when PGRES_POLLING_FAILED
@@ -96,7 +96,7 @@ class ::PG::Connection
96
96
  def wait_for_notify(timeout = nil, &block)
97
97
  return move_on_after(timeout) { wait_for_notify(&block) } if timeout
98
98
 
99
- loop do
99
+ while true
100
100
  Thread.current.backend.wait_io(socket_io, false)
101
101
  consume_input
102
102
  notice = notifies
@@ -59,7 +59,15 @@ module Polyphony
59
59
  throttled_loop(rate: rate, interval: interval, &block)
60
60
  end
61
61
  else
62
- Fiber.current.spin(tag, caller) { loop(&block) }
62
+ spin_looped_block(tag, caller, block)
63
+ end
64
+ end
65
+
66
+ def spin_looped_block(tag, caller, block)
67
+ Fiber.current.spin(tag, caller) do
68
+ block.call while true
69
+ rescue LocalJumpError, StopIteration
70
+ # break called or StopIteration raised
63
71
  end
64
72
  end
65
73
 
@@ -133,8 +141,12 @@ module Polyphony
133
141
  if opts[:count]
134
142
  opts[:count].times { |_i| throttler.(&block) }
135
143
  else
136
- loop { throttler.(&block) }
144
+ while true
145
+ throttler.(&block)
146
+ end
137
147
  end
148
+ rescue LocalJumpError, StopIteration
149
+ # break called or StopIteration raised
138
150
  ensure
139
151
  throttler&.stop
140
152
  end
@@ -45,7 +45,9 @@ module Polyphony
45
45
  end
46
46
 
47
47
  def thread_loop
48
- loop { run_queued_task }
48
+ while true
49
+ run_queued_task
50
+ end
49
51
  end
50
52
 
51
53
  def run_queued_task
@@ -15,7 +15,7 @@ module Polyphony
15
15
  Thread.current.backend.sleep(delta) if delta > 0
16
16
  yield self
17
17
 
18
- loop do
18
+ while true
19
19
  @next_time += @min_dt
20
20
  break if @next_time > now
21
21
  end
@@ -34,9 +34,18 @@ module Polyphony
34
34
  schedule Polyphony::Cancel.new
35
35
  end
36
36
 
37
- def terminate
37
+ def graceful_shutdown=(graceful)
38
+ @graceful_shutdown = graceful
39
+ end
40
+
41
+ def graceful_shutdown?
42
+ @graceful_shutdown
43
+ end
44
+
45
+ def terminate(graceful = false)
38
46
  return if @running == false
39
47
 
48
+ @graceful_shutdown = graceful
40
49
  schedule Polyphony::Terminate.new
41
50
  end
42
51
 
@@ -66,7 +75,9 @@ module Polyphony
66
75
  @on_child_done = proc do |fiber, result|
67
76
  self << fiber unless result.is_a?(Exception)
68
77
  end
69
- loop { supervise_perform(opts) }
78
+ while true
79
+ supervise_perform(opts)
80
+ end
70
81
  rescue Polyphony::MoveOn
71
82
  # generated in #supervise_perform to stop supervisor
72
83
  ensure
@@ -210,11 +221,14 @@ module Polyphony
210
221
  @on_child_done&.(child_fiber, result)
211
222
  end
212
223
 
213
- def terminate_all_children
224
+ def terminate_all_children(graceful = false)
214
225
  return unless @children
215
226
 
216
227
  e = Polyphony::Terminate.new
217
- @children.each_key { |c| c.raise e }
228
+ @children.each_key do |c|
229
+ c.graceful_shutdown = true if graceful
230
+ c.raise e
231
+ end
218
232
  end
219
233
 
220
234
  def await_all_children
@@ -230,8 +244,8 @@ module Polyphony
230
244
  results.values
231
245
  end
232
246
 
233
- def shutdown_all_children
234
- terminate_all_children
247
+ def shutdown_all_children(graceful = false)
248
+ terminate_all_children(graceful)
235
249
  await_all_children
236
250
  end
237
251
  end
@@ -119,18 +119,11 @@ class ::IO
119
119
  end
120
120
 
121
121
  alias_method :orig_readpartial, :read
122
- def readpartial(len, str = nil)
123
- @read_buffer ||= +''
124
- result = Thread.current.backend.read(self, @read_buffer, len, false)
122
+ def readpartial(len, str = +'')
123
+ result = Thread.current.backend.read(self, str, len, false)
125
124
  raise EOFError unless result
126
125
 
127
- if str
128
- str << @read_buffer
129
- else
130
- str = @read_buffer
131
- end
132
- @read_buffer = +''
133
- str
126
+ result
134
127
  end
135
128
 
136
129
  alias_method :orig_write, :write
@@ -154,15 +147,16 @@ class ::IO
154
147
 
155
148
  @read_buffer ||= +''
156
149
 
157
- loop do
150
+ while true
158
151
  idx = @read_buffer.index(sep)
159
152
  return @read_buffer.slice!(0, idx + sep_size) if idx
160
153
 
161
- data = readpartial(8192)
154
+ data = readpartial(8192, +'')
155
+ return nil unless data
162
156
  @read_buffer << data
163
- rescue EOFError
164
- return nil
165
157
  end
158
+ rescue EOFError
159
+ return nil
166
160
  end
167
161
 
168
162
  # def print(*args)
@@ -25,7 +25,7 @@ class ::OpenSSL::SSL::SSLSocket
25
25
 
26
26
  alias_method :orig_accept, :accept
27
27
  def accept
28
- loop do
28
+ while true
29
29
  result = accept_nonblock(exception: false)
30
30
  case result
31
31
  when :wait_readable then Thread.current.backend.wait_io(io, false)
@@ -37,14 +37,14 @@ class ::OpenSSL::SSL::SSLSocket
37
37
  end
38
38
 
39
39
  def accept_loop
40
- loop do
40
+ while true
41
41
  yield accept
42
42
  end
43
43
  end
44
44
 
45
45
  alias_method :orig_sysread, :sysread
46
46
  def sysread(maxlen, buf = +'')
47
- loop do
47
+ while true
48
48
  case (result = read_nonblock(maxlen, buf, exception: false))
49
49
  when :wait_readable then Thread.current.backend.wait_io(io, false)
50
50
  when :wait_writable then Thread.current.backend.wait_io(io, true)
@@ -55,7 +55,7 @@ class ::OpenSSL::SSL::SSLSocket
55
55
 
56
56
  alias_method :orig_syswrite, :syswrite
57
57
  def syswrite(buf)
58
- loop do
58
+ while true
59
59
  case (result = write_nonblock(buf, exception: false))
60
60
  when :wait_readable then Thread.current.backend.wait_io(io, false)
61
61
  when :wait_writable then Thread.current.backend.wait_io(io, true)
@@ -33,7 +33,7 @@ class ::Socket
33
33
 
34
34
  def recvfrom(maxlen, flags = 0)
35
35
  @read_buffer ||= +''
36
- loop do
36
+ while true
37
37
  result = recvfrom_nonblock(maxlen, flags, @read_buffer, **NO_EXCEPTION)
38
38
  case result
39
39
  when nil then raise IOError
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.47.5.1'
4
+ VERSION = '0.48.0'
5
5
  end
@@ -6,7 +6,7 @@ Gem::Specification.new do |s|
6
6
  s.licenses = ['MIT']
7
7
  s.summary = 'Fine grained concurrency for Ruby'
8
8
  s.author = 'Sharon Rosner'
9
- s.email = 'ciconia@gmail.com'
9
+ s.email = 'sharon@noteflakes.com'
10
10
  s.files = `git ls-files`.split
11
11
  s.homepage = 'https://digital-fabric.github.io/polyphony'
12
12
  s.metadata = {
@@ -4,6 +4,7 @@ require 'bundler/setup'
4
4
 
5
5
  require_relative './coverage' if ENV['COVERAGE']
6
6
 
7
+ require 'httparty'
7
8
  require 'polyphony'
8
9
 
9
10
  require 'fileutils'
@@ -105,7 +105,7 @@ class BackendTest < MiniTest::Test
105
105
 
106
106
  clients = []
107
107
  server_fiber = spin do
108
- @backend.accept_loop(server) { |c| clients << c }
108
+ @backend.accept_loop(server, TCPSocket) { |c| clients << c }
109
109
  end
110
110
 
111
111
  c1 = TCPSocket.new('127.0.0.1', 1234)
@@ -1038,3 +1038,67 @@ class RestartTest < MiniTest::Test
1038
1038
  assert_equal [f, 'foo', 'bar', :done, f2, 'baz', 42, :done], buffer
1039
1039
  end
1040
1040
  end
1041
+
1042
+ class GracefulTerminationTest < MiniTest::Test
1043
+ def test_graceful_termination
1044
+ buffer = []
1045
+ f = spin do
1046
+ buffer << 1
1047
+ snooze
1048
+ buffer << 2
1049
+ sleep 3
1050
+ buffer << 3
1051
+ ensure
1052
+ buffer << 4 if Fiber.current.graceful_shutdown?
1053
+ end
1054
+
1055
+ 3.times { snooze }
1056
+ f.terminate(false)
1057
+ f.await
1058
+ assert_equal [1, 2], buffer
1059
+
1060
+ buffer = []
1061
+ f = spin do
1062
+ buffer << 1
1063
+ snooze
1064
+ buffer << 2
1065
+ sleep 3
1066
+ buffer << 3
1067
+ ensure
1068
+ buffer << 4 if Fiber.current.graceful_shutdown?
1069
+ end
1070
+
1071
+ 3.times { snooze }
1072
+ f.terminate(true)
1073
+ f.await
1074
+ assert_equal [1, 2, 4], buffer
1075
+ end
1076
+
1077
+ def test_graceful_child_shutdown
1078
+ buffer = []
1079
+ f0 = spin do
1080
+ f1 = spin do
1081
+ sleep
1082
+ ensure
1083
+ buffer << 1 if Fiber.current.graceful_shutdown?
1084
+ end
1085
+
1086
+ f2 = spin do
1087
+ sleep
1088
+ ensure
1089
+ buffer << 2 if Fiber.current.graceful_shutdown?
1090
+ end
1091
+
1092
+ sleep
1093
+ ensure
1094
+ Fiber.current.terminate_all_children(true) if Fiber.current.graceful_shutdown?
1095
+ Fiber.current.await_all_children
1096
+ end
1097
+
1098
+ 3.times { snooze }
1099
+ f0.terminate(true)
1100
+ f0.await
1101
+
1102
+ assert_equal [1, 2], buffer
1103
+ end
1104
+ end
@@ -307,6 +307,36 @@ class SpinLoopTest < MiniTest::Test
307
307
  f.stop
308
308
  assert_in_range 1..3, counter
309
309
  end
310
+
311
+ def test_spin_loop_break
312
+ i = 0
313
+ f = spin_loop do
314
+ i += 1
315
+ snooze
316
+ break if i >= 5
317
+ end
318
+ f.await
319
+ assert_equal 5, i
320
+
321
+ i = 0
322
+ f = spin_loop do
323
+ i += 1
324
+ snooze
325
+ raise StopIteration if i >= 5
326
+ end
327
+ f.await
328
+ assert_equal 5, i
329
+ end
330
+
331
+ def test_throttled_spin_loop_break
332
+ i = 0
333
+ f = spin_loop(rate: 100) do
334
+ i += 1
335
+ break if i >= 5
336
+ end
337
+ f.await
338
+ assert_equal 5, i
339
+ end
310
340
  end
311
341
 
312
342
  class SpinScopeTest < MiniTest::Test
@@ -92,6 +92,32 @@ class IOTest < MiniTest::Test
92
92
  assert_raises(EOFError) { i.readpartial(1) }
93
93
  end
94
94
 
95
+ def test_gets
96
+ i, o = IO.pipe
97
+
98
+ buf = []
99
+ f = spin do
100
+ while (l = i.gets)
101
+ buf << l
102
+ end
103
+ end
104
+
105
+ snooze
106
+ assert_equal [], buf
107
+
108
+ o << 'fab'
109
+ snooze
110
+ assert_equal [], buf
111
+
112
+ o << "ulous\n"
113
+ 10.times { snooze }
114
+ assert_equal ["fabulous\n"], buf
115
+
116
+ o.close
117
+ f.await
118
+ assert_equal ["fabulous\n"], buf
119
+ end
120
+
95
121
  def test_getc
96
122
  i, o = IO.pipe
97
123
 
@@ -60,7 +60,6 @@ class SocketTest < MiniTest::Test
60
60
  end
61
61
 
62
62
  class HTTPClientTest < MiniTest::Test
63
- require 'httparty'
64
63
  require 'json'
65
64
 
66
65
  def test_http
@@ -20,7 +20,7 @@ class SuperviseTest < MiniTest::Test
20
20
 
21
21
  f2 << 'bar'
22
22
  f2.await
23
- assert_equal :waiting, p.state
23
+ assert_equal :runnable, p.state
24
24
  snooze
25
25
 
26
26
  assert_equal :dead, p.state
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.47.5.1
4
+ version: 0.48.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-20 00:00:00.000000000 Z
11
+ date: 2021-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler
@@ -269,7 +269,7 @@ dependencies:
269
269
  - !ruby/object:Gem::Version
270
270
  version: 0.3.0
271
271
  description:
272
- email: ciconia@gmail.com
272
+ email: sharon@noteflakes.com
273
273
  executables: []
274
274
  extensions:
275
275
  - ext/polyphony/extconf.rb
@@ -383,6 +383,7 @@ files:
383
383
  - examples/io/raw.rb
384
384
  - examples/io/reline.rb
385
385
  - examples/io/system.rb
386
+ - examples/io/tcp_proxy.rb
386
387
  - examples/io/tcpserver.rb
387
388
  - examples/io/tcpsocket.rb
388
389
  - examples/io/tunnel.rb
@@ -391,6 +392,8 @@ files:
391
392
  - examples/performance/fiber_resume.rb
392
393
  - examples/performance/fiber_transfer.rb
393
394
  - examples/performance/fs_read.rb
395
+ - examples/performance/line_splitting.rb
396
+ - examples/performance/loop.rb
394
397
  - examples/performance/mem-usage.rb
395
398
  - examples/performance/messaging.rb
396
399
  - examples/performance/multi_snooze.rb
@@ -433,7 +436,6 @@ files:
433
436
  - ext/liburing/setup.c
434
437
  - ext/liburing/syscall.c
435
438
  - ext/liburing/syscall.h
436
- - ext/polyphony/backend.h
437
439
  - ext/polyphony/backend_common.h
438
440
  - ext/polyphony/backend_io_uring.c
439
441
  - ext/polyphony/backend_io_uring_context.c
@@ -1,26 +0,0 @@
1
- #ifndef BACKEND_H
2
- #define BACKEND_H
3
-
4
- #include "ruby.h"
5
-
6
- typedef VALUE (* backend_pending_count_t)(VALUE self);
7
- typedef VALUE (*backend_poll_t)(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue);
8
- typedef VALUE (* backend_ref_t)(VALUE self);
9
- typedef int (* backend_ref_count_t)(VALUE self);
10
- typedef void (* backend_reset_ref_count_t)(VALUE self);
11
- typedef VALUE (* backend_unref_t)(VALUE self);
12
- typedef VALUE (* backend_wait_event_t)(VALUE self, VALUE raise_on_exception);
13
- typedef VALUE (* backend_wakeup_t)(VALUE self);
14
-
15
- typedef struct backend_interface {
16
- backend_pending_count_t pending_count;
17
- backend_poll_t poll;
18
- backend_ref_t ref;
19
- backend_ref_count_t ref_count;
20
- backend_reset_ref_count_t reset_ref_count;
21
- backend_unref_t unref;
22
- backend_wait_event_t wait_event;
23
- backend_wakeup_t wakeup;
24
- } backend_interface_t;
25
-
26
- #endif /* BACKEND_H */