polyphony 0.98 → 0.99.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (267) 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 +11 -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/examples/io/https_server_sni_2.rb +14 -8
  24. data/ext/polyphony/backend_io_uring.c +154 -9
  25. data/ext/polyphony/backend_io_uring_context.c +21 -12
  26. data/ext/polyphony/backend_io_uring_context.h +12 -7
  27. data/ext/polyphony/backend_libev.c +1 -1
  28. data/ext/polyphony/extconf.rb +25 -8
  29. data/ext/polyphony/fiber.c +79 -2
  30. data/ext/polyphony/io_extensions.c +53 -0
  31. data/ext/polyphony/libev.h +0 -2
  32. data/ext/polyphony/pipe.c +42 -2
  33. data/ext/polyphony/polyphony.c +345 -31
  34. data/ext/polyphony/polyphony.h +9 -2
  35. data/ext/polyphony/queue.c +181 -0
  36. data/ext/polyphony/ring_buffer.c +0 -1
  37. data/ext/polyphony/runqueue.c +8 -1
  38. data/ext/polyphony/runqueue_ring_buffer.c +13 -0
  39. data/ext/polyphony/runqueue_ring_buffer.h +2 -1
  40. data/ext/polyphony/socket_extensions.c +6 -0
  41. data/ext/polyphony/thread.c +34 -2
  42. data/lib/polyphony/adapters/process.rb +11 -1
  43. data/lib/polyphony/adapters/sequel.rb +1 -1
  44. data/lib/polyphony/core/channel.rb +2 -0
  45. data/lib/polyphony/core/debug.rb +1 -1
  46. data/lib/polyphony/core/global_api.rb +25 -24
  47. data/lib/polyphony/core/resource_pool.rb +7 -6
  48. data/lib/polyphony/core/sync.rb +55 -2
  49. data/lib/polyphony/core/thread_pool.rb +3 -3
  50. data/lib/polyphony/core/timer.rb +8 -8
  51. data/lib/polyphony/extensions/exception.rb +2 -0
  52. data/lib/polyphony/extensions/fiber.rb +15 -13
  53. data/lib/polyphony/extensions/io.rb +161 -16
  54. data/lib/polyphony/extensions/kernel.rb +20 -2
  55. data/lib/polyphony/extensions/openssl.rb +101 -12
  56. data/lib/polyphony/extensions/pipe.rb +103 -7
  57. data/lib/polyphony/extensions/process.rb +13 -1
  58. data/lib/polyphony/extensions/socket.rb +93 -27
  59. data/lib/polyphony/extensions/thread.rb +9 -1
  60. data/lib/polyphony/extensions/timeout.rb +1 -1
  61. data/lib/polyphony/version.rb +2 -1
  62. data/lib/polyphony.rb +27 -7
  63. data/polyphony.gemspec +1 -8
  64. data/test/stress.rb +1 -1
  65. data/test/test_global_api.rb +45 -7
  66. data/test/test_io.rb +6 -7
  67. data/test/test_socket.rb +157 -0
  68. data/test/test_sync.rb +42 -1
  69. data/test/test_timer.rb +5 -5
  70. data/vendor/liburing/.github/workflows/build.yml +7 -16
  71. data/vendor/liburing/.gitignore +5 -0
  72. data/vendor/liburing/CHANGELOG +23 -1
  73. data/vendor/liburing/Makefile +4 -3
  74. data/vendor/liburing/Makefile.common +1 -0
  75. data/vendor/liburing/README +48 -0
  76. data/vendor/liburing/configure +76 -6
  77. data/vendor/liburing/debian/changelog +11 -0
  78. data/vendor/liburing/debian/control +7 -16
  79. data/vendor/liburing/debian/liburing-dev.manpages +3 -6
  80. data/vendor/liburing/debian/liburing2.install +1 -0
  81. data/vendor/liburing/debian/liburing2.symbols +56 -0
  82. data/vendor/liburing/debian/rules +15 -68
  83. data/vendor/liburing/examples/Makefile +4 -0
  84. data/vendor/liburing/examples/io_uring-close-test.c +123 -0
  85. data/vendor/liburing/examples/io_uring-udp.c +1 -1
  86. data/vendor/liburing/examples/send-zerocopy.c +315 -56
  87. data/vendor/liburing/examples/ucontext-cp.c +2 -17
  88. data/vendor/liburing/liburing-ffi.pc.in +12 -0
  89. data/vendor/liburing/liburing.pc.in +1 -1
  90. data/vendor/liburing/liburing.spec +1 -1
  91. data/vendor/liburing/make-debs.sh +3 -3
  92. data/vendor/liburing/man/IO_URING_CHECK_VERSION.3 +1 -0
  93. data/vendor/liburing/man/IO_URING_VERSION_MAJOR.3 +1 -0
  94. data/vendor/liburing/man/IO_URING_VERSION_MINOR.3 +1 -0
  95. data/vendor/liburing/man/io_uring_buf_ring_add.3 +6 -6
  96. data/vendor/liburing/man/io_uring_check_version.3 +72 -0
  97. data/vendor/liburing/man/io_uring_close_ring_fd.3 +43 -0
  98. data/vendor/liburing/man/io_uring_major_version.3 +1 -0
  99. data/vendor/liburing/man/io_uring_minor_version.3 +1 -0
  100. data/vendor/liburing/man/io_uring_prep_accept.3 +1 -1
  101. data/vendor/liburing/man/io_uring_prep_fgetxattr.3 +1 -0
  102. data/vendor/liburing/man/io_uring_prep_fsetxattr.3 +1 -0
  103. data/vendor/liburing/man/io_uring_prep_getxattr.3 +61 -0
  104. data/vendor/liburing/man/io_uring_prep_link_timeout.3 +94 -0
  105. data/vendor/liburing/man/io_uring_prep_msg_ring.3 +22 -2
  106. data/vendor/liburing/man/io_uring_prep_msg_ring_cqe_flags.3 +1 -0
  107. data/vendor/liburing/man/io_uring_prep_poll_add.3 +1 -1
  108. data/vendor/liburing/man/io_uring_prep_provide_buffers.3 +18 -9
  109. data/vendor/liburing/man/io_uring_prep_readv.3 +3 -3
  110. data/vendor/liburing/man/io_uring_prep_readv2.3 +3 -3
  111. data/vendor/liburing/man/io_uring_prep_recv.3 +5 -5
  112. data/vendor/liburing/man/io_uring_prep_recvmsg.3 +4 -4
  113. data/vendor/liburing/man/io_uring_prep_send.3 +9 -0
  114. data/vendor/liburing/man/io_uring_prep_send_set_addr.3 +38 -0
  115. data/vendor/liburing/man/io_uring_prep_send_zc.3 +39 -7
  116. data/vendor/liburing/man/io_uring_prep_send_zc_fixed.3 +1 -0
  117. data/vendor/liburing/man/io_uring_prep_sendmsg.3 +20 -0
  118. data/vendor/liburing/man/io_uring_prep_sendmsg_zc.3 +1 -0
  119. data/vendor/liburing/man/io_uring_prep_setxattr.3 +64 -0
  120. data/vendor/liburing/man/io_uring_prep_splice.3 +40 -0
  121. data/vendor/liburing/man/io_uring_prep_writev.3 +2 -2
  122. data/vendor/liburing/man/io_uring_prep_writev2.3 +2 -2
  123. data/vendor/liburing/man/io_uring_recvmsg_out.3 +13 -9
  124. data/vendor/liburing/man/io_uring_register.2 +15 -9
  125. data/vendor/liburing/man/io_uring_register_buf_ring.3 +4 -4
  126. data/vendor/liburing/man/io_uring_register_buffers.3 +49 -6
  127. data/vendor/liburing/man/io_uring_register_buffers_sparse.3 +1 -0
  128. data/vendor/liburing/man/io_uring_register_buffers_tags.3 +1 -0
  129. data/vendor/liburing/man/io_uring_register_buffers_update_tag.3 +1 -0
  130. data/vendor/liburing/man/io_uring_register_files.3 +60 -5
  131. data/vendor/liburing/man/io_uring_register_files_tags.3 +1 -0
  132. data/vendor/liburing/man/io_uring_register_files_update.3 +1 -0
  133. data/vendor/liburing/man/io_uring_register_files_update_tag.3 +1 -0
  134. data/vendor/liburing/man/io_uring_setup.2 +31 -2
  135. data/vendor/liburing/man/io_uring_wait_cqe_timeout.3 +1 -1
  136. data/vendor/liburing/src/Makefile +25 -3
  137. data/vendor/liburing/src/ffi.c +15 -0
  138. data/vendor/liburing/src/include/liburing/io_uring.h +30 -7
  139. data/vendor/liburing/src/include/liburing.h +190 -148
  140. data/vendor/liburing/src/int_flags.h +1 -0
  141. data/vendor/liburing/src/lib.h +5 -16
  142. data/vendor/liburing/src/liburing-ffi.map +172 -0
  143. data/vendor/liburing/src/liburing.map +11 -0
  144. data/vendor/liburing/src/nolibc.c +9 -2
  145. data/vendor/liburing/src/queue.c +2 -2
  146. data/vendor/liburing/src/register.c +66 -96
  147. data/vendor/liburing/src/setup.c +5 -4
  148. data/vendor/liburing/src/version.c +21 -0
  149. data/vendor/liburing/test/232c93d07b74.c +3 -3
  150. data/vendor/liburing/test/35fa71a030ca.c +3 -3
  151. data/vendor/liburing/test/500f9fbadef8.c +2 -0
  152. data/vendor/liburing/test/917257daa0fe.c +1 -1
  153. data/vendor/liburing/test/Makefile +27 -7
  154. data/vendor/liburing/test/a0908ae19763.c +2 -2
  155. data/vendor/liburing/test/a4c0b3decb33.c +2 -2
  156. data/vendor/liburing/test/accept-link.c +4 -4
  157. data/vendor/liburing/test/accept-reuse.c +5 -7
  158. data/vendor/liburing/test/accept.c +34 -31
  159. data/vendor/liburing/test/b19062a56726.c +1 -1
  160. data/vendor/liburing/test/buf-ring.c +58 -4
  161. data/vendor/liburing/test/ce593a6c480a.c +2 -2
  162. data/vendor/liburing/test/close-opath.c +2 -1
  163. data/vendor/liburing/test/connect.c +8 -0
  164. data/vendor/liburing/test/cq-overflow.c +14 -8
  165. data/vendor/liburing/test/d4ae271dfaae.c +1 -1
  166. data/vendor/liburing/test/defer-taskrun.c +64 -9
  167. data/vendor/liburing/test/defer.c +1 -1
  168. data/vendor/liburing/test/double-poll-crash.c +3 -3
  169. data/vendor/liburing/test/eeed8b54e0df.c +8 -3
  170. data/vendor/liburing/test/eploop.c +74 -0
  171. data/vendor/liburing/test/eventfd-ring.c +1 -1
  172. data/vendor/liburing/test/eventfd.c +1 -1
  173. data/vendor/liburing/test/evloop.c +73 -0
  174. data/vendor/liburing/test/exit-no-cleanup.c +1 -1
  175. data/vendor/liburing/test/fadvise.c +1 -1
  176. data/vendor/liburing/test/fc2a85cb02ef.c +3 -3
  177. data/vendor/liburing/test/fd-pass.c +35 -16
  178. data/vendor/liburing/test/file-register.c +61 -0
  179. data/vendor/liburing/test/file-verify.c +2 -2
  180. data/vendor/liburing/test/files-exit-hang-timeout.c +2 -2
  181. data/vendor/liburing/test/fixed-link.c +1 -1
  182. data/vendor/liburing/test/fsnotify.c +118 -0
  183. data/vendor/liburing/test/hardlink.c +1 -1
  184. data/vendor/liburing/test/helpers.c +54 -2
  185. data/vendor/liburing/test/helpers.h +4 -0
  186. data/vendor/liburing/test/io-cancel.c +3 -1
  187. data/vendor/liburing/test/io_uring_passthrough.c +39 -8
  188. data/vendor/liburing/test/io_uring_setup.c +3 -80
  189. data/vendor/liburing/test/iopoll-overflow.c +118 -0
  190. data/vendor/liburing/test/iopoll.c +90 -4
  191. data/vendor/liburing/test/lfs-openat-write.c +7 -9
  192. data/vendor/liburing/test/lfs-openat.c +6 -8
  193. data/vendor/liburing/test/link_drain.c +31 -5
  194. data/vendor/liburing/test/madvise.c +1 -1
  195. data/vendor/liburing/test/msg-ring-flags.c +192 -0
  196. data/vendor/liburing/test/msg-ring-overflow.c +159 -0
  197. data/vendor/liburing/test/msg-ring.c +173 -13
  198. data/vendor/liburing/test/multicqes_drain.c +22 -19
  199. data/vendor/liburing/test/nvme.h +4 -3
  200. data/vendor/liburing/test/pipe-bug.c +95 -0
  201. data/vendor/liburing/test/poll-link.c +3 -3
  202. data/vendor/liburing/test/poll-many.c +41 -19
  203. data/vendor/liburing/test/poll-mshot-overflow.c +105 -2
  204. data/vendor/liburing/test/poll-race-mshot.c +292 -0
  205. data/vendor/liburing/test/poll-race.c +105 -0
  206. data/vendor/liburing/test/poll.c +244 -26
  207. data/vendor/liburing/test/pollfree.c +5 -5
  208. data/vendor/liburing/test/read-before-exit.c +20 -3
  209. data/vendor/liburing/test/read-write.c +2 -0
  210. data/vendor/liburing/test/recv-multishot.c +96 -3
  211. data/vendor/liburing/test/reg-reg-ring.c +90 -0
  212. data/vendor/liburing/test/rename.c +1 -1
  213. data/vendor/liburing/test/ring-leak.c +0 -1
  214. data/vendor/liburing/test/ring-leak2.c +1 -1
  215. data/vendor/liburing/test/ringbuf-read.c +10 -6
  216. data/vendor/liburing/test/send-zerocopy.c +273 -103
  217. data/vendor/liburing/test/send_recv.c +7 -4
  218. data/vendor/liburing/test/sendmsg_fs_cve.c +2 -2
  219. data/vendor/liburing/test/single-issuer.c +7 -9
  220. data/vendor/liburing/test/skip-cqe.c +3 -4
  221. data/vendor/liburing/test/socket.c +0 -1
  222. data/vendor/liburing/test/sq-poll-dup.c +10 -3
  223. data/vendor/liburing/test/sq-poll-kthread.c +1 -1
  224. data/vendor/liburing/test/sq-poll-share.c +3 -2
  225. data/vendor/liburing/test/sqpoll-cancel-hang.c +17 -6
  226. data/vendor/liburing/test/sqpoll-disable-exit.c +4 -4
  227. data/vendor/liburing/test/symlink.c +2 -1
  228. data/vendor/liburing/test/test.h +2 -1
  229. data/vendor/liburing/test/timeout-new.c +11 -7
  230. data/vendor/liburing/test/timeout.c +1 -2
  231. data/vendor/liburing/test/unlink.c +1 -1
  232. data/vendor/liburing/test/version.c +25 -0
  233. data/vendor/liburing/test/wakeup-hang.c +1 -1
  234. data/vendor/liburing/test/xattr.c +8 -4
  235. metadata +57 -44
  236. data/docs/_config.yml +0 -64
  237. data/docs/_includes/head.html +0 -40
  238. data/docs/_includes/title.html +0 -1
  239. data/docs/_sass/custom/custom.scss +0 -10
  240. data/docs/_sass/overrides.scss +0 -0
  241. data/docs/api-reference/exception.md +0 -31
  242. data/docs/api-reference/fiber.md +0 -425
  243. data/docs/api-reference/index.md +0 -9
  244. data/docs/api-reference/io.md +0 -36
  245. data/docs/api-reference/object.md +0 -99
  246. data/docs/api-reference/polyphony-baseexception.md +0 -33
  247. data/docs/api-reference/polyphony-cancel.md +0 -26
  248. data/docs/api-reference/polyphony-moveon.md +0 -24
  249. data/docs/api-reference/polyphony-net.md +0 -20
  250. data/docs/api-reference/polyphony-process.md +0 -28
  251. data/docs/api-reference/polyphony-resourcepool.md +0 -59
  252. data/docs/api-reference/polyphony-restart.md +0 -18
  253. data/docs/api-reference/polyphony-terminate.md +0 -18
  254. data/docs/api-reference/polyphony-threadpool.md +0 -67
  255. data/docs/api-reference/polyphony-throttler.md +0 -77
  256. data/docs/api-reference/polyphony.md +0 -36
  257. data/docs/api-reference/thread.md +0 -88
  258. data/docs/favicon.ico +0 -0
  259. data/docs/getting-started/index.md +0 -10
  260. data/docs/getting-started/installing.md +0 -34
  261. data/vendor/liburing/debian/compat +0 -1
  262. data/vendor/liburing/debian/liburing1-udeb.install +0 -1
  263. data/vendor/liburing/debian/liburing1.install +0 -1
  264. data/vendor/liburing/debian/liburing1.symbols +0 -32
  265. /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
  266. /data/{docs → assets}/polyphony-logo.png +0 -0
  267. /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
