polyphony 1.0.1 → 1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +1 -1
  3. data/.github/workflows/test_io_uring.yml +1 -1
  4. data/.yardopts +1 -0
  5. data/CHANGELOG.md +9 -0
  6. data/README.md +1 -0
  7. data/TODO.md +6 -12
  8. data/docs/advanced-io.md +224 -0
  9. data/docs/cheat-sheet.md +2 -2
  10. data/docs/readme.md +1 -0
  11. data/examples/core/debug.rb +12 -0
  12. data/examples/core/rpc_benchmark.rb +136 -0
  13. data/examples/core/stream_mockup.rb +68 -0
  14. data/examples/core/throttled_loop_inside_move_on_after.rb +13 -0
  15. data/ext/polyphony/backend_common.c +3 -5
  16. data/ext/polyphony/backend_common.h +10 -1
  17. data/ext/polyphony/backend_io_uring.c +6 -6
  18. data/ext/polyphony/backend_libev.c +5 -5
  19. data/ext/polyphony/extconf.rb +6 -0
  20. data/ext/polyphony/fiber.c +21 -1
  21. data/lib/polyphony/extensions/fiber.rb +1 -0
  22. data/lib/polyphony/extensions/io.rb +74 -74
  23. data/lib/polyphony/extensions/object.rb +6 -0
  24. data/lib/polyphony/extensions/socket.rb +39 -39
  25. data/lib/polyphony/version.rb +1 -1
  26. data/polyphony.gemspec +3 -1
  27. data/test/stress.rb +1 -1
  28. data/test/test_fiber.rb +45 -1
  29. data/test/test_io.rb +46 -0
  30. data/test/test_process_supervision.rb +1 -1
  31. data/test/test_resource_pool.rb +1 -1
  32. data/test/test_scenarios.rb +38 -0
  33. data/test/test_socket.rb +1 -2
  34. data/test/test_thread_pool.rb +4 -2
  35. data/test/test_timer.rb +2 -2
  36. metadata +36 -149
  37. data/vendor/liburing/man/IO_URING_CHECK_VERSION.3 +0 -1
  38. data/vendor/liburing/man/IO_URING_VERSION_MAJOR.3 +0 -1
  39. data/vendor/liburing/man/IO_URING_VERSION_MINOR.3 +0 -1
  40. data/vendor/liburing/man/io_uring.7 +0 -781
  41. data/vendor/liburing/man/io_uring_buf_ring_add.3 +0 -53
  42. data/vendor/liburing/man/io_uring_buf_ring_advance.3 +0 -31
  43. data/vendor/liburing/man/io_uring_buf_ring_cq_advance.3 +0 -41
  44. data/vendor/liburing/man/io_uring_buf_ring_init.3 +0 -30
  45. data/vendor/liburing/man/io_uring_buf_ring_mask.3 +0 -27
  46. data/vendor/liburing/man/io_uring_check_version.3 +0 -72
  47. data/vendor/liburing/man/io_uring_close_ring_fd.3 +0 -43
  48. data/vendor/liburing/man/io_uring_cq_advance.3 +0 -49
  49. data/vendor/liburing/man/io_uring_cq_has_overflow.3 +0 -25
  50. data/vendor/liburing/man/io_uring_cq_ready.3 +0 -26
  51. data/vendor/liburing/man/io_uring_cqe_get_data.3 +0 -53
  52. data/vendor/liburing/man/io_uring_cqe_get_data64.3 +0 -1
  53. data/vendor/liburing/man/io_uring_cqe_seen.3 +0 -42
  54. data/vendor/liburing/man/io_uring_enter.2 +0 -1700
  55. data/vendor/liburing/man/io_uring_enter2.2 +0 -1
  56. data/vendor/liburing/man/io_uring_free_probe.3 +0 -27
  57. data/vendor/liburing/man/io_uring_get_events.3 +0 -33
  58. data/vendor/liburing/man/io_uring_get_probe.3 +0 -30
  59. data/vendor/liburing/man/io_uring_get_sqe.3 +0 -57
  60. data/vendor/liburing/man/io_uring_major_version.3 +0 -1
  61. data/vendor/liburing/man/io_uring_minor_version.3 +0 -1
  62. data/vendor/liburing/man/io_uring_opcode_supported.3 +0 -30
  63. data/vendor/liburing/man/io_uring_peek_cqe.3 +0 -38
  64. data/vendor/liburing/man/io_uring_prep_accept.3 +0 -197
  65. data/vendor/liburing/man/io_uring_prep_accept_direct.3 +0 -1
  66. data/vendor/liburing/man/io_uring_prep_cancel.3 +0 -118
  67. data/vendor/liburing/man/io_uring_prep_cancel64.3 +0 -1
  68. data/vendor/liburing/man/io_uring_prep_close.3 +0 -59
  69. data/vendor/liburing/man/io_uring_prep_close_direct.3 +0 -1
  70. data/vendor/liburing/man/io_uring_prep_connect.3 +0 -66
  71. data/vendor/liburing/man/io_uring_prep_fadvise.3 +0 -59
  72. data/vendor/liburing/man/io_uring_prep_fallocate.3 +0 -59
  73. data/vendor/liburing/man/io_uring_prep_fgetxattr.3 +0 -1
  74. data/vendor/liburing/man/io_uring_prep_files_update.3 +0 -92
  75. data/vendor/liburing/man/io_uring_prep_fsetxattr.3 +0 -1
  76. data/vendor/liburing/man/io_uring_prep_fsync.3 +0 -70
  77. data/vendor/liburing/man/io_uring_prep_getxattr.3 +0 -61
  78. data/vendor/liburing/man/io_uring_prep_link.3 +0 -1
  79. data/vendor/liburing/man/io_uring_prep_link_timeout.3 +0 -94
  80. data/vendor/liburing/man/io_uring_prep_linkat.3 +0 -91
  81. data/vendor/liburing/man/io_uring_prep_madvise.3 +0 -56
  82. data/vendor/liburing/man/io_uring_prep_mkdir.3 +0 -1
  83. data/vendor/liburing/man/io_uring_prep_mkdirat.3 +0 -83
  84. data/vendor/liburing/man/io_uring_prep_msg_ring.3 +0 -92
  85. data/vendor/liburing/man/io_uring_prep_msg_ring_cqe_flags.3 +0 -1
  86. data/vendor/liburing/man/io_uring_prep_multishot_accept.3 +0 -1
  87. data/vendor/liburing/man/io_uring_prep_multishot_accept_direct.3 +0 -1
  88. data/vendor/liburing/man/io_uring_prep_nop.3 +0 -28
  89. data/vendor/liburing/man/io_uring_prep_openat.3 +0 -117
  90. data/vendor/liburing/man/io_uring_prep_openat2.3 +0 -117
  91. data/vendor/liburing/man/io_uring_prep_openat2_direct.3 +0 -1
  92. data/vendor/liburing/man/io_uring_prep_openat_direct.3 +0 -1
  93. data/vendor/liburing/man/io_uring_prep_poll_add.3 +0 -72
  94. data/vendor/liburing/man/io_uring_prep_poll_multishot.3 +0 -1
  95. data/vendor/liburing/man/io_uring_prep_poll_remove.3 +0 -55
  96. data/vendor/liburing/man/io_uring_prep_poll_update.3 +0 -89
  97. data/vendor/liburing/man/io_uring_prep_provide_buffers.3 +0 -140
  98. data/vendor/liburing/man/io_uring_prep_read.3 +0 -69
  99. data/vendor/liburing/man/io_uring_prep_read_fixed.3 +0 -72
  100. data/vendor/liburing/man/io_uring_prep_readv.3 +0 -85
  101. data/vendor/liburing/man/io_uring_prep_readv2.3 +0 -111
  102. data/vendor/liburing/man/io_uring_prep_recv.3 +0 -105
  103. data/vendor/liburing/man/io_uring_prep_recv_multishot.3 +0 -1
  104. data/vendor/liburing/man/io_uring_prep_recvmsg.3 +0 -124
  105. data/vendor/liburing/man/io_uring_prep_recvmsg_multishot.3 +0 -1
  106. data/vendor/liburing/man/io_uring_prep_remove_buffers.3 +0 -52
  107. data/vendor/liburing/man/io_uring_prep_rename.3 +0 -1
  108. data/vendor/liburing/man/io_uring_prep_renameat.3 +0 -96
  109. data/vendor/liburing/man/io_uring_prep_send.3 +0 -66
  110. data/vendor/liburing/man/io_uring_prep_send_set_addr.3 +0 -38
  111. data/vendor/liburing/man/io_uring_prep_send_zc.3 +0 -96
  112. data/vendor/liburing/man/io_uring_prep_send_zc_fixed.3 +0 -1
  113. data/vendor/liburing/man/io_uring_prep_sendmsg.3 +0 -89
  114. data/vendor/liburing/man/io_uring_prep_sendmsg_zc.3 +0 -1
  115. data/vendor/liburing/man/io_uring_prep_setxattr.3 +0 -64
  116. data/vendor/liburing/man/io_uring_prep_shutdown.3 +0 -53
  117. data/vendor/liburing/man/io_uring_prep_socket.3 +0 -118
  118. data/vendor/liburing/man/io_uring_prep_socket_direct.3 +0 -1
  119. data/vendor/liburing/man/io_uring_prep_socket_direct_alloc.3 +0 -1
  120. data/vendor/liburing/man/io_uring_prep_splice.3 +0 -120
  121. data/vendor/liburing/man/io_uring_prep_statx.3 +0 -74
  122. data/vendor/liburing/man/io_uring_prep_symlink.3 +0 -1
  123. data/vendor/liburing/man/io_uring_prep_symlinkat.3 +0 -85
  124. data/vendor/liburing/man/io_uring_prep_sync_file_range.3 +0 -59
  125. data/vendor/liburing/man/io_uring_prep_tee.3 +0 -74
  126. data/vendor/liburing/man/io_uring_prep_timeout.3 +0 -95
  127. data/vendor/liburing/man/io_uring_prep_timeout_remove.3 +0 -1
  128. data/vendor/liburing/man/io_uring_prep_timeout_update.3 +0 -98
  129. data/vendor/liburing/man/io_uring_prep_unlink.3 +0 -1
  130. data/vendor/liburing/man/io_uring_prep_unlinkat.3 +0 -82
  131. data/vendor/liburing/man/io_uring_prep_write.3 +0 -67
  132. data/vendor/liburing/man/io_uring_prep_write_fixed.3 +0 -72
  133. data/vendor/liburing/man/io_uring_prep_writev.3 +0 -85
  134. data/vendor/liburing/man/io_uring_prep_writev2.3 +0 -111
  135. data/vendor/liburing/man/io_uring_queue_exit.3 +0 -26
  136. data/vendor/liburing/man/io_uring_queue_init.3 +0 -89
  137. data/vendor/liburing/man/io_uring_queue_init_params.3 +0 -1
  138. data/vendor/liburing/man/io_uring_recvmsg_cmsg_firsthdr.3 +0 -1
  139. data/vendor/liburing/man/io_uring_recvmsg_cmsg_nexthdr.3 +0 -1
  140. data/vendor/liburing/man/io_uring_recvmsg_name.3 +0 -1
  141. data/vendor/liburing/man/io_uring_recvmsg_out.3 +0 -82
  142. data/vendor/liburing/man/io_uring_recvmsg_payload.3 +0 -1
  143. data/vendor/liburing/man/io_uring_recvmsg_payload_length.3 +0 -1
  144. data/vendor/liburing/man/io_uring_recvmsg_validate.3 +0 -1
  145. data/vendor/liburing/man/io_uring_register.2 +0 -834
  146. data/vendor/liburing/man/io_uring_register_buf_ring.3 +0 -140
  147. data/vendor/liburing/man/io_uring_register_buffers.3 +0 -104
  148. data/vendor/liburing/man/io_uring_register_buffers_sparse.3 +0 -1
  149. data/vendor/liburing/man/io_uring_register_buffers_tags.3 +0 -1
  150. data/vendor/liburing/man/io_uring_register_buffers_update_tag.3 +0 -1
  151. data/vendor/liburing/man/io_uring_register_eventfd.3 +0 -51
  152. data/vendor/liburing/man/io_uring_register_eventfd_async.3 +0 -1
  153. data/vendor/liburing/man/io_uring_register_file_alloc_range.3 +0 -52
  154. data/vendor/liburing/man/io_uring_register_files.3 +0 -112
  155. data/vendor/liburing/man/io_uring_register_files_sparse.3 +0 -1
  156. data/vendor/liburing/man/io_uring_register_files_tags.3 +0 -1
  157. data/vendor/liburing/man/io_uring_register_files_update.3 +0 -1
  158. data/vendor/liburing/man/io_uring_register_files_update_tag.3 +0 -1
  159. data/vendor/liburing/man/io_uring_register_iowq_aff.3 +0 -61
  160. data/vendor/liburing/man/io_uring_register_iowq_max_workers.3 +0 -71
  161. data/vendor/liburing/man/io_uring_register_ring_fd.3 +0 -49
  162. data/vendor/liburing/man/io_uring_register_sync_cancel.3 +0 -71
  163. data/vendor/liburing/man/io_uring_setup.2 +0 -669
  164. data/vendor/liburing/man/io_uring_sq_ready.3 +0 -31
  165. data/vendor/liburing/man/io_uring_sq_space_left.3 +0 -25
  166. data/vendor/liburing/man/io_uring_sqe_set_data.3 +0 -48
  167. data/vendor/liburing/man/io_uring_sqe_set_data64.3 +0 -1
  168. data/vendor/liburing/man/io_uring_sqe_set_flags.3 +0 -87
  169. data/vendor/liburing/man/io_uring_sqring_wait.3 +0 -34
  170. data/vendor/liburing/man/io_uring_submit.3 +0 -46
  171. data/vendor/liburing/man/io_uring_submit_and_get_events.3 +0 -31
  172. data/vendor/liburing/man/io_uring_submit_and_wait.3 +0 -38
  173. data/vendor/liburing/man/io_uring_submit_and_wait_timeout.3 +0 -56
  174. data/vendor/liburing/man/io_uring_unregister_buf_ring.3 +0 -30
  175. data/vendor/liburing/man/io_uring_unregister_buffers.3 +0 -27
  176. data/vendor/liburing/man/io_uring_unregister_eventfd.3 +0 -1
  177. data/vendor/liburing/man/io_uring_unregister_files.3 +0 -27
  178. data/vendor/liburing/man/io_uring_unregister_iowq_aff.3 +0 -1
  179. data/vendor/liburing/man/io_uring_unregister_ring_fd.3 +0 -32
  180. data/vendor/liburing/man/io_uring_wait_cqe.3 +0 -40
  181. data/vendor/liburing/man/io_uring_wait_cqe_nr.3 +0 -43
  182. data/vendor/liburing/man/io_uring_wait_cqe_timeout.3 +0 -53
  183. data/vendor/liburing/man/io_uring_wait_cqes.3 +0 -56
