polyphony 0.99 → 0.99.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/FUNDING.yml +1 -1
  3. data/.rubocop.yml +3 -3
  4. data/.yardopts +30 -0
  5. data/CHANGELOG.md +4 -0
  6. data/LICENSE +1 -1
  7. data/README.md +63 -29
  8. data/Rakefile +1 -5
  9. data/TODO.md +0 -4
  10. data/docs/{main-concepts/concurrency.md → concurrency.md} +2 -9
  11. data/docs/{main-concepts/design-principles.md → design-principles.md} +3 -9
  12. data/docs/{main-concepts/exception-handling.md → exception-handling.md} +2 -9
  13. data/docs/{main-concepts/extending.md → extending.md} +2 -9
  14. data/docs/faq.md +3 -16
  15. data/docs/{main-concepts/fiber-scheduling.md → fiber-scheduling.md} +1 -9
  16. data/docs/link_rewriter.rb +16 -0
  17. data/docs/{getting-started/overview.md → overview.md} +1 -30
  18. data/docs/{getting-started/tutorial.md → tutorial.md} +3 -28
  19. data/docs/{_posts/2020-07-26-polyphony-0.44.md → whats-new.md} +3 -1
  20. data/examples/adapters/redis_client.rb +3 -2
  21. data/examples/io/echo_server.rb +1 -1
  22. data/examples/io/echo_server_plain_ruby.rb +26 -0
  23. data/ext/polyphony/backend_io_uring.c +154 -9
  24. data/ext/polyphony/backend_io_uring_context.c +21 -12
  25. data/ext/polyphony/backend_io_uring_context.h +12 -7
  26. data/ext/polyphony/backend_libev.c +1 -1
  27. data/ext/polyphony/extconf.rb +24 -8
  28. data/ext/polyphony/fiber.c +79 -2
  29. data/ext/polyphony/io_extensions.c +53 -0
  30. data/ext/polyphony/pipe.c +42 -2
  31. data/ext/polyphony/polyphony.c +345 -31
  32. data/ext/polyphony/polyphony.h +9 -2
  33. data/ext/polyphony/queue.c +181 -0
  34. data/ext/polyphony/ring_buffer.c +0 -1
  35. data/ext/polyphony/runqueue.c +8 -1
  36. data/ext/polyphony/runqueue_ring_buffer.c +13 -0
  37. data/ext/polyphony/runqueue_ring_buffer.h +2 -1
  38. data/ext/polyphony/socket_extensions.c +6 -0
  39. data/ext/polyphony/thread.c +34 -2
  40. data/lib/polyphony/adapters/process.rb +11 -1
  41. data/lib/polyphony/adapters/sequel.rb +1 -1
  42. data/lib/polyphony/core/channel.rb +2 -0
  43. data/lib/polyphony/core/debug.rb +1 -1
  44. data/lib/polyphony/core/global_api.rb +25 -24
  45. data/lib/polyphony/core/resource_pool.rb +7 -6
  46. data/lib/polyphony/core/sync.rb +2 -2
  47. data/lib/polyphony/core/thread_pool.rb +3 -3
  48. data/lib/polyphony/core/timer.rb +8 -8
  49. data/lib/polyphony/extensions/exception.rb +2 -0
  50. data/lib/polyphony/extensions/fiber.rb +15 -13
  51. data/lib/polyphony/extensions/io.rb +127 -5
  52. data/lib/polyphony/extensions/kernel.rb +20 -2
  53. data/lib/polyphony/extensions/openssl.rb +100 -11
  54. data/lib/polyphony/extensions/pipe.rb +103 -7
  55. data/lib/polyphony/extensions/process.rb +13 -1
  56. data/lib/polyphony/extensions/socket.rb +93 -27
  57. data/lib/polyphony/extensions/thread.rb +9 -1
  58. data/lib/polyphony/extensions/timeout.rb +1 -1
  59. data/lib/polyphony/version.rb +2 -1
  60. data/lib/polyphony.rb +27 -7
  61. data/polyphony.gemspec +1 -8
  62. data/test/stress.rb +1 -1
  63. data/test/test_global_api.rb +45 -7
  64. data/test/test_socket.rb +96 -0
  65. data/test/test_timer.rb +5 -5
  66. metadata +17 -40
  67. data/docs/_config.yml +0 -64
  68. data/docs/_includes/head.html +0 -40
  69. data/docs/_includes/title.html +0 -1
  70. data/docs/_sass/custom/custom.scss +0 -10
  71. data/docs/_sass/overrides.scss +0 -0
  72. data/docs/api-reference/exception.md +0 -31
  73. data/docs/api-reference/fiber.md +0 -425
  74. data/docs/api-reference/index.md +0 -9
  75. data/docs/api-reference/io.md +0 -36
  76. data/docs/api-reference/object.md +0 -99
  77. data/docs/api-reference/polyphony-baseexception.md +0 -33
  78. data/docs/api-reference/polyphony-cancel.md +0 -26
  79. data/docs/api-reference/polyphony-moveon.md +0 -24
  80. data/docs/api-reference/polyphony-net.md +0 -20
  81. data/docs/api-reference/polyphony-process.md +0 -28
  82. data/docs/api-reference/polyphony-resourcepool.md +0 -59
  83. data/docs/api-reference/polyphony-restart.md +0 -18
  84. data/docs/api-reference/polyphony-terminate.md +0 -18
  85. data/docs/api-reference/polyphony-threadpool.md +0 -67
  86. data/docs/api-reference/polyphony-throttler.md +0 -77
  87. data/docs/api-reference/polyphony.md +0 -36
  88. data/docs/api-reference/thread.md +0 -88
  89. data/docs/favicon.ico +0 -0
  90. data/docs/getting-started/index.md +0 -10
  91. data/docs/getting-started/installing.md +0 -34
  92. /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
  93. /data/{docs → assets}/polyphony-logo.png +0 -0
  94. /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