@@ -6,7 +6,7 @@ require_relative './io'
6
6
  require_relative '../core/thread_pool'
7
7
 
8
8
  # BasicSocket extensions
9
- class BasicSocket
9
+ class BasicSocket < ::IO
10
10
  # Returns `:backend_recv`. This method is used to tell parsers which read
11
11
  # method to use for this object.
12
12
  #
@@ -15,13 +15,17 @@ class BasicSocket
15
15
  :backend_recv
16
16
  end
17
17
 
18
+ # Returns `:backend_send`. This method is used to tell various libraries which
19
+ # write method to use for this object.
20
+ #
21
+ # @return [:backend_send] use Polyphony.backend_send to send DATA
18
22
  def __write_method__
19
23
  :backend_send
20
24
  end
21
25
  end
22
26
 
23
27
  # Socket extensions # TODO: rewrite in C
24
- class ::Socket
28
+ class ::Socket < ::BasicSocket
25
29
 
26
30
  # Accepts an incoming connection.
27
31
 
@@ -35,12 +39,13 @@ class ::Socket
35
39
  #
36
40
  # Accepts incoming connections in an infinite loop.
37
41
  #
38
- # @param &block [Proc] handler block
42
+ # @yield [Socket] block receiving accepted sockets
39
43
  # @return [void]
