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
@@ -8,7 +8,7 @@ module Polyphony
8
8
  # Initializes a new resource pool.
9
9
  #
10
10
  # @param opts [Hash] options
11
- # @param &block [Proc] allocator block
11
+ # @yield [] allocator block
12
12
  def initialize(opts, &block)
13
13
  @allocator = block
14
14
  @limit = opts[:limit] || 4
@@ -36,7 +36,7 @@ module Polyphony
36
36
  # db.query(sql).to_a
37
37
  # end
38
38
  #
39
- # @param &block [Proc] code to run
39
+ # @yield [any] code to run
40
40
  # @return [any] return value of block
41
41
  def acquire(&block)
42
42
  fiber = Fiber.current
@@ -54,13 +54,14 @@ module Polyphony
54
54
  # }
55
55
  #
56
56
  # @param sym [Symbol] method name
57
- # @param *args [Array<any>] method arguments
58
- # @param &block [Proc] block passed to method
57
+ # @param args [Array<any>] method arguments
58
+ # @yield [any] block passed to method
59
+ # @return [any] result of method call
59
60
  def method_missing(sym, *args, &block)
60
61
  acquire { |r| r.send(sym, *args, &block) }
61
62
  end
62
63
 
63
- # :no-doc:
64
+ # @!visibility private
64
65
  def respond_to_missing?(*_args)
65
66
  true
66
67
  end
@@ -87,7 +88,7 @@ module Polyphony
87
88
  # Acquires a resource from stock, yielding it to the given block.
88
89
  #
89
90
  # @param fiber [Fiber] the fiber the resource will be associated with
90
- # @param &block [Proc] given block
91
+ # @yield [any] given block
91
92
  # @return [any] return value of block
92
93
  def acquire_from_stock(fiber)
93
94
  add_to_stock if (@stock.empty? || @stock.pending?) && @size < @limit
@@ -17,7 +17,7 @@ module Polyphony
17
17
  # This method is re-entrant. Recursive calls from the given block will not
18
18
  # block.
19
19
  #
20
- # @param &block [Proc] code to run
20
+ # @yield [] code to run
21
21
  # @return [any] return value of block
22
22
  def synchronize(&block)
23
23
  return yield if @holding_fiber == Fiber.current
@@ -58,6 +58,58 @@ module Polyphony
58
58
  @holding_fiber
59
59
  end
60
60
 
61
+ # Obtains a lock. Raises `ThreadError` if mutex is locked by the current
62
+ # thread.
63
+ #
64
+ # @return [Mutex] self
65
+ def lock
66
+ raise ThreadError if owned?
67
+
68
+ @token = @store.shift
69
+ @holding_fiber = Fiber.current
70
+ self
71
+ end
72
+
73
+ # Releases the lock. Raises `ThreadError` if mutex is not locked by the
74
+ # current thread.
75
+ #
76
+ # @return [Mutex] self
77
+ def unlock
78
+ raise ThreadError if !owned?
79
+
80
+ @holding_fiber = nil
81
+ @store << @token if @token
82
+ @token = nil
83
+ end
84
+
85
+ # Attempts to obtain the lock and returns immediately. Returns `true` if the
86
+ # lock was granted.
87
+ #
88
+ # @return [true, false]
89
+ def try_lock
90
+ return false if @holding_fiber
91
+
92
+ @token = @store.shift
93
+ @holding_fiber = Fiber.current
94
+ true
95
+ end
96
+
97
+ # Releases the lock and sleeps timeout seconds if it is given and non-nil or
98
+ # forever. Raises `ThreadError` if mutex wasn’t locked by the current
99
+ # thread.
100
+ #
101
+ # @param timeout [nil, Number] sleep timeout
102
+ # @return [Number] slept time in seconds
103
+ def sleep(timeout = nil)
104
+ unlock
105
+ t0 = Time.now
106
+ Kernel.sleep(timeout)
107
+ t1 = Time.now
108
+ lock
109
+
110
+ return t1 - t0
111
+ end
112
+
61
113
  private
62
114
 
63
115
  # Helper method for performing a `#synchronize` when not currently holding
@@ -72,6 +124,7 @@ module Polyphony
72
124
  ensure
73
125
  @holding_fiber = nil
74
126
  @store << @token if @token
127
+ @token = nil
75
128
  end
76
129
  end
77
130
  end
@@ -87,7 +140,7 @@ module Polyphony
87
140
  # Waits for the condition variable to be signalled.
88
141
  #
