polyphony 0.98 → 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 (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