40
44
  def accept_loop(&block)
41
45
  Polyphony.backend_accept_loop(self, TCPSocket, &block)
42
46
  end
43
47
 
48
+ # @!visibility private
44
49
  NO_EXCEPTION = { exception: false }.freeze
45
50
 
46
51
  # Connects to the given address
@@ -53,6 +58,7 @@ class ::Socket
53
58
  self
54
59
  end
55
60
 
61
+ # @!visibility private
56
62
  alias_method :orig_read, :read
57
63
 
58
64
  # call-seq:
@@ -122,7 +128,7 @@ class ::Socket
122
128
  # will be passed to the given block.
123
129
  #
124
130
  # @param maxlen [Integer] maximum bytes to receive
125
- # @param &block [Proc] handler block
131
+ # @yield [String] handler block
126
132
  # @return [void]
127
133
  def recv_loop(maxlen = 8192, &block)
128
134
  Polyphony.backend_recv_loop(self, maxlen, &block)
@@ -149,13 +155,17 @@ class ::Socket
149
155
  #
150
156
  # @param receiver [any] receiver object
151
157
  # @param method [Symbol] method to call
152
- # @param &block [Proc] block to handle result of method call to receiver
158
+ # @yield [any] block to handle result of method call to receiver
153
159
  # @return [void]