89
142
  # @param mutex [Polyphony::Mutex] mutex to release while waiting for signal
90
- # @param timeout [Number, nil] timeout in seconds (currently not implemented)
143
+ # @param _timeout [Number, nil] timeout in seconds (currently not implemented)
91
144
  # @return [void]
92
145
  def wait(mutex, _timeout = nil)
93
146
  mutex.conditional_release
@@ -12,7 +12,7 @@ module Polyphony
12
12
 
13
13
  # Runs the given block on an available thread from the default thread pool.
14
14
  #
15
- # @param &block [Proc] given block
15
+ # @yield [] given block
16
16
  # @return [any] return value of given block
17
17
  def self.process(&block)
18
18
  @default_pool ||= new
@@ -41,7 +41,7 @@ module Polyphony
41
41
 
42
42
  # Runs the given block on an available thread from the pool.
43
43
  #
44
- # @param &block [Proc] given block
44
+ # @yield [] given block
45
45
  # @return [any] return value of block
46
46
  def process(&block)
47
47
  setup unless @task_queue
@@ -55,7 +55,7 @@ module Polyphony
55
55
  # method does not block. The task will be performed once a thread becomes
56
56
  # available.
57
57
  #
58
- # @param &block [Proc] given block
58
+ # @yield [] given block
59
59
  # @return [Polyphony::ThreadPool] self
60
60
  def cast(&block)
61
61
  setup unless @task_queue
@@ -11,7 +11,7 @@ module Polyphony
11
11
  # Initializes a new timer with the given resolution.
12
12
  #
13
13
  # @param tag [any] tag to use for the timer's fiber
14
- # @param resolution: [Number] timer granularity in seconds or fractions thereof
14
+ # @param resolution [Number] timer granularity in seconds or fractions thereof
15
15
  def initialize(tag = nil, resolution:)
16
16
  @fiber = spin_loop(tag, interval: resolution) { update }
17
17
  @timeouts = {}
@@ -43,8 +43,8 @@ module Polyphony
43
43
  # Spins up a fiber that will run the given block after sleeping for the
44
44
  # given delay.
45
45
  #
46
- # @param delay [Number] delay in seconds before running the given block
47
- # @param &block [Proc] block to run
46
+ # @param interval [Number] delay in seconds before running the given block
47
+ # @yield [] block to run
48
48
  # @return [Fiber] spun fiber
49
49
  def after(interval, &block)
50
50
  spin do
@@ -57,7 +57,7 @@ module Polyphony
57
57
  # consecutive iterations.
58
58
  #
59
59
  # @param interval [Number] interval between consecutive iterations in seconds
60
- # @param &block [Proc] block to run
60
+ # @yield [] block to run
61
61
  # @return [void]
62
62
  def every(interval)
63
63
  fiber = Fiber.current
@@ -109,8 +109,8 @@ module Polyphony
109
109
  # end
110
110
  #
111
111
  # @param interval [Number] timout in seconds
112
- # @param with_exception: [Class, Exception] exception or exception class
113
- # @param &block [Proc] block to execute
112
+ # @param with_exception [Class, Exception] exception or exception class
113
+ # @yield [Canceller] block to execute
114
114
  # @return [any] block's return value
115
115
  def cancel_after(interval, with_exception: Polyphony::Cancel)
116
116
  fiber = Fiber.current
@@ -163,8 +163,8 @@ module Polyphony
163
163
  # end
164
164
  #
165
165
  # @param interval [Number] timout in seconds
166
- # @param with_value: [any] return value in case of timeout
167
- # @param &block [Proc] block to execute
166
+ # @param with_value [any] return value in case of timeout
167
+ # @yield [Fiber] block to execute
168
168
  # @return [any] block's return value
169
169
  def move_on_after(interval, with_value: nil)
170
170
  fiber = Fiber.current
@@ -18,6 +18,7 @@ class ::Exception
18
18
  # Set to the fiber from which the exception was raised.
19
19
  attr_accessor :raising_fiber
20
20
 
21
+ # @!visibility private
21
22
  alias_method :orig_initialize, :initialize
22
23
 
23
24
  # Initializes the exception with the given arguments.
@@ -26,6 +27,7 @@ class ::Exception
26
27
  orig_initialize(*args)
27
28
  end
28
29
 
30
+ # @!visibility private
29
31
  alias_method :orig_backtrace, :backtrace
30
32
 
31
33
  # Returns the backtrace for the exception. If
@@ -116,7 +116,7 @@ module Polyphony
116
116
  # operation will be resumed. This API is experimental and might be removed