@@ -277,10 +277,10 @@ static inline int fd_from_io(VALUE io, rb_io_t **fptr, int write_mode, int recti
277
277
  if (underlying_io != Qnil) io = underlying_io;
278
278
 
279
279
  GetOpenFile(io, *fptr);
280
- io_verify_blocking_mode(*fptr, io, Qfalse);
280
+ int fd = rb_io_descriptor(io);
281
+ io_verify_blocking_mode(io, fd, Qfalse);
281
282
  if (rectify_file_pos) rectify_io_file_pos(*fptr);
282
-
283
- return (*fptr)->fd;
283
+ return fd;
284
284
  }
285
285
  }
286
286
 
@@ -681,7 +681,7 @@ VALUE Backend_accept(VALUE self, VALUE server_socket, VALUE socket_class) {
681
681
  fp->fd = fd;
682
682
  fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
683
683
  rb_io_ascii8bit_binmode(socket);
684
- io_verify_blocking_mode(fp, socket, Qfalse);
684
+ io_verify_blocking_mode(socket, fd, Qfalse);
685
685
  rb_io_synchronized(fp);
686
686
 
687
687
  // if (rsock_do_not_reverse_lookup) {
@@ -736,7 +736,7 @@ VALUE Backend_accept_loop(VALUE self, VALUE server_socket, VALUE socket_class) {
736
736
  fp->fd = fd;
737
737
  fp->mode = FMODE_READWRITE | FMODE_DUPLEX;
738
738
  rb_io_ascii8bit_binmode(socket);
739
- io_verify_blocking_mode(fp, socket, Qfalse);
739
+ io_verify_blocking_mode(socket, fd, Qfalse);
740
740
  rb_io_synchronized(fp);
741
741
 
742
742
  rb_yield(socket);
@@ -98,4 +98,10 @@ end
98
98
 
99
99
  have_header('ruby/io/buffer.h')
100
100
 
101
+ have_func('rb_io_path')
102
+ have_func('rb_io_descriptor')
103
+ have_func('rb_io_get_write_io')
104
+ have_func('rb_io_closed_p')
105
+ have_func('rb_io_open_descriptor')
106
+
101
107
  create_makefile 'polyphony_ext'
@@ -1,3 +1,4 @@
1
+ #include <stdnoreturn.h>
1
2
  #include "polyphony.h"
2
3
 
3
4
  ID ID_ivar_auto_watcher;
@@ -129,7 +130,7 @@ VALUE Fiber_send(VALUE self, VALUE msg) {
129
130
  return self;
130
131
  }
131
132
 
132
- /* Receive's a message from the fiber's mailbox. If no message is available,
133
+ /* Receives a message from the fiber's mailbox. If no message is available,
133
134
  * waits for a message to be sent to it.
134
135
  *
135
136
  * @return [any] received message
@@ -144,6 +145,24 @@ VALUE Fiber_receive(VALUE self) {
144
145
  return Queue_shift(0, 0, mailbox);
145
146
  }
146
147
 
148
+ /* Receives messages from the fiber's mailbox in an infinite loop.
149
+ *
150
+ */
151
+
152
+ noreturn VALUE Fiber_receive_loop(VALUE self) {
153
+ VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
154
+ if (mailbox == Qnil) {
155
+ mailbox = rb_funcall(cQueue, ID_new, 0);
156
+ rb_ivar_set(self, ID_ivar_mailbox, mailbox);
157
+ }
158
+
159
+ while (1) {
160
+ VALUE msg = Queue_shift(0, 0,mailbox);
161
+ rb_yield(msg);
162
+ RB_GC_GUARD(msg);
163
+ }
164
+ }
165
+
147
166
  /* Returns the fiber's mailbox.
148
167
  *
149
168
  * @return [Queue]
@@ -201,6 +220,7 @@ void Init_Fiber(void) {
201
220
  rb_define_method(cFiber, "<<", Fiber_send, 1);
202
221
  rb_define_method(cFiber, "send", Fiber_send, 1);
203
222
  rb_define_method(cFiber, "receive", Fiber_receive, 0);
223
+ rb_define_method(cFiber, "receive_loop", Fiber_receive_loop, 0);
204
224
  rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
205
225
  rb_define_method(cFiber, "mailbox", Fiber_mailbox, 0);
206
226
 
@@ -89,6 +89,7 @@ class ::Fiber
89
89
  self
90
90
  end
91
91
  alias_method :stop, :interrupt
92
+ alias_method :kill, :interrupt
92
93
  alias_method :move_on, :interrupt
93
94
 
94
95
  # Restarts the fiber, with the given value serving as the first value passed
@@ -7,7 +7,7 @@ class ::IO
7
7
  class << self
8
8
  # @!visibility private
9
9
  alias_method :orig_binread, :binread
10
-
10
+
11
11
  # @!visibility private
12
12
  def binread(name, length = nil, offset = nil)
13
13
  File.open(name, 'rb:ASCII-8BIT') do |f|
@@ -15,10 +15,10 @@ class ::IO
15
15
  length ? f.read(length) : f.read
16
16
  end
17
17
  end
18
-
18
+
19
19
  # @!visibility private
20
20
  alias_method :orig_binwrite, :binwrite
21
-
21
+
22
22
  # @!visibility private
23
23
  def binwrite(name, string, offset = nil)
24
24
  File.open(name, 'wb:ASCII-8BIT') do |f|
@@ -26,13 +26,13 @@ class ::IO
26
26
  f.write(string)
27
27
  end
28
28
  end
29
-
29
+
30
30
  # @!visibility private
31
31
  EMPTY_HASH = {}.freeze
32
-
32
+
33
33
  # @!visibility private
34
34
  alias_method :orig_foreach, :foreach
35
-
35
+
36
36
  # @!visibility private
37
37
  def foreach(name, sep = $/, limit = nil, getline_args = EMPTY_HASH, &block)
38
38
  if sep.is_a?(Integer)
@@ -43,10 +43,10 @@ class ::IO
43
43
  f.each_line(sep, limit, chomp: getline_args[:chomp], &block)
44
44
  end
45
45
  end
46
-
46
+
47
47
  # @!visibility private
48
48
  alias_method :orig_read, :read
49
-
49
+
50
50
  # @!visibility private
51
51
  def read(name, length = nil, offset = nil, opt = EMPTY_HASH)
52
52
  if length.is_a?(Hash)
@@ -58,17 +58,17 @@ class ::IO
58
58
  length ? f.read(length) : f.read
59
59
  end
60
60
  end
61
-
61
+
62
62
  # alias_method :orig_readlines, :readlines
63
63
  # def readlines(name, sep = $/, limit = nil, getline_args = EMPTY_HASH)
64
64
  # File.open(name, 'r') do |f|
65
65
  # f.readlines(sep, limit, getline_args)
66
66
  # end
67
67
  # end
68
-
68
+
69
69
  # @!visibility private
70
70
  alias_method :orig_write, :write
71
-
71
+
72
72
  # @!visibility private
73
73
  def write(name, string, offset = nil, opt = EMPTY_HASH)
74
74
  File.open(name, opt[:mode] || 'w') do |f|
@@ -76,18 +76,18 @@ class ::IO
76
76
  f.write(string)
77
77
  end
78
78
  end
79
-
79
+
80
80
  # @!visibility private
81
81
  alias_method :orig_popen, :popen
82
-
83
-
82
+
83
+
84
84
  # @!visibility private
85
85
  def popen(cmd, mode = 'r')
86
86
  return orig_popen(cmd, mode) unless block_given?
87
-
87
+
88
88
  Open3.popen2(cmd) { |_i, o, _t| yield o }
89
89
  end
90
-
90
+
91
91
  # Splices from one IO to another IO. At least one of the IOs must be a pipe.
92
92
  # If maxlen is negative, splices repeatedly using absolute value of maxlen
93
93
  # until EOF is encountered.
@@ -99,9 +99,9 @@ class ::IO
99
99
  def splice(src, dest, maxlen)
100
100
  Polyphony.backend_splice(src, dest, maxlen)
101
101
  end
102
-
103
- # Creates a pipe and splices data between the two given IOs using the
104
- # pipe, splicing until EOF.
102
+
103
+ # Creates a pipe and splices data between the two given IOs, using the pipe,
104
+ # splicing until EOF.
105
105
  #
106
106
  # @param src [IO, Polyphony::Pipe] source to splice from
107
107
  # @param dest [IO, Polyphony::Pipe] destination to splice to
@@ -109,7 +109,7 @@ class ::IO
109
109
  def double_splice(src, dest)
110
110
  Polyphony.backend_double_splice(src, dest)
111
111
  end
112
-
112
+
113
113
  # Tees data from the source to the desination.
114
114
  #
115
115
  # @param src [IO, Polyphony::Pipe] source to tee from
@@ -125,7 +125,7 @@ class ::IO
125
125
  def double_splice(src, dest)
126
126
  raise NotImplementedError
127
127
  end
128
-
128
+
129
129
  # @!visibility private
130
130
  def tee(src, dest, maxlen)
131
131
  raise NotImplementedError
@@ -140,51 +140,51 @@ class ::IO
140
140
  def __read_method__
141
141
  :backend_read
142
142
  end
143
-
143
+
144
144
  # @!visibility private
145
145
  def __write_method__
146
146
  :backend_write
147
147
  end
148
-
148
+
149
149
  # def each(sep = $/, limit = nil, chomp: nil)
150
150
  # sep, limit = $/, sep if sep.is_a?(Integer)
151
151
  # end
152
152
  # alias_method :each_line, :each
153
-
153
+
154
154
  # def each_byte
155
155
  # end
156
-
156
+
157
157
  # def each_char
158
158
  # end
159
-
159
+
160
160
  # def each_codepoint
161
161
  # end
162
-
162
+
163
163
  # @!visibility private
164
164
  alias_method :orig_getbyte, :getbyte
165
-
166
-
165
+
166
+
167
167
  # @!visibility private
168
168
  def getbyte
169
169
  char = getc
170
- char ? char.getbyte(0) : nil
170
+ char&.getbyte(0)
171
171
  end
172
-
172
+
173
173
  # @!visibility private
174
174
  alias_method :orig_getc, :getc
175
-
176
-
175
+
176
+
177
177
  # @!visibility private
178
178
  def getc
179
179
  return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
180
-
180
+
181
181
  @read_buffer ||= +''
182
182
  Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
183
183
  return @read_buffer.slice!(0) if !@read_buffer.empty?
184
-
184
+
185
185
  nil
186
186
  end
187
-
187
+
188
188
  # @!visibility private
189
189
  def ungetc(c)
190
190
  c = c.chr if c.is_a?(Integer)
@@ -195,59 +195,59 @@ class ::IO
195
195
  end
196
196
  end
197
197
  alias_method :ungetbyte, :ungetc
198
-
198
+
199
199
  # @!visibility private
200
200
  alias_method :orig_read, :read
201
-
202
-
201
+
202
+
203
203
  # @!visibility private
204
204
  def read(len = nil, buf = nil, buf_pos = 0)
205
205
  return '' if len == 0
206
-
206
+
207
207
  if buf
208
208
  return Polyphony.backend_read(self, buf, len, true, buf_pos)
209
209
  end
210
-
210
+
211
211
  @read_buffer ||= +''
212
212
  result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
213
213
  return nil unless result
214
-
214
+
215
215
  already_read = @read_buffer
216
216
  @read_buffer = +''
217
217
  already_read
218
218
  end
219
-
219
+
220
220
  # @!visibility private
221
221
  alias_method :orig_readpartial, :read
222
-
222
+
223
223
  # @!visibility private
224
224
  def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
225
225
  result = Polyphony.backend_read(self, str, len, false, buffer_pos)
226
226
  raise EOFError if !result && raise_on_eof
227
-
227
+
228
228
  result
229
229
  end
230
-
230
+
231
231
  # @!visibility private
232
232
  alias_method :orig_write, :write
233
-
233
+
234
234
  # @!visibility private
235
235
  def write(str, *args)
236
236
  Polyphony.backend_write(self, str, *args)
237
237
  end
238
-
238
+
239
239
  # @!visibility private
240
240
  alias_method :orig_write_chevron, :<<
241
-
241
+
242
242
  # @!visibility private
243
243
  def <<(str)
244
244
  Polyphony.backend_write(self, str)
245
245
  self
246
246
  end
247
-
247
+
248
248
  # @!visibility private
249
249
  alias_method :orig_gets, :gets
250
-
250
+
251
251
  # @!visibility private
252
252
  def gets(sep = $/, _limit = nil, _chomp: nil)
253
253
  if sep.is_a?(Integer)
@@ -255,20 +255,20 @@ class ::IO
255
255
  _limit = sep
256
256
  end
257
257
  sep_size = sep.bytesize
258
-
258
+
259
259
  @read_buffer ||= +''
260
-
260
+
261
261
  while true
262
262
  idx = @read_buffer.index(sep)
263
263
  return @read_buffer.slice!(0, idx + sep_size) if idx
264
-
264
+
265
265
  result = readpartial(8192, @read_buffer, -1)
266
266
  return nil unless result
267
267
  end
268
268
  rescue EOFError
269
269
  return nil
270
270
  end
271
-
271
+
272
272
  # @!visibility private
273
273
  def each_line(sep = $/, limit = nil, chomp: false)
274
274
  if sep.is_a?(Integer)
@@ -276,48 +276,48 @@ class ::IO
276
276
  sep = $/
277
277
  end
278
278
  sep_size = sep.bytesize
279
-
280
-
279
+
280
+
281
281
  @read_buffer ||= +''
282
-
282
+
283
283
  while true
284
284
  while (idx = @read_buffer.index(sep))
285
285
  line = @read_buffer.slice!(0, idx + sep_size)
286
286
  line = line.chomp if chomp
287
287
  yield line
288
288
  end
289
-
289
+
290
290
  result = readpartial(8192, @read_buffer, -1)
291
291
  return self if !result
292
292
  end
293
293
  rescue EOFError
294
294
  return self
295
295
  end
296
-
296
+
297
297
  # def print(*args)
298
298
  # end
299
-
299
+
300
300
  # def printf(format, *args)
301
301
  # end
302
-
302
+
303
303
  # def putc(obj)
304
304
  # end
305
-
305
+
306
306
  # @!visibility private
307
307
  LINEFEED = "\n"
308
308
  # @!visibility private
309
309
  LINEFEED_RE = /\n$/.freeze
310
-
310
+
311
311
  # @!visibility private
312
312
  alias_method :orig_puts, :puts
313
-
313
+
314
314
  # @!visibility private
315
315
  def puts(*args)
316
316
  if args.empty?
317
317
  write LINEFEED
318
318
  return
319
319
  end
320
-
320
+
321
321
  idx = 0
322
322
  while idx < args.size
323
323
  arg = args[idx]
@@ -329,26 +329,26 @@ class ::IO
329
329
  idx += 2
330
330
  end
331
331
  end
332
-
332
+
333
333
  write(*args)
334
334
  nil
335
335
  end
336
-
336
+
337
337
  # def readbyte
338
338
  # end
339
-
339
+
340
340
  # def readchar
341
341
  # end
342
-
342
+
343
343
  # def readline(sep = $/, limit = nil, chomp: nil)
344
344
  # end
345
-
345
+
346
346
  # def readlines(sep = $/, limit = nil, chomp: nil)
347
347
  # end
348
-
348
+
349
349
  # @!visibility private
350
350
  alias_method :orig_write_nonblock, :write_nonblock
351
-
351
+
352
352
  # @!visibility private
353
353
  def write_nonblock(string, _options = {})
354
354
  write(string)
@@ -396,7 +396,7 @@ end
396
396
  # @return [IO] self
397
397
  def wait_readable(timeout = nil)
398
398
  return self if @read_buffer && @read_buffer.size > 0
399
-
399
+
400
400
  if timeout
401
401
  move_on_after(timeout) do
402
402
  Polyphony.backend_wait_io(self, false)
@@ -171,6 +171,12 @@ class ::Object
171
171
  Fiber.current.receive
172
172
  end
173
173
 
174
+ # Receives messages in an infinite loop from the current fiber's mailbox,
175
+ # passing them to the given block.
176
+ def receive_loop(&block)
177
+ Fiber.current.receive_loop(&block)
178
+ end
179
+
174
180
  # Returns all messages currently pending on the current fiber's mailbox.
175
181
  #
176
182
  # @return [Array] array of received messages
@@ -69,24 +69,24 @@ class ::Socket < ::BasicSocket
69
69
  # If no bytes are available and `EOF` is not hit, this method will block until
70
70
  # the socket is ready to read from.
71
71
  #
72
- # @param maxlen [Integer, nil] maximum bytes to read from socket
72
+ # @param len [Integer, nil] maximum bytes to read from socket
73
73
  # @param buf [String, nil] buffer to read into
74
74
  # @param buf_pos [Number] buffer position to read into
75
75
  # @return [String] buffer used for reading
76
- def read(maxlen = nil, buf = nil, buf_pos = 0)
77
- return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
78
- return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
76
+ def read(len = nil, buf = nil, buf_pos = 0)
77
+ return '' if len == 0
79
78
 
80
- buf = +''
81
- len = buf.bytesize
82
- while true
83
- Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
84
- new_len = buf.bytesize
85
- break if new_len == len
86
-
87
- len = new_len
79
+ if buf
80
+ return Polyphony.backend_read(self, buf, len, true, buf_pos)
88
81
  end
89
- buf
82
+
83
+ @read_buffer ||= +''
84
+ result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
85
+ return nil unless result
86
+
87
+ already_read = @read_buffer
88
+ @read_buffer = +''
89
+ already_read
90
90
  end
91
91
 
92
92
  # Receives up to `maxlen` bytes from the socket. If `outbuf` is given, it is
@@ -333,24 +333,24 @@ class ::TCPSocket < ::IPSocket
333
333
  # If no bytes are available and `EOF` is not hit, this method will block until
334
334
  # the socket is ready to read from.
335
335
  #
336
- # @param maxlen [Integer, nil] maximum bytes to read from socket
336
+ # @param len [Integer, nil] maximum bytes to read from socket
337
337
  # @param buf [String, nil] buffer to read into
338
338
  # @param buf_pos [Number] buffer position to read into
339
339
  # @return [String] buffer used for reading
340
- def read(maxlen = nil, buf = nil, buf_pos = 0)
341
- return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
342
- return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
343
-
344
- buf = +''
345
- len = buf.bytesize
346
- while true
347
- Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
348
- new_len = buf.bytesize
349
- break if new_len == len
340
+ def read(len = nil, buf = nil, buf_pos = 0)
341
+ return '' if len == 0
350
342
 
351
- len = new_len
343
+ if buf
344
+ return Polyphony.backend_read(self, buf, len, true, buf_pos)
352
345
  end
353
- buf
346
+
347
+ @read_buffer ||= +''
348
+ result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
349
+ return nil unless result
350
+
351
+ already_read = @read_buffer
352
+ @read_buffer = +''
353
+ already_read
354
354
  end
355
355
 
356
356
  # Receives up to `maxlen` bytes from the socket. If `outbuf` is given, it is
@@ -542,24 +542,24 @@ class ::UNIXSocket < ::BasicSocket
542
542
  # If no bytes are available and `EOF` is not hit, this method will block until
543
543
  # the socket is ready to read from.
544
544
  #
545
- # @param maxlen [Integer, nil] maximum bytes to read from socket
545
+ # @param len [Integer, nil] maximum bytes to read from socket
546
546
  # @param buf [String, nil] buffer to read into
547
547
  # @param buf_pos [Number] buffer position to read into
548
548
  # @return [String] buffer used for reading
549
- def read(maxlen = nil, buf = nil, buf_pos = 0)
550
- return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
551
- return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
549
+ def read(len = nil, buf = nil, buf_pos = 0)
550
+ return '' if len == 0
552
551
 
553
- buf = +''
554
- len = buf.bytesize
555
- while true
556
- Polyphony.backend_recv(self, buf, maxlen || 4096, -1)
557
- new_len = buf.bytesize
558
- break if new_len == len
559
-
560
- len = new_len
552
+ if buf
553
+ return Polyphony.backend_read(self, buf, len, true, buf_pos)
561
554
  end
562
- buf
555
+
556
+ @read_buffer ||= +''
557
+ result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
558
+ return nil unless result
559
+
560
+ already_read = @read_buffer
561
+ @read_buffer = +''
562
+ already_read
563
563
  end
564
564
 
565
565
  # Receives up to `maxlen` bytes from the socket. If `outbuf` is given, it is
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Polyphony
4
4
  # @!visibility private
5
- VERSION = '1.0.1'
5
+ VERSION = '1.1'
6
6
  end
data/polyphony.gemspec CHANGED
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.summary = 'Fine grained concurrency for Ruby'
8
8
  s.author = 'Sharon Rosner'
9
9
  s.email = 'sharon@noteflakes.com'
10
- s.files = `git ls-files --recurse-submodules`.split
10
+ s.files = `git ls-files --recurse-submodules`.split.reject { |fn| fn =~ /liburing\/man/ }
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",
@@ -29,4 +29,6 @@ Gem::Specification.new do |s|
29
29
  s.add_development_dependency 'msgpack', '1.6.0'
30
30
  s.add_development_dependency 'httparty', '0.21.0'
31
31
  s.add_development_dependency 'localhost', '1.1.10'
32
+ s.add_development_dependency 'debug', '1.8.0'
33
+ s.add_development_dependency 'benchmark-ips', '2.10.0'
32
34
  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'
6
+ $test_cmd = +'ruby test/test_scenarios.rb'
7
7
  if test_name
8
8
  $test_cmd << " --name #{test_name}"
9
9
  end