154
160
  def feed_loop(receiver, method = :call, &block)
155
161
  Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
156
162
  end
157
163
 
158
- # :no-doc:
164
+ # Reimplements #recvfrom.
165
+ #
166
+ # @param maxlen [Integer] maximum bytes to receive
167
+ # @param flags [Integer] optional flags
168
+ # @return [String] received data
159
169
  def recvfrom(maxlen, flags = 0)
160
170
  buf = +''
161
171
  while true
@@ -198,6 +208,7 @@ class ::Socket
198
208
  result
199
209
  end
200
210
 
211
+ # @!visibility private
201
212
  ZERO_LINGER = [0, 0].pack('ii').freeze
202
213
 
203
214
  # Sets the linger option to 0.
@@ -233,7 +244,8 @@ class ::Socket
233
244
  end
234
245
 
235
246
  class << self
236
- alias_method :orig_getaddrinfo, :getaddrinfo
247
+ # @!visibility private
248
+ alias_method :orig_getaddrinfo, :getaddrinfo
237
249
 
238
250
  # Resolves the given addr using a worker thread from the default thread
239
251
  # pool.
@@ -246,9 +258,11 @@ class ::Socket
246
258
  end
247
259
 
248
260
  # Overide stock TCPSocket code by encapsulating a Socket instance
249
- class ::TCPSocket
261
+ class ::TCPSocket < ::IPSocket
262
+ # @!visibility private
250
263
  NO_EXCEPTION = { exception: false }.freeze
251
264
 
265
+ # @!visibility private
252
266
  attr_reader :io
253
267
 
254
268
  class << self
@@ -275,6 +289,7 @@ class ::TCPSocket
275
289
  @io.connect(addr)
276
290
  end
277
291
 
292
+ # @!visibility private
278
293
  alias_method :orig_close, :close
279
294
 
280
295
  # Closes the socket.
@@ -285,6 +300,7 @@ class ::TCPSocket
285
300
  self
286
301
  end
287
302
 
303
+ # @!visibility private
288
304
  alias_method :orig_setsockopt, :setsockopt
289
305
 
290
306
  # Calls `setsockopt` with the given arguments.
@@ -295,6 +311,7 @@ class ::TCPSocket
295
311
  self
296
312
  end
297
313
 
314
+ # @!visibility private
298
315
  alias_method :orig_closed?, :closed?
299
316
 
300
317
  # Returns true if the socket is closed.
@@ -336,6 +353,7 @@ class ::TCPSocket
336
353
  self
337
354
  end
338
355
 
356
+ # @!visibility private
339
357
  alias_method :orig_read, :read
340
358
 
341
359
  # call-seq:
@@ -405,7 +423,7 @@ class ::TCPSocket
405
423
  # will be passed to the given block.
406
424
  #
407
425
  # @param maxlen [Integer] maximum bytes to receive