117
117
  # in the future.
118
118
  #
119
- # @param &block [Proc] given block
119
+ # @yield [any] given block
120
120
  # @return [Fiber] self
121
121
  def interject(&block)
122
122
  raise Polyphony::Interjection.new(block)
@@ -132,7 +132,7 @@ module Polyphony
132
132
 
133
133
  private
134
134
 
135
- # :no-doc:
135
+ # @!visibility private
136
136
  def error_from_raise_args(args)
137
137
  case (arg = args.shift)
138
138
  when String then RuntimeError.new(arg)
@@ -171,10 +171,11 @@ module Polyphony
171
171
  #
172
172
  # This method blocks indefinitely.
173
173
  #
174
- # @param *fibers [Array<Fiber>] fibers to supervise
175
- # @param on_done: [Proc, nil] proc to call when a supervised fiber is terminated
176
- # @param on_error: [Proc, nil] proc to call when a supervised fiber is terminated with an exception
177
- # @param restart: [:always, :on_error, nil] whether to restart terminated fibers
174
+ # @param fibers [Array<Fiber>] fibers to supervise
175
+ # @option opts [Proc, nil] :on_done proc to call when a supervised fiber is terminated
176
+ # @option opts [Proc, nil] :on_error proc to call when a supervised fiber is terminated with an exception
177
+ # @option opts [:always, :on_error, nil] :restart whether to restart terminated fibers
178
+ # @yield [] supervisor block
178
179
  # @return [void]
179
180
  def supervise(*fibers, **opts, &block)
180
181
  block ||= supervise_opts_to_block(opts)
@@ -198,7 +199,7 @@ module Polyphony
198
199
 
199
200
  private
200
201
 
201
- # :no-doc:
202
+ # @!visibility private
202
203
  def supervise_opts_to_block(opts)
203
204
  block = opts[:on_done] || opts[:on_error]
204
205
  restart = opts[:restart]
@@ -228,7 +229,7 @@ module Polyphony
228
229
  # terminates with an uncaught exception, `Fiber.await` will await all the
229
230
  # other fibers to terminate, then reraise the exception.
230
231
  #
231
- # @param *fibers [Array<Fiber>] fibers to wait for
232
+ # @param fibers [Array<Fiber>] fibers to wait for
232
233
  # @return [Array<any>] return values of given fibers
233
234
  def await(*fibers)
234
235
  return [] if fibers.empty?
@@ -267,7 +268,7 @@ module Polyphony
267
268
  # array containing the first terminated fiber and its return value. If an
268
269
  # exception occurs in one of the given fibers, it will be reraised.
269
270
  #
270
- # @param *fibers [Array<Fiber>] Fibers to wait for
271
+ # @param fibers [Array<Fiber>] Fibers to wait for
271
272
  # @return [Array] Array containing the first terminated fiber and its return value
272
273
  def select(*fibers)
273
274
  return nil if fibers.empty?
@@ -301,7 +302,7 @@ module Polyphony
301
302
  # also be scheduled with priority. This method is mainly used trapping
302
303
  # signals (see also the patched `Kernel#trap`)
303
304
  #
304
- # @param &block [Proc] given block
305
+ # @yield [] given block
305
306
  # @return [void]
306
307
  def schedule_priority_oob_fiber(&block)
307
308
  oob_fiber = Fiber.new do
@@ -322,7 +323,7 @@ module Polyphony
322
323
 
323
324
  private
324
325
 
325
- # :no-doc:
326
+ # @!visibility private
326
327
  def prepare_oob_fiber(fiber, block)
327
328
  fiber.oob = true
328
329
  fiber.tag = :oob
@@ -348,7 +349,7 @@ module Polyphony
348
349
  #
349
350
  # @param tag [any] child fiber's tag
350
351
  # @param orig_caller [Array<String>] caller to set for fiber
351
- # @param &block [Proc] child fiber's block
352
+ # @yield [any] child fiber's block
352
353
  # @return [Fiber] child fiber
353
354
  def spin(tag = nil, orig_caller = Kernel.caller, &block)
354
355
  f = Fiber.new { |v| f.run(v) }
@@ -456,10 +457,11 @@ module Polyphony
456
457
 
457
458
  # Removes a child fiber reference. Used internally.
458
459
  #
459
- # @param parent [Fiber] new parent
460
+ # @param child_fiber [Fiber] child fiber to be removed
460
461
  # @return [Fiber] self
461
462
  def remove_child(child_fiber)