data/ext/polyphony/pipe.c CHANGED
@@ -36,7 +36,15 @@ static VALUE Pipe_allocate(VALUE klass) {
36
36
  #define GetPipe(obj, pipe) \
37
37
  TypedData_Get_Struct((obj), Pipe_t, &Pipe_type, (pipe))
38
38
 
39
- static VALUE Pipe_initialize(int argc, VALUE *argv, VALUE self) {
39
+ /* call-seq:
40
+ * Pipe.new -> pipe
41
+ *
42
+ * Creates a new pipe.
43
+ *
44
+ * @return [void]
45
+ */
46
+
47
+ static VALUE Pipe_initialize(VALUE self) {
40
48
  Pipe_t *pipe_struct;
41
49
  GetPipe(self, pipe_struct);
42
50
 
@@ -72,12 +80,28 @@ int Pipe_get_fd(VALUE self, int write_mode) {
72
80
  return pipe->fds[write_mode ? 1 : 0];
73
81
  }
74
82
 
83
+ /* call-seq:
84
+ * pipe.closed? -> bool
85
+ *
86
+ * Returns true if the pipe is closed.
87
+ *
88
+ * @return [boolean]
89
+ */
90
+
75
91
  VALUE Pipe_closed_p(VALUE self) {
76
92
  Pipe_t *pipe;
77
93
  GetPipe(self, pipe);
78
94
  return pipe->w_closed ? Qtrue : Qfalse;
79
95
  }
80
96
 
97
+ /* call-seq:
98
+ * pipe.close -> pipe
99
+ *
100
+ * Closes the pipe.
101
+ *
102
+ * @return [Pipe] self
103
+ */
104
+
81
105
  VALUE Pipe_close(VALUE self) {
82
106
  Pipe_t *pipe;
83
107
  GetPipe(self, pipe);
@@ -89,6 +113,15 @@ VALUE Pipe_close(VALUE self) {
89
113
  return self;
90
114
  }
91
115
 
116
+ /* call-seq:
117
+ * Pipe.fds -> [r, w]
118
+ *
119
+ * Returns an array containing the read and write fds for the pipe,
120
+ * respectively.
121
+ *
122
+ * @return [Array<Integer>]
123
+ */
124
+
92
125
  VALUE Pipe_fds(VALUE self) {
93
126
  Pipe_t *pipe;
94
127
  GetPipe(self, pipe);
@@ -98,11 +131,18 @@ VALUE Pipe_fds(VALUE self) {
98
131
 
99
132
  void Init_Pipe(void) {
100
133
  cPipe = rb_define_class_under(mPolyphony, "Pipe", rb_cObject);
134
+
135
+ /*
136
+ * Document-class: Polyphony::Pipe::ClosedPipeError
137
+ *
138
+ * An exception raised when trying to read or write to a closed pipe.
139
+ */
140
+
101
141
  cClosedPipeError = rb_define_class_under(cPipe, "ClosedPipeError", rb_eRuntimeError);
102
142
 
103
143
  rb_define_alloc_func(cPipe, Pipe_allocate);
104
144
 
105
- rb_define_method(cPipe, "initialize", Pipe_initialize, -1);
145
+ rb_define_method(cPipe, "initialize", Pipe_initialize, 0);
106
146
  rb_define_method(cPipe, "closed?", Pipe_closed_p, 0);
107
147
  rb_define_method(cPipe, "close", Pipe_close, 0);
108
148
  rb_define_method(cPipe, "fds", Pipe_fds, 0);
@@ -11,6 +11,7 @@ ID ID_inspect;
11
11
  ID ID_invoke;
12
12
  ID ID_ivar_blocking_mode;
13
13
  ID ID_ivar_io;
14
+ ID ID_ivar_multishot_accept_queue;
14
15
  ID ID_ivar_parked;
15
16
  ID ID_ivar_runnable;
16
17
  ID ID_ivar_running;
@@ -26,10 +27,33 @@ ID ID_R;
26
27
  ID ID_W;
27
28
  ID ID_RW;
28
29
 
30
+ /* call-seq:
31
+ * snooze
32
+ * Polyphony.snooze
33
+ *
34
+ * Switches to the next fiber in the current thread's runqueue after adding the
35
+ * current fiber to the runqueue. This lets other fibers run, letting the
36
+ * current fiber eventually continue its work. This call is useful when
37
+ * performing long-running calculations in order to keep the program responsive.
38
+ *
39
+ * @return [void]
40
+ */
41
+
29
42
  VALUE Polyphony_snooze(VALUE self) {
30
43
  return Backend_snooze(BACKEND());
31
44
  }
32
45
 
46
+ /* call-seq:
47
+ * suspend
48
+ * Polyphony.suspend
49
+ *
50
+ * Switches to the next fiber in the current thread's runqueue without
51
+ * rescheduling the current fiber. This is useful if the current fiber does not
52
+ * need to continue or will be scheduled by other means eventually.
53
+ *
54
+ * @return [void]
55
+ */
56
+
33
57
  static VALUE Polyphony_suspend(VALUE self) {
34
58
  VALUE ret = Thread_switch_fiber(rb_thread_current());
35
59
 
@@ -38,102 +62,373 @@ static VALUE Polyphony_suspend(VALUE self) {
38
62
  return ret;
39
63
  }
40
64
 
65
+ /* call-seq:
66
+ * Polyphony.backend_accept(server_socket, socket_class) -> socket
67
+ *
68
+ * Accepts an incoming connection on the given server socket, returning an
69
+ * instance of the given socket class.
70
+ *
71
+ * @param server_socket [Socket] socket to accept on
72
+ * @param socket_class [Class] class of the socket to instantiate for the accepted connection
73
+ *
74
+ * @return [Socket] accepted connection
75
+ */
76
+
41
77
  VALUE Polyphony_backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
42
78
  return Backend_accept(BACKEND(), server_socket, socket_class);
43
79
  }
44
80
 
81
+ /* call-seq:
82
+ * Polyphony.backend_accept_loop(server_socket, socket_class) { |socket| ... }
83
+ *
84
+ * Runs an infinite loop accepting connections on the given server socket,
85
+ * returning an instance of the given socket class.
86
+ *
87
+ * @param server_socket [Socket] socket to accept on
88
+ * @param socket_class [Class] class of the socket to instantiate for the accepted connection
89
+ * @yield [Socket] accepted connection passed to the given block
90
+ * @return [void]
91
+ */
92
+
45
93
  VALUE Polyphony_backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
46
94
  return Backend_accept_loop(BACKEND(), server_socket, socket_class);
47
95
  }
48
96
 
97
+ #ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
98
+ /* call-seq:
99
+ * Polyphony.backend_multishot_accept(server_socket) { ... }
100
+ *
101
+ * Starts a multishot accept operation on the given server socket. This API is
102
+ * available only for the io_uring backend.
103
+ *
104
+ * @param server_socket [Socket] socket to accept on
105
+ * @return [void]
106
+ */
107
+
108
+ VALUE Polyphony_backend_multishot_accept(VALUE self, VALUE server_socket) {
109
+ return Backend_multishot_accept(BACKEND(), server_socket);
110
+ }
111
+ #endif
112
+
113
+
114
+ /* call-seq:
115
+ * Polyphony.backend_connect(socket, addr, port) -> socket
116
+ *
117
+ * Connects the given socket to the given address and port.
118
+ *
119
+ * @param io [Socket] socket to connect
120
+ * @param addr [String] address to connect to
121
+ * @param port [Integer] port to connect to
122
+ *
123
+ * @return [Socket] accepted connection
124
+ */
125
+
49
126
  VALUE Polyphony_backend_connect(VALUE self, VALUE io, VALUE addr, VALUE port) {
50
127
  return Backend_connect(BACKEND(), io, addr, port);
51
128
  }
52
129
 
130
+ /* call-seq:
131
+ * Polyphony.backend_feed_loop(io, receiver, method)
132
+ *
133
+ * Runs a feed loop, reading data from the given io, feeding it to the receiver
134
+ * with the given method, and passing the receiver's output to the given block.
135
+ * The loop terminates when EOF is encountered.
136
+ *
137
+ * @param io [IO] io to read from
138
+ * @param receiver [any] an object receiving the data
139
+ * @param method [Symbol] method used to feed the data to the receiver
140
+ * @yield [any] data passed to the given block
141
+ *
142
+ * @return [void]
143
+ */
144
+
53
145
  VALUE Polyphony_backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
54
146
  return Backend_feed_loop(BACKEND(), io, receiver, method);
55
147
  }
56
148
 
149
+ /* call-seq:
150
+ * Polyphony.backend_read(io, buffer, length, to_eof, pos) -> buffer
151
+ *
152
+ * Reads from the given io.
153
+ *
154
+ * @param io [IO] io to read from
155
+ * @param buffer [String, nil] buffer to read into
156
+ * @param length [Integer] maximum bytes to read
157
+ * @param to_eof [boolean] whether to read to EOF
158
+ * @param pos [Integer] Position in the buffer to read into
159
+ *
160
+ * @return [String] buffer
161
+ */
162
+
57
163
  VALUE Polyphony_backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eof, VALUE pos) {
58
164
  return Backend_read(BACKEND(), io, buffer, length, to_eof, pos);
59
165
  }
60
166
 
167
+ /* call-seq:
168
+ * Polyphony.backend_read_loop(io, max_len)
169
+ *
170
+ * Performs an infinite loop reading data from the given io. The loop terminates
171
+ * when EOF is encountered.
172
+ *
173
+ * @param io [IO] io to read from
174
+ * @param maxlen [Integer] maximum bytes to read
175
+ *
176
+ * @return [void]
177
+ */
178
+
61
179
  VALUE Polyphony_backend_read_loop(VALUE self, VALUE io, VALUE maxlen) {
62
180
  return Backend_read_loop(BACKEND(), io, maxlen);
63
181
  }
64
182
 
183
+ /* call-seq:
184
+ * Polyphony.backend_recv(io, buffer, length, pos) -> buffer
185
+ *
186
+ * Receives data on the given io.
187
+ *
188
+ * @param io [Socket] io to receive on
189
+ * @param buffer [String, nil] buffer to read into
190
+ * @param length [Integer] maximum bytes to read
191
+ * @param pos [Integer] Position in the buffer to read into
192
+ *
193
+ * @return [String] buffer
194
+ */
195
+
65
196
  VALUE Polyphony_backend_recv(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE pos) {
66
197
  return Backend_recv(BACKEND(), io, buffer, length, pos);
67
198
  }
68
199
 
69
- VALUE Polyphony_backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE pos, VALUE flags, VALUE maxcontrollen, VALUE opts) {
70
- return Backend_recvmsg(BACKEND(), io, buffer, maxlen, pos, flags, maxcontrollen, opts);
200
+ /* call-seq:
201
+ * Polyphony.backend_recvmsg(socket, buffer, maxlen, pos, flags, maxcontrollen, opts) -> buffer
202
+ *
203
+ * Receives a message on the given socket.
204
+ *
205
+ * @param socket [UDPSocket] io to receive on
206
+ * @param buffer [String, nil] buffer to read into
207
+ * @param maxlen [Integer] maximum bytes to read
208
+ * @param pos [Integer] Position in the buffer to read into
209
+ * @param flags [Integer] Flags
210
+ * @param maxcontrollen [Integer] Maximum control bytes
211
+ * @param opts [Hash] Options
212
+ *
213
+ * @return [String] buffer
214
+ */
215
+
216
+ VALUE Polyphony_backend_recvmsg(VALUE self, VALUE socket, VALUE buffer, VALUE maxlen, VALUE pos, VALUE flags, VALUE maxcontrollen, VALUE opts) {
217
+ return Backend_recvmsg(BACKEND(), socket, buffer, maxlen, pos, flags, maxcontrollen, opts);
71
218
  }
72
219
 
73
- VALUE Polyphony_backend_recv_loop(VALUE self, VALUE io, VALUE maxlen) {
74
- return Backend_recv_loop(BACKEND(), io, maxlen);
220
+ /* call-seq:
221
+ * Polyphony.backend_recv_loop(socket, max_len)
222
+ *
223
+ * Performs an infinite loop receiving data on the given socket. The loop terminates
224
+ * when the socket is closed.
225
+ *
226
+ * @param socket [Socket] socket to receive on
227
+ * @param maxlen [Integer] maximum bytes to read
228
+ *
229
+ * @return [void]
230
+ */
231
+
232
+ VALUE Polyphony_backend_recv_loop(VALUE self, VALUE socket, VALUE maxlen) {
233
+ return Backend_recv_loop(BACKEND(), socket, maxlen);
75
234
  }
76
235
 
77
- VALUE Polyphony_backend_recv_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method) {
78
- return Backend_recv_feed_loop(BACKEND(), io, receiver, method);
236
+ /* call-seq:
237
+ * Polyphony.backend_recv_feed_loop(socket, receiver, method)
238
+ *
239
+ * Runs a feed loop, receiving data on the given socket, feeding it to the receiver
240
+ * with the given method, and passing the receiver's output to the given block.
241
+ * The loop terminates when EOF is encountered.
242
+ *
243
+ * @param socket [Socket] socket to receive on
244
+ * @param receiver [any] an object receiving the data
245
+ * @param method [Symbol] method used to feed the data to the receiver
246
+ * @yield [any] data passed to the given block
247
+ *
248
+ * @return [void]
249
+ */
250
+
251
+ VALUE Polyphony_backend_recv_feed_loop(VALUE self, VALUE socket, VALUE receiver, VALUE method) {
252
+ return Backend_recv_feed_loop(BACKEND(), socket, receiver, method);
79
253
  }
80
254
 
81
- VALUE Polyphony_backend_send(VALUE self, VALUE io, VALUE msg, VALUE flags) {
82
- return Backend_send(BACKEND(), io, msg, flags);
255
+ /* call-seq:
256
+ * Polyphony.backend_send(socket, msg, flags) -> bytes_sent
257
+ *
258
+ * Sends data on the given socket, returning the number of bytes sent.
259
+ *
260
+ * @param socket [Socket] socket to read from
261
+ * @param msg [String] data to be sent
262
+ * @param flags [Integer] Flags
263
+ *
264
+ * @return [Integer] number of bytes sent
265
+ */
266
+
267
+ VALUE Polyphony_backend_send(VALUE self, VALUE socket, VALUE msg, VALUE flags) {
268
+ return Backend_send(BACKEND(), socket, msg, flags);
83
269
  }
84
270
 
85
- VALUE Polyphony_backend_sendmsg(VALUE self, VALUE io, VALUE msg, VALUE flags, VALUE dest_sockaddr, VALUE controls) {
86
- return Backend_sendmsg(BACKEND(), io, msg, flags, dest_sockaddr, controls);
271
+ /* call-seq:
272
+ * Polyphony.backend_sendmsg(socket, msg, flags, dest_sockaddr, controls) -> bytes_sent
273
+ *
274
+ * Sends data on the given socket, returning the number of bytes sent.
275
+ *
276
+ * @param socket [Socket] socket to read from
277
+ * @param msg [String] data to be sent
278
+ * @param flags [Integer] Flags
279
+ * @param dest_sockaddr [any] Destination address
280
+ * @param controls [any] Control data
281
+ * @return [Integer] number of bytes sent
282
+ */
283
+
284
+ VALUE Polyphony_backend_sendmsg(VALUE self, VALUE socket, VALUE msg, VALUE flags, VALUE dest_sockaddr, VALUE controls) {
285
+ return Backend_sendmsg(BACKEND(), socket, msg, flags, dest_sockaddr, controls);
87
286
  }
88
287
 
89
- VALUE Polyphony_backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
90
- return Backend_sendv(BACKEND(), io, ary, flags);
288
+ /* call-seq:
289
+ * Polyphony.backend_sendv(socket, ary, flags) -> bytes_sent
290
+ *
291
+ * Sends multiple strings on the given socket, returning the number of bytes sent.
292
+ *
293
+ * @param socket [Socket] socket to read from
294
+ * @param ary [Array<String>] data to be sent
295
+ * @param flags [Integer] Flags
296
+ * @return [Integer] number of bytes sent
297
+ */
298
+
299
+ VALUE Polyphony_backend_sendv(VALUE self, VALUE socket, VALUE ary, VALUE flags) {
300
+ return Backend_sendv(BACKEND(), socket, ary, flags);
91
301
  }
92
302
 
303
+ /* call-seq:
304
+ * Polyphony.backend_sleep(duration)
305
+ *
306
+ * Sleeps for the given duration, yielding execution to other fibers.
307
+ *
308
+ * @param duration [Number] duration in seconds
309
+ * @return [void]
310
+ */
311
+
93
312
  VALUE Polyphony_backend_sleep(VALUE self, VALUE duration) {
94
313
  return Backend_sleep(BACKEND(), duration);
95
314
  }
96
315
 
316
+ /* call-seq:
317
+ * Polyphony.backend_splice(src, dest, maxlen) -> bytes_spliced
318
+ *
319
+ * Splices data from the given source to the given destination, returning the
320
+ * number of bytes spliced.
321
+ *
322
+ * @param src [IO] source
323
+ * @param dest [IO] destination
324
+ * @param maxlen [Integer] Maximum bytes to splice
325
+ * @return [Integer] number of bytes spliced
326
+ */
327
+
97
328
  VALUE Polyphony_backend_splice(VALUE self, VALUE src, VALUE dest, VALUE maxlen) {
98
329
  return Backend_splice(BACKEND(), src, dest, maxlen);
99
330
  }
100
331
 
101
332
  #ifdef POLYPHONY_BACKEND_LIBURING
333
+ /* @!visibility private */
334
+
102
335
  VALUE Polyphony_backend_double_splice(VALUE self, VALUE src, VALUE dest) {
103
336
  return Backend_double_splice(BACKEND(), src, dest);
104
337
  }
105
338
  #endif
106
339
 
107
340
  #ifdef POLYPHONY_LINUX
341
+ /* @!visibility private */
342
+
108
343
  VALUE Polyphony_backend_tee(VALUE self, VALUE src, VALUE dest, VALUE chunksize) {
109
344
  return Backend_tee(BACKEND(), src, dest, chunksize);
110
345
  }
111
346
  #endif
112
347
 
348
+ /* call-seq:
349
+ * Polyphony.backend_timeout(duration) { ... }
350
+ * Polyphony.backend_timeout(duration, exception_class) { ... }
351
+ *
352
+ * Runs the given block, raising an exception if the block has not finished
353
+ * running before a timeout has elapsed, using the given duration. If an
354
+ * exception class is not given, a TimeoutError is raised.
355
+ *
356
+ */
357
+
113
358
  VALUE Polyphony_backend_timeout(int argc,VALUE *argv, VALUE self) {
114
359
  return Backend_timeout(argc, argv, BACKEND());
115
360
  }
116
361
 
362
+ /* call-seq:
363
+ * Polyphony.backend_timer_loop(interval) { ... }
364
+ *
365
+ * Runs an infinite loop that calls the given block at the specified time interval.
366
+ *
367
+ * @param interval [Number] interval in seconds
368
+ * @yield [] code to run
369
+ * @return [void]
370
+ */
371
+
117
372
  VALUE Polyphony_backend_timer_loop(VALUE self, VALUE interval) {
118
373
  return Backend_timer_loop(BACKEND(), interval);
119
374
  }
120
375
 
376
+ /* call-seq:
377
+ * Polyphony.backend_wait_event(raise)
378
+ *
379
+ * For for the current fiber to be rescheduled, resuming the fiber with its
380
+ * resumed value. If raise is true and the resumed value is an exception, an
381
+ * exception will be raised.
382
+ *
383
+ * @param raise [boolean]
384
+ * @return [any] resumed value
385
+ */
386
+
121
387
  VALUE Polyphony_backend_wait_event(VALUE self, VALUE raise) {
122
388
  return Backend_wait_event(BACKEND(), raise);
123
389
  }
124
390
 
391
+ /* call-seq:
392
+ * Polyphony.backend_wait_io(io, read_or_write)
393
+ *
394
+ * Waits for the given IO to be readable or writeable, according to the
395
+ * read_or_write parameter.
396
+ *
397
+ * @param io [IO]
398
+ * @param write [boolean] false for read, true for write
399
+ * @return [void]
400
+ */
401
+
125
402
  VALUE Polyphony_backend_wait_io(VALUE self, VALUE io, VALUE write) {
126
403
  return Backend_wait_io(BACKEND(), io, write);
127
404
  }
128
405
 
406
+ /* call-seq:
407
+ * Polyphony.backend_wait_pid(pid) -> exit code
408
+ *
409
+ * Waits for the given process to terminate, returning its exit code.
410
+ *
411
+ * @param pid [Integer] pid
412
+ * @return [Integer] exit code
413
+ */
414
+
129
415
  VALUE Polyphony_backend_waitpid(VALUE self, VALUE pid) {
130
416
  return Backend_waitpid(BACKEND(), pid);
131
417
  }
132
418
 
419
+ /* call-seq:
420
+ * Polyphony.backend_write(io, data, ...) -> bytes_written
421
+ *
422
+ * Writes one or more strings to the given io, returning the total number of
423
+ * bytes written.
424
+ */
425
+
133
426
  VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
134
427
  return Backend_write_m(argc, argv, BACKEND());
135
428
  }
136
429
 
430
+ /* @!visibility private */
431
+
137
432
  VALUE Polyphony_with_raw_buffer(VALUE self, VALUE size) {
138
433
  struct buffer_spec buffer_spec;
139
434
  buffer_spec.len = FIX2INT(size);
@@ -146,6 +441,8 @@ VALUE Polyphony_with_raw_buffer(VALUE self, VALUE size) {
146
441
  return return_value;
147
442
  }
148
443
 
444
+ /* @!visibility private */
445
+
149
446
  VALUE Polyphony_raw_buffer_get(int argc, VALUE *argv, VALUE self) {
150
447
  VALUE buf = Qnil;
151
448
  VALUE len = Qnil;
@@ -158,6 +455,8 @@ VALUE Polyphony_raw_buffer_get(int argc, VALUE *argv, VALUE self) {
158
455
  return rb_utf8_str_new((char *)buffer_spec->ptr, length);
159
456
  }
160
457
 
458
+ /* @!visibility private */
459
+
161
460
  VALUE Polyphony_raw_buffer_set(VALUE self, VALUE buffer, VALUE str) {
162
461
  struct buffer_spec *buffer_spec = FIX2PTR(buffer);
163
462
  int len = RSTRING_LEN(str);
@@ -169,6 +468,8 @@ VALUE Polyphony_raw_buffer_set(VALUE self, VALUE buffer, VALUE str) {
169
468
  return self;
170
469
  }
171
470
 
471
+ /* @!visibility private */
472
+
172
473
  VALUE Polyphony_raw_buffer_size(VALUE self, VALUE buffer) {
173
474
  struct buffer_spec *buffer_spec = FIX2PTR(buffer);
174
475
  return INT2FIX(buffer_spec->len);
@@ -186,6 +487,12 @@ void Init_Polyphony(void) {
186
487
  rb_define_singleton_method(mPolyphony, "backend_accept_loop", Polyphony_backend_accept_loop, 2);
187
488
  rb_define_singleton_method(mPolyphony, "backend_connect", Polyphony_backend_connect, 3);
188
489
  rb_define_singleton_method(mPolyphony, "backend_feed_loop", Polyphony_backend_feed_loop, 3);
490
+
491
+ #ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
492
+ rb_define_singleton_method(mPolyphony, "backend_multishot_accept", Polyphony_backend_multishot_accept, 1);
493
+ #endif
494
+
495
+
189
496
  rb_define_singleton_method(mPolyphony, "backend_read", Polyphony_backend_read, 5);
190
497
  rb_define_singleton_method(mPolyphony, "backend_read_loop", Polyphony_backend_read_loop, 2);
191
498
  rb_define_singleton_method(mPolyphony, "backend_recv", Polyphony_backend_recv, 4);
@@ -223,25 +530,32 @@ void Init_Polyphony(void) {
223
530
  rb_define_global_function("snooze", Polyphony_snooze, 0);
224
531
  rb_define_global_function("suspend", Polyphony_suspend, 0);
225
532
 
533
+ /*
534
+ * Document-class: Polyphony::TimeoutException
535
+ *
536
+ * An exception raised on timeout.
537
+ */
538
+
226
539
  cTimeoutException = rb_define_class_under(mPolyphony, "TimeoutException", rb_eException);
227
540
 
228
- ID_call = rb_intern("call");
229
- ID_caller = rb_intern("caller");
230
- ID_clear = rb_intern("clear");
231
- ID_each = rb_intern("each");
232
- ID_inspect = rb_intern("inspect");
233
- ID_invoke = rb_intern("invoke");
234
- ID_ivar_blocking_mode = rb_intern("@blocking_mode");
235
- ID_ivar_io = rb_intern("@io");
236
- ID_ivar_parked = rb_intern("@parked");
237
- ID_ivar_runnable = rb_intern("@runnable");
238
- ID_ivar_running = rb_intern("@running");
239
- ID_ivar_thread = rb_intern("@thread");
240
- ID_new = rb_intern("new");
241
- ID_raise = rb_intern("raise");
242
- ID_signal = rb_intern("signal");
243
- ID_size = rb_intern("size");
244
- ID_switch_fiber = rb_intern("switch_fiber");
245
- ID_to_s = rb_intern("to_s");
246
- ID_transfer = rb_intern("transfer");
541
+ ID_call = rb_intern("call");
542
+ ID_caller = rb_intern("caller");
543
+ ID_clear = rb_intern("clear");
544
+ ID_each = rb_intern("each");
545
+ ID_inspect = rb_intern("inspect");
546
+ ID_invoke = rb_intern("invoke");
547
+ ID_ivar_blocking_mode = rb_intern("@blocking_mode");
548
+ ID_ivar_io = rb_intern("@io");
549
+ ID_ivar_multishot_accept_queue = rb_intern("@multishot_accept_queue");
550
+ ID_ivar_parked = rb_intern("@parked");
551
+ ID_ivar_runnable = rb_intern("@runnable");
552
+ ID_ivar_running = rb_intern("@running");
553
+ ID_ivar_thread = rb_intern("@thread");
554
+ ID_new = rb_intern("new");
555
+ ID_raise = rb_intern("raise");
556
+ ID_signal = rb_intern("signal");
557
+ ID_size = rb_intern("size");
558
+ ID_switch_fiber = rb_intern("switch_fiber");
559
+ ID_to_s = rb_intern("to_s");
560
+ ID_transfer = rb_intern("transfer");
247
561
  }
@@ -14,8 +14,9 @@
14
14
  // exceptions
15
15
  #define TEST_EXCEPTION(ret) (rb_obj_is_kind_of(ret, rb_eException) == Qtrue)
16
16
  #define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
17
- #define RAISE_IF_EXCEPTION(ret) if (rb_obj_is_kind_of(ret, rb_eException) == Qtrue) { RAISE_EXCEPTION(ret); }
18
- #define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
17
+ #define IS_EXCEPTION(o) (rb_obj_is_kind_of(o, rb_eException) == Qtrue)
18
+ #define RAISE_IF_EXCEPTION(o) if (IS_EXCEPTION(o)) { RAISE_EXCEPTION(o); }
19
+ #define RAISE_IF_NOT_NIL(o) if (o != Qnil) { RAISE_EXCEPTION(o); }
19
20
 
20
21
  // Fiber#transfer
21
22
  #if HAVE_RB_FIBER_TRANSFER
@@ -44,6 +45,7 @@ extern ID ID_invoke;
44
45
  extern ID ID_ivar_backend;
45
46
  extern ID ID_ivar_blocking_mode;
46
47
  extern ID ID_ivar_io;
48
+ extern ID ID_ivar_multishot_accept_queue;
47
49
  extern ID ID_ivar_parked;
48
50
  extern ID ID_ivar_runnable;
49
51
  extern ID ID_ivar_running;
@@ -97,6 +99,11 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class);
97
99
  VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class);
98
100
  VALUE Backend_connect(VALUE self, VALUE io, VALUE addr, VALUE port);
99
101
  VALUE Backend_feed_loop(VALUE self, VALUE io, VALUE receiver, VALUE method);
102
+
103
+ #ifdef HAVE_IO_URING_PREP_MULTISHOT_ACCEPT
104
+ VALUE Backend_multishot_accept(VALUE self, VALUE io);
105
+ #endif
106
+
100
107
  VALUE Backend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof, VALUE pos);
101
108
  VALUE Backend_read_loop(VALUE self, VALUE io, VALUE maxlen);
102
109
  VALUE Backend_recv(VALUE self, VALUE io, VALUE str, VALUE length, VALUE pos);