408
- # @param &block [Proc] handler block
426
+ # @yield [String] handler block
409
427
  # @return [void]
410
428
  def recv_loop(maxlen = 8192, &block)
411
429
  Polyphony.backend_recv_loop(self, maxlen, &block)
@@ -432,7 +450,7 @@ class ::TCPSocket
432
450
  #
433
451
  # @param receiver [any] receiver object
434
452
  # @param method [Symbol] method to call
435
- # @param &block [Proc] block to handle result of method call to receiver
453
+ # @yield [any] block to handle result of method call to receiver
436
454
  # @return [void]
437
455
  def feed_loop(receiver, method = :call, &block)
438
456
  Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
@@ -460,8 +478,8 @@ class ::TCPSocket
460
478
  # @param buf_pos [Number] buffer position to read into
461
479
  # @param raise_on_eof [bool] whether to raise an exception on `EOF`
462
480
  # @return [String, nil] buffer used for reading or nil on `EOF`
463
- def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
464
- result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
481
+ def readpartial(maxlen, buf = +'', buf_pos = 0, raise_on_eof = true)
482
+ result = Polyphony.backend_recv(self, buf, maxlen, buf_pos)
465
483
  raise EOFError if !result && raise_on_eof
466
484
  result
467
485
  end
@@ -476,8 +494,8 @@ class ::TCPSocket
476
494
  # @param buf [String, nil] read buffer
477
495
  # @param exception [bool] whether to raise an exception if not ready for reading
478
496
  # @return [String, :wait_readable] read buffer
479
- def read_nonblock(len, buf = nil, exception: true)
480
- @io.read_nonblock(len, buf, exception: exception)
497
+ def read_nonblock(maxlen, buf = nil, exception: true)
498
+ @io.read_nonblock(maxlen, buf, exception: exception)
481
499
  end
482
500
 
483
501
  # Performs a non-blocking to the socket. If the socket is not ready for
@@ -494,7 +512,7 @@ class ::TCPSocket
494
512
  end
495
513
 
496
514
  # TCPServer extensions
497
- class ::TCPServer
515
+ class ::TCPServer < ::TCPSocket
498
516
 
499
517
  # Initializes the TCP server socket.
500
518
  #
@@ -503,10 +521,12 @@ class ::TCPServer
503
521
  def initialize(hostname = nil, port = 0)
504
522
  addr = Addrinfo.tcp(hostname, port)
505
523
  @io = Socket.new addr.afamily, Socket::SOCK_STREAM
524
+ @io.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
506
525
  @io.bind(addr)
507
526
  @io.listen(0)
508
527
  end
509
528
 
529
+ # @!visibility private
510
530
  alias_method :orig_accept, :accept
511
531
 
512
532
  # Accepts an incoming connection.
@@ -516,17 +536,33 @@ class ::TCPServer
516
536
  Polyphony.backend_accept(@io, TCPSocket)
517
537
  end
518
538
 
539
+ if Polyphony.instance_methods(false).include?(:backend_multishot_accept)
540
+ # Starts a multishot accept operation (only available with io_uring
541
+ # backend). Example usage:
542
+ #
543
+ # server.multishot_accept do
544
+ # server.accept_loop { |c| handle_connection(c) }
545
+ # end
546
+ #
547
+ # @yield [TCPSocket] code block
548
+ # @return [any] return value of code block
549
+ def multishot_accept(&block)
550
+ Polyphony.backend_multishot_accept(@io, &block)
551
+ end
552
+ end
553
+
519
554
  # call-seq:
520
555
  # socket.accept_loop { |conn| ... }
521
556
  #
522
557
  # Accepts incoming connections in an infinite loop.
523
558
  #
524
- # @param &block [Proc] handler block
559
+ # @yield [TCPSocket] handler block
525
560
  # @return [void]
526
561
  def accept_loop(&block)
527
562
  Polyphony.backend_accept_loop(@io, TCPSocket, &block)
528
563
  end
529
564
 
565
+ # @!visibility private
530
566
  alias_method :orig_close, :close
531
567
 
532
568
  # Closes the server socket.
@@ -538,7 +574,9 @@ class ::TCPServer
538
574
  end
539
575
  end
540
576
 
541
- class ::UNIXServer
577
+ # UNIXServer extensions
578
+ class ::UNIXServer < ::UNIXSocket
579
+ # @!visibility private
542
580
  alias_method :orig_accept, :accept
543
581
 
544
582
  # Accepts an incoming connection.
@@ -553,14 +591,16 @@ class ::UNIXServer
553
591
  #
554
592
  # Accepts incoming connections in an infinite loop.
555
593
  #
556
- # @param &block [Proc] handler block
594
+ # @yield [UNIXSocket] handler block
557
595
  # @return [void]
558
596
  def accept_loop(&block)
559
597
  Polyphony.backend_accept_loop(self, UNIXSocket, &block)
560
598
  end
561
599
  end
562
600
 
563
- class ::UNIXSocket
601
+ # UNIXSocket extensions
602
+ class ::UNIXSocket < ::BasicSocket
603
+ # @!visibility private
564
604
  alias_method :orig_read, :read
565
605
 
566
606
  # call-seq:
@@ -630,7 +670,7 @@ class ::UNIXSocket
630
670
  # will be passed to the given block.
631
671
  #
632
672
  # @param maxlen [Integer] maximum bytes to receive
633
- # @param &block [Proc] handler block
673
+ # @yield [String] handler block
634
674
  # @return [void]
635
675
  def recv_loop(maxlen = 8192, &block)
636
676
  Polyphony.backend_recv_loop(self, maxlen, &block)
@@ -657,7 +697,7 @@ class ::UNIXSocket
657
697
  #
658
698
  # @param receiver [any] receiver object
659
699
  # @param method [Symbol] method to call