462
463
  @children.delete(child_fiber) if @children
464
+ self
463
465
  end
464
466
  end
465
467
 
@@ -5,9 +5,10 @@ require 'open3'
5
5
  # IO extensions
6
6
  class ::IO
7
7
  class << self
8
+ # @!visibility private
8
9
  alias_method :orig_binread, :binread
9
10
 
10
- # TODO: add docs to all methods in this file
11
+ # @!visibility private
11
12
  def binread(name, length = nil, offset = nil)
12
13
  File.open(name, 'rb:ASCII-8BIT') do |f|
13
14
  f.seek(offset) if offset
@@ -15,7 +16,10 @@ class ::IO
15
16
  end
16
17
  end
17
18
 
19
+ # @!visibility private
18
20
  alias_method :orig_binwrite, :binwrite
21
+
22
+ # @!visibility private
19
23
  def binwrite(name, string, offset = nil)
20
24
  File.open(name, 'wb:ASCII-8BIT') do |f|
21
25
  f.seek(offset) if offset
@@ -23,24 +27,27 @@ class ::IO
23
27
  end
24
28
  end
25
29
 
30
+ # @!visibility private
26
31
  EMPTY_HASH = {}.freeze
27
32
 
28
- # alias_method :orig_foreach, :foreach
29
- # def foreach(_name, _sep = $/, _limit = nil, _getline_args = EMPTY_HASH,
30
- # &_block)
31
- # # IO.orig_read(name).each_line(&block)
32
- # raise NotImplementedError
33
-
34
- # # if sep.is_a?(Integer)
35
- # # sep = $/
36
- # # limit = sep
37
- # # end
38
- # # File.open(name, 'r') do |f|
39
- # # f.each_line(sep, limit, getline_args, &block)
40
- # # end
41
- # end
33
+ # @!visibility private
34
+ alias_method :orig_foreach, :foreach
35
+
36
+ # @!visibility private
37
+ def foreach(name, sep = $/, limit = nil, getline_args = EMPTY_HASH, &block)
38
+ if sep.is_a?(Integer)
39
+ sep = $/
40
+ limit = sep
41
+ end
42
+ File.open(name, 'r') do |f|
43
+ f.each_line(sep, limit, chomp: getline_args[:chomp], &block)
44
+ end
45
+ end
42
46
 
47
+ # @!visibility private
43
48
  alias_method :orig_read, :read
49
+
50
+ # @!visibility private
44
51
  def read(name, length = nil, offset = nil, opt = EMPTY_HASH)
45
52
  if length.is_a?(Hash)
46
53
  opt = length
@@ -59,7 +66,10 @@ class ::IO
59
66
  # end
60
67
  # end
61
68
 
69
+ # @!visibility private
62
70
  alias_method :orig_write, :write
71
+
72
+ # @!visibility private
63
73
  def write(name, string, offset = nil, opt = EMPTY_HASH)
64
74
  File.open(name, opt[:mode] || 'w') do |f|
65
75
  f.seek(offset) if offset
@@ -67,22 +77,44 @@ class ::IO
67
77
  end
68
78
  end
69
79
 
80
+ # @!visibility private
70
81
  alias_method :orig_popen, :popen
82
+
83
+
84
+ # @!visibility private
71
85
  def popen(cmd, mode = 'r')
72
86
  return orig_popen(cmd, mode) unless block_given?
73
87
 
74
88
  Open3.popen2(cmd) { |_i, o, _t| yield o }
75
89
  end
76
90
 
91
+ # Splices from one IO to another IO. At least one of the IOs must be a pipe.
92
+ #
93
+ # @param src [IO, Polyphony::Pipe] source to splice from
94
+ # @param dest [IO, Polyphony::Pipe] destination to splice to
95
+ # @param maxlen [Integer] maximum bytes to splice
96
+ # @return [Integer] bytes spliced
77
97
  def splice(src, dest, maxlen)
78
98
  Polyphony.backend_splice(src, dest, maxlen)
79
99
  end
80
100
 
81
101
  if RUBY_PLATFORM =~ /linux/
102
+ # Creates a pipe and splices data between the two given IOs using the
103
+ # pipe, splicing until EOF.
104
+ #
105
+ # @param src [IO, Polyphony::Pipe] source to splice from
106
+ # @param dest [IO, Polyphony::Pipe] destination to splice to
107
+ # @return [Integer] total bytes spliced
82
108
  def double_splice(src, dest)
83
109
  Polyphony.backend_double_splice(src, dest)
