polyphony 0.99 → 0.99.1

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.
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);