660
- # @param &block [Proc] block to handle result of method call to receiver
700
+ # @yield [any] block to handle result of method call to receiver
661
701
  # @return [void]
662
702
  def feed_loop(receiver, method = :call, &block)
663
703
  Polyphony.backend_recv_feed_loop(self, receiver, method, &block)
@@ -675,7 +715,7 @@ class ::UNIXSocket
675
715
  # Sends one or more strings on the socket. The strings are guaranteed to be
676
716
  # written as a single blocking operation.
677
717
  #
678
- # @param *args [Array<String>] string buffers to write
718
+ # @param args [Array<String>] string buffers to write
679
719
  # @return [Integer] number of bytes written
680
720
  def write(*args)
681
721
  Polyphony.backend_sendv(self, args, 0)
@@ -711,8 +751,8 @@ class ::UNIXSocket
711
751
  # @param buf_pos [Number] buffer position to read into
712
752
  # @param raise_on_eof [bool] whether to raise an exception on `EOF`
713
753
  # @return [String, nil] buffer used for reading or nil on `EOF`
714
- def readpartial(maxlen, str = +'', buffer_pos = 0, raise_on_eof = true)
715
- result = Polyphony.backend_recv(self, str, maxlen, buffer_pos)
754
+ def readpartial(maxlen, buf = +'', buf_pos = 0, raise_on_eof = true)
755
+ result = Polyphony.backend_recv(self, buf, maxlen, buf_pos)
716
756
  raise EOFError if !result && raise_on_eof
717
757
  result
718
758
  end
@@ -727,8 +767,8 @@ class ::UNIXSocket
727
767
  # @param buf [String, nil] read buffer
728
768
  # @param exception [bool] whether to raise an exception if not ready for reading
729
769
  # @return [String, :wait_readable] read buffer
730
- def read_nonblock(len, str = nil, exception: true)
731
- @io.read_nonblock(len, str, exception: exception)
770
+ def read_nonblock(maxlen, buf = nil, exception: true)
771
+ @io.read_nonblock(maxlen, buf, exception: exception)
732
772
  end
733
773
 
734
774
  # Performs a non-blocking to the socket. If the socket is not ready for
@@ -744,21 +784,47 @@ class ::UNIXSocket
744
784
  end
745
785
  end
746
786
 
747
- class ::UDPSocket
787
+ # UDPSocket extensions
788
+ class ::UDPSocket < ::IPSocket
789
+ # Reimplements #recvfrom.
790
+ #
791
+ # @param maxlen [Integer] maximum bytes to receive
792
+ # @param flags [Integer] optional flags
793
+ # @return [String] received data
748
794
  def recvfrom(maxlen, flags = 0)
749
795
  buf = +''
750
796
  Polyphony.backend_recvmsg(self, buf, maxlen, 0, flags, 0, nil)
751
797
  end
752
798
 
799
+ # Reimplements #recvmsg.
800
+ #
801
+ # @param maxlen [Integer] maximum bytes to receive
802
+ # @param flags [Integer] optional flags
803
+ # @param maxcontrollen [Integer] maximum control bytes to receive
804
+ # @param opts [Hash] options
805
+ # @return [String] received data
753
806
  def recvmsg(maxlen = nil, flags = 0, maxcontrollen = nil, opts = {})
754
807
  buf = +''
755
808
  Polyphony.backend_recvmsg(self, buf, maxlen || 4096, 0, flags, maxcontrollen, opts)
756
809
  end
757
810
 
811
+ # Reimplements #sendmsg.
812
+ #
813
+ # @param msg [String] data to send
814
+ # @param flags [Integer] optional flags
815
+ # @param dest_sockaddr [Sockaddr, nil] optional destination address
816
+ # @param controls [Array] optional control data
817
+ # @return [Integer] bytes sent
758
818
  def sendmsg(msg, flags = 0, dest_sockaddr = nil, *controls)
759
819
  Polyphony.backend_sendmsg(self, msg, flags, dest_sockaddr, controls)
760
820
  end
761
821
 
822
+ # Sends data.
823
+ #
824
+ # @param msg [String] data to send
825
+ # @param flags [Integer] flags
826
+ # @param addr [Array] addresses to send to
827
+ # @return [Integer] bytes sent
762
828
  def send(msg, flags, *addr)
763
829
  sockaddr = case addr.size
764
830
  when 2
@@ -7,9 +7,13 @@ class ::Thread
7
7
  attr_reader :main_fiber, :result
8
8
  attr_accessor :backend
9
9
 
10
+ # @!visibility private
10
11
  alias_method :orig_initialize, :initialize
11
12
 
12
13
  # Initializes the thread.
14
+ # @param args [Array] arguments to pass to thread block
15
+ # @yield [any] thread block
16
+ # @return [void]
13
17
  def initialize(*args, &block)
14
18
  @join_wait_queue = []
15
19
  @finalization_mutex = Mutex.new
@@ -27,6 +31,7 @@ class ::Thread
27
31
  setup_fiber_scheduling
28
32
  end
29
33
 
34
+ # @!visibility private
30
35
  alias_method :orig_join, :join
31
36
 
32
37
  # call-seq:
@@ -56,6 +61,7 @@ class ::Thread
56
61
  end
57
62
  alias_method :await, :join
58
63
 
64
+ # @!visibility private
59
65
  alias_method :orig_raise, :raise
60
66
 
61
67
  # call-seq:
@@ -77,6 +83,7 @@ class ::Thread
77
83
  main_fiber&.raise(error)
78
84
  end
79
85
 
86
+ # @!visibility private
80
87
  alias_method :orig_kill, :kill
81
88
 
82
89
  # Terminates the thread.
@@ -89,6 +96,7 @@ class ::Thread
89
96
  self