84
110
  end
85
111
 
112
+ # Tees data from the source to the desination.
113
+ #
114
+ # @param src [IO, Polyphony::Pipe] source to tee from
115
+ # @param dest [IO, Polyphony::Pipe] destination to tee to
116
+ # @param maxlen [Integer] maximum bytes to tee
117
+ # @return [Integer] total bytes teed
86
118
  def tee(src, dest, maxlen)
87
119
  Polyphony.backend_tee(src, dest, maxlen)
88
120
  end
@@ -92,10 +124,12 @@ end
92
124
 
93
125
  # IO instance method patches
94
126
  class ::IO
127
+ # @!visibility private
95
128
  def __read_method__
96
129
  :backend_read
97
130
  end
98
131
 
132
+ # @!visibility private
99
133
  def __write_method__
100
134
  :backend_write
101
135
  end
@@ -114,13 +148,21 @@ class ::IO
114
148
  # def each_codepoint
115
149
  # end
116
150
 
151
+ # @!visibility private
117
152
  alias_method :orig_getbyte, :getbyte
153
+
154
+
155
+ # @!visibility private
118
156
  def getbyte
119
157
  char = getc
120
158
  char ? char.getbyte(0) : nil
121
159
  end
122
160
 
161
+ # @!visibility private
123
162
  alias_method :orig_getc, :getc
163
+
164
+
165
+ # @!visibility private
124
166
  def getc
125
167
  return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
126
168
 
@@ -131,6 +173,7 @@ class ::IO
131
173
  nil
132
174
  end
133
175
 
176
+ # @!visibility private
134
177
  def ungetc(c)
135
178
  c = c.chr if c.is_a?(Integer)
136
179
  if @read_buffer
@@ -141,7 +184,11 @@ class ::IO
141
184
  end
142
185
  alias_method :ungetbyte, :ungetc
143
186
 
187
+ # @!visibility private
144
188
  alias_method :orig_read, :read
189
+
190
+
191
+ # @!visibility private
145
192
  def read(len = nil, buf = nil, buf_pos = 0)
146
193
  return '' if len == 0
147
194
 
@@ -158,7 +205,10 @@ class ::IO
158
205
  already_read
159
206
  end
160
207
 
208
+ # @!visibility private
161
209
  alias_method :orig_readpartial, :read
210
+
211
+ # @!visibility private
162
212
  def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
163
213
  result = Polyphony.backend_read(self, str, len, false, buffer_pos)
164
214
  raise EOFError if !result && raise_on_eof
@@ -166,18 +216,27 @@ class ::IO
166
216
  result
167
217
  end
168
218
 
219
+ # @!visibility private
169
220
  alias_method :orig_write, :write
221
+
222
+ # @!visibility private
170
223
  def write(str, *args)
171
224
  Polyphony.backend_write(self, str, *args)
172
225
  end
173
226
 
227
+ # @!visibility private
174
228
  alias_method :orig_write_chevron, :<<
229
+
230
+ # @!visibility private
175
231
  def <<(str)
176
232
  Polyphony.backend_write(self, str)
177
233
  self
178
234
  end
179
-
235
+
236
+ # @!visibility private
180
237
  alias_method :orig_gets, :gets
238
+
239
+ # @!visibility private
181
240
  def gets(sep = $/, _limit = nil, _chomp: nil)
182
241
  if sep.is_a?(Integer)
183
242
  sep = $/
@@ -198,6 +257,31 @@ class ::IO
198
257
  return nil
199
258
  end
200
259
 
260
+ # @!visibility private
261
+ def each_line(sep = $/, limit = nil, chomp: false)
262
+ if sep.is_a?(Integer)
263
+ limit = sep
264
+ sep = $/
265
+ end
266
+ sep_size = sep.bytesize
267
+
268
+
269
+ @read_buffer ||= +''
270
+
271
+ while true
272
+ while (idx = @read_buffer.index(sep))
273
+ line = @read_buffer.slice!(0, idx + sep_size)
274
+ line = line.chomp if chomp
275
+ yield line
276
+ end
277
+
278
+ result = readpartial(8192, @read_buffer, -1)
279
+ return self if !result
280
+ end
281
+ rescue EOFError
282
+ return self
283
+ end
284
+
201
285
  # def print(*args)
202
286
  # end
203
287
 
@@ -207,10 +291,15 @@ class ::IO
207
291
  # def putc(obj)
208
292
  # end
209
293
 
294
+ # @!visibility private
210
295
  LINEFEED = "\n"