90
97
  end
91
98
 
99
+ # @!visibility private
92
100
  alias_method :orig_inspect, :inspect
93
101
 
94
102
  # Returns a string representation of the thread for debugging purposes.
@@ -128,7 +136,7 @@ class ::Thread
128
136
 
129
137
  # Sets the idle handler for the thread's backend.
130
138
  #
131
- # @param &block [Proc] idle handler
139
+ # @yield [] idle handler
132
140
  # @return [Proc] idle handler
133
141
  def on_idle(&block)
134
142
  backend.idle_proc = block
@@ -13,7 +13,7 @@ module ::Timeout
13
13
  # @param sec [Number] timeout period in seconds
14
14
  # @param klass [Class] exception class
15
15
  # @param message [String] exception message
16
- # @param &block [Proc] code to run
16
+ # @yield [] code to run
17
17
  # @return [any] block's return value
18
18
  def self.timeout(sec, klass = Timeout::Error, message = 'execution expired', &block)
19
19
  cancel_after(sec, with_exception: [klass, message], &block)
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.98'
4
+ # @!visibility private
5
+ VERSION = '0.99.1'
5
6
  end
data/lib/polyphony.rb CHANGED
@@ -18,10 +18,14 @@ require_relative './polyphony/adapters/process'
18
18
  # Polyphony API
19
19
  module Polyphony
20
20
  class << self
21
+ # Creates a new Polyphony::Pipe instance.
22
+ #
23
+ # @return [Polyphony::Pipe] created pipe
21
24
  def pipe
22
25
  Pipe.new
23
26
  end
24
27
 
28
+ # @!visibility private
25
29
  def fork(&block)
26
30
  Kernel.fork do
27
31
  # A race condition can arise if a TERM or INT signal is received before
@@ -39,6 +43,19 @@ module Polyphony
39
43
  end
40
44
  end
41
45
 
46
+ # call-seq:
47
+ # Polyphony.watch_process(cmd)
48
+ # Polyphony.watch_process { sleep 1 }
49
+ #
50
+ # Lubnches a process using either a command or a block for a forked process,
51
+ # waiting for the child process to terminate.
52
+ def watch_process(cmd = nil, &block)
53
+ Polyphony::Process.watch(cmd, &block)
54
+ end
55
+
56
+ private
57
+
58
+ # @!visibility private
42
59
  def spin_forked_block(&block)
43
60
  Fiber.new do
44
61
  run_forked_block(&block)
@@ -54,6 +71,7 @@ module Polyphony
54
71
  end
55
72
  end
56
73
 
74
+ # @!visibility private
57
75
  def run_forked_block(&block)
58
76
  Thread.current.setup
59
77
  Thread.current.backend.post_fork
@@ -63,6 +81,7 @@ module Polyphony
63
81
  block.()
64
82
  end
65
83
 
84
+ # @!visibility private
66
85
  def exit_forked_process
67
86
  terminate_threads
68
87
  Fiber.current.shutdown_all_children
@@ -74,10 +93,7 @@ module Polyphony
74
93
  exit
75
94
  end
76
95
 
77
- def watch_process(cmd = nil, &block)
78
- Polyphony::Process.watch(cmd, &block)
79
- end
80
-
96
+ # @!visibility private
81
97
  def install_terminating_signal_handlers
82
98
  trap('SIGTERM') { raise SystemExit }
83
99
  orig_trap('SIGINT') do
@@ -86,6 +102,7 @@ module Polyphony
86
102
  end
87
103
  end
88
104
 
105
+ # @!visibility private
89
106
  def terminate_threads
90
107
  threads = Thread.list - [Thread.current]
91
108
  return if threads.empty?
@@ -94,8 +111,10 @@ module Polyphony
94
111
  threads.each(&:join)
95
112
  end
96
113
 
114
+ # @!visibility private
97
115
  attr_accessor :original_pid
98
116
 
117
+ # @!visibility private
99
118
  def install_at_exit_handler
100
119
  @original_pid = ::Process.pid
101
120
 
@@ -106,7 +125,7 @@ module Polyphony
106
125
  at_exit do
107
126
  next unless @original_pid == ::Process.pid
108
127
 
109
- Polyphony.terminate_threads
128
+ terminate_threads
110
129
  Fiber.current.shutdown_all_children
111
130
  end
112
131
  end
@@ -123,10 +142,11 @@ module Polyphony
123
142
 
124
143
  Object.const_set(:ConditionVariable, Polyphony::ConditionVariable)
125
144
  $VERBOSE = verbose
145
+
146
+ install_terminating_signal_handlers
147
+ install_at_exit_handler
126
148
  end
127
149
 
128
- Polyphony.install_terminating_signal_handlers
129
- Polyphony.install_at_exit_handler
130
150
 
131
151
  if (debug_socket_path = ENV['POLYPHONY_DEBUG_SOCKET_PATH'])
132
152
  puts "Starting debug server on #{debug_socket_path}"
data/polyphony.gemspec CHANGED
@@ -11,9 +11,7 @@ Gem::Specification.new do |s|
11
11
  s.homepage = 'https://digital-fabric.github.io/polyphony'
12
12
  s.metadata = {
13
13
  "source_code_uri" => "https://github.com/digital-fabric/polyphony",
14
- # "documentation_uri" => "https://www.rubydoc.info/gems/polyphony",
15
- "documentation_uri" => "https://digital-fabric.github.io/polyphony/",
16
- "homepage_uri" => "https://digital-fabric.github.io/polyphony/",
14
+ "documentation_uri" => "https://www.rubydoc.info/gems/polyphony",
17
15
  "changelog_uri" => "https://github.com/digital-fabric/polyphony/blob/master/CHANGELOG.md"
18
16
  }
19
17
  s.rdoc_options = ["--title", "polyphony", "--main", "README.md"]
@@ -31,9 +29,4 @@ Gem::Specification.new do |s|
31
29
  s.add_development_dependency 'msgpack', '1.6.0'
32
30
  s.add_development_dependency 'httparty', '0.21.0'
33
31
  s.add_development_dependency 'localhost', '1.1.10'
34
-
35
- # s.add_development_dependency 'jekyll', '~>3.8.6'
36
- # s.add_development_dependency 'jekyll-remote-theme', '~>0.4.1'
37
- # s.add_development_dependency 'jekyll-seo-tag', '~>2.6.1'
38
- # s.add_development_dependency 'just-the-docs', '~>0.3.0'
39
32
  end
data/test/stress.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  count = ARGV[0] ? ARGV[0].to_i : 100
4
4
  test_name = ARGV[1]
5
5
 
6
- $test_cmd = +'ruby test/run.rb --name test_signal_handler_trace'
6
+ $test_cmd = +'ruby test/run.rb'
7
7
  if test_name
8
8
  $test_cmd << " --name #{test_name}"
9
9
  end
@@ -145,13 +145,13 @@ class MoveOnAfterTest < MiniTest::Test
145
145
 
146
146
  t0 = monotonic_clock
147
147
  o = move_on_after(0.01, with_value: 1) do
148
- move_on_after(0.02, with_value: 2) do
148
+ move_on_after(0.03, with_value: 2) do
149
149
  sleep 1
150
150
  end
151
151
  end
152
152
  t1 = monotonic_clock
153
153
  assert_equal 1, o
154
- assert_in_range 0.008..0.015, t1 - t0 if IS_LINUX
154
+ assert_in_range 0.008..0.027, t1 - t0 if IS_LINUX
155
155
 
156
156
  t0 = monotonic_clock
157
157
  o = move_on_after(0.05, with_value: 1) do
@@ -161,7 +161,7 @@ class MoveOnAfterTest < MiniTest::Test
161
161
  end
162
162
  t1 = monotonic_clock
163
163
  assert_equal 2, o
164
- assert_in_range 0.008..0.013, t1 - t0 if IS_LINUX
164
+ assert_in_range 0.008..0.025, t1 - t0 if IS_LINUX
165
165
  end
166
166
  end
167
167
 
@@ -181,15 +181,17 @@ class CancelAfterTest < MiniTest::Test
181
181
 
182
182
  def test_cancel_after_with_reset
183
183
  t0 = monotonic_clock
184
- cancel_after(0.01) do |f|
184
+ cancel_after(0.1) do |f|
185
185
  assert_kind_of Fiber, f
186
186
  assert_equal Fiber.current, f.parent
187
- sleep 0.007
187
+ sleep 0.05
188
188
  f.reset
189
- sleep 0.007
189
+ sleep 0.05
190
+ f.reset
191
+ sleep 0.05
190
192
  end
191
193
  t1 = monotonic_clock
192
- assert_in_range 0.014..0.024, t1 - t0 if IS_LINUX
194
+ assert_in_range 0.14..0.24, t1 - t0 if IS_LINUX
193
195
  end
194
196
 
195
197
  class CustomException < Exception
@@ -228,6 +230,34 @@ class CancelAfterTest < MiniTest::Test
228
230
  assert_equal 'foo', e.message
229
231
  end
230
232
  end
233
+
234
+ def test_lots_of_cancel_after
235
+ cancels = 100
236
+
237
+ cancel_count = 0
238
+ cancels.times do
239
+ begin
240
+ cancel_after(0.001) { sleep 1 }
241
+ rescue Polyphony::Cancel
242
+ cancel_count += 1
243
+ end
244
+ end
245
+ assert_equal cancels, cancel_count
246
+ end
247
+
248
+ def test_cancel_after_with_lots_of_resets
249
+ resets = 100
250
+
251
+ t0 = monotonic_clock
252
+ cancel_after(0.1) do |f|
253
+ resets.times do
254
+ sleep 0.0001
255
+ f.reset
256
+ end
257
+ end
258
+ t1 = monotonic_clock
259
+ assert_in_range 0.01..0.2, t1 - t0 if IS_LINUX
260
+ end
231
261
  end
232
262
 
233
263
 
@@ -381,6 +411,14 @@ class ThrottledLoopTest < MiniTest::Test
381
411
  assert_in_range 0.075..0.15, t1 - t0 if IS_LINUX
382
412
  assert_equal [1, 2, 3, 4, 5], buffer
383
413
  end
414
+
415
+ def test_throttled_loop_inside_move_on_after
416
+ count = 0
417
+ move_on_after(0.1) do
418
+ throttled_loop(50) { count += 1 }
419
+ end
420
+ assert_in_range 3..7, count
421
+ end
384
422
  end
385
423
 
386
424
  class GlobalAPIEtcTest < MiniTest::Test
data/test/test_io.rb CHANGED
@@ -523,13 +523,12 @@ class IOClassMethodsTest < MiniTest::Test
523
523
  assert_equal BIN_DATA, s
524
524
  end
525
525
 
526
- # def test_foreach
527
- # skip 'IO.foreach is not yet implemented'
528
- # lines = []
529
- # IO.foreach(__FILE__) { |l| lines << l }
530
- # assert_equal "# frozen_string_literal: true\n", lines[0]
531
- # assert_equal "end\n", lines[-1]
532
- # end
526
+ def test_foreach
527
+ lines = []
528
+ IO.foreach(__FILE__) { |l| lines << l }
529
+ assert_equal "# frozen_string_literal: true\n", lines[0]
530
+ assert_equal "end\n", lines[-1]
531
+ end
533
532
 
534
533
  def test_read_class_method
535
534
  s = IO.read(__FILE__)