296
+ # @!visibility private
211
297
  LINEFEED_RE = /\n$/.freeze
212
298
 
299
+ # @!visibility private
213
300
  alias_method :orig_puts, :puts
301
+
302
+ # @!visibility private
214
303
  def puts(*args)
215
304
  if args.empty?
216
305
  write LINEFEED
@@ -245,24 +334,66 @@ class ::IO
245
334
  # def readlines(sep = $/, limit = nil, chomp: nil)
246
335
  # end
247
336
 
337
+ # @!visibility private
248
338
  alias_method :orig_write_nonblock, :write_nonblock
339
+
340
+ # @!visibility private
249
341
  def write_nonblock(string, _options = {})
250
342
  write(string)
251
343
  end
252
344
 
345
+ # @!visibility private
253
346
  alias_method :orig_read_nonblock, :read_nonblock
347
+
348
+ # @!visibility private
254
349
  def read_nonblock(maxlen, buf = nil, _options = nil)
255
350
  buf ? readpartial(maxlen, buf) : readpartial(maxlen)
256
351
  end
257
352
 
353
+ # call-seq:
354
+ # io.read_loop { |data| ... }
355
+ # io.read_loop(maxlen) { |data| ... }
356
+ #
357
+ # Reads up to `maxlen` bytes at a time in an infinite loop. Read data
358
+ # will be passed to the given block.
359
+ #
360
+ # @param maxlen [Integer] maximum bytes to receive
361
+ # @yield [String] handler block
362
+ # @return [void]
258
363
  def read_loop(maxlen = 8192, &block)
259
364
  Polyphony.backend_read_loop(self, maxlen, &block)
260
365
  end
261
366
 
367
+ # call-seq:
368
+ # io.feed_loop(receiver, method)
369
+ # io.feed_loop(receiver, method) { |result| ... }
370
+ #
371
+ # Receives data from the io in an infinite loop, passing the data to the given
372
+ # receiver using the given method. If a block is given, the result of the
373
+ # method call to the receiver is passed to the block.
374
+ #
375
+ # This method can be used to feed data into parser objects. The following
376
+ # example shows how to feed data from a io directly into a MessagePack
377
+ # unpacker:
378
+ #
379
+ # unpacker = MessagePack::Unpacker.new
380
+ # buffer = []
381
+ # reader = spin do
382
+ # io.feed_loop(unpacker, :feed_each) { |msg| handle_msg(msg) }
383
+ # end
384
+ #
385
+ # @param receiver [any] receiver object
386
+ # @param method [Symbol] method to call
387
+ # @yield [any] block to handle result of method call to receiver
388
+ # @return [void]
262
389
  def feed_loop(receiver, method = :call, &block)
263
390
  Polyphony.backend_feed_loop(self, receiver, method, &block)
264
391
  end
265
392
 
393
+ # Waits for the IO to become readable, with an optional timeout.
394
+ #
395
+ # @param timeout [Integer, nil] optional timeout in seconds.
396
+ # @return [IO] self
266
397
  def wait_readable(timeout = nil)
267
398
  return self if @read_buffer && @read_buffer.size > 0
268
399
 
@@ -277,6 +408,10 @@ class ::IO
277
408
  end
278
409
  end
279
410
 
411
+ # Waits for the IO to become writeable, with an optional timeout.
412
+ #
413
+ # @param timeout [Integer, nil] optional timeout in seconds.
414
+ # @return [IO] self
280
415
  def wait_writable(timeout = nil)
281
416
  if timeout
282
417
  move_on_after(timeout) do
@@ -289,11 +424,21 @@ class ::IO
289
424
  end
290
425
  end
291
426
 
427
+ # Splices data from the given IO.
428
+ #
429
+ # @param src [IO, Polpyhony::Pipe] source to splice from
430
+ # @param maxlen [Integer] maximum bytes to splice
431
+ # @return [Integer] bytes spliced
292
432
  def splice_from(src, maxlen)
293
433
  Polyphony.backend_splice(src, self, maxlen)
294
434
  end
295
435
 
296
436
  if RUBY_PLATFORM =~ /linux/
437
+ # Tees data from the given IO.
438
+ #
439
+ # @param src [IO, Polpyhony::Pipe] source to tee from
440
+ # @param maxlen [Integer] maximum bytes to tee
441
+ # @return [Integer] bytes teed
297
442
  def tee_from(src, maxlen)
298
443
  Polyphony.backend_tee(src, self, maxlen)
299
444
  end