polyphony 0.99 → 0.99.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -1
- data/.rubocop.yml +3 -3
- data/.yardopts +30 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE +1 -1
- data/README.md +63 -29
- data/Rakefile +1 -5
- data/TODO.md +0 -4
- data/docs/{main-concepts/concurrency.md → concurrency.md} +2 -9
- data/docs/{main-concepts/design-principles.md → design-principles.md} +3 -9
- data/docs/{main-concepts/exception-handling.md → exception-handling.md} +2 -9
- data/docs/{main-concepts/extending.md → extending.md} +2 -9
- data/docs/faq.md +3 -16
- data/docs/{main-concepts/fiber-scheduling.md → fiber-scheduling.md} +1 -9
- data/docs/link_rewriter.rb +16 -0
- data/docs/{getting-started/overview.md → overview.md} +1 -30
- data/docs/{getting-started/tutorial.md → tutorial.md} +3 -28
- data/docs/{_posts/2020-07-26-polyphony-0.44.md → whats-new.md} +3 -1
- data/examples/adapters/redis_client.rb +3 -2
- data/examples/io/echo_server.rb +1 -1
- data/examples/io/echo_server_plain_ruby.rb +26 -0
- data/ext/polyphony/backend_io_uring.c +154 -9
- data/ext/polyphony/backend_io_uring_context.c +21 -12
- data/ext/polyphony/backend_io_uring_context.h +12 -7
- data/ext/polyphony/backend_libev.c +1 -1
- data/ext/polyphony/extconf.rb +24 -8
- data/ext/polyphony/fiber.c +79 -2
- data/ext/polyphony/io_extensions.c +53 -0
- data/ext/polyphony/pipe.c +42 -2
- data/ext/polyphony/polyphony.c +345 -31
- data/ext/polyphony/polyphony.h +9 -2
- data/ext/polyphony/queue.c +181 -0
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/runqueue.c +8 -1
- data/ext/polyphony/runqueue_ring_buffer.c +13 -0
- data/ext/polyphony/runqueue_ring_buffer.h +2 -1
- data/ext/polyphony/socket_extensions.c +6 -0
- data/ext/polyphony/thread.c +34 -2
- data/lib/polyphony/adapters/process.rb +11 -1
- data/lib/polyphony/adapters/sequel.rb +1 -1
- data/lib/polyphony/core/channel.rb +2 -0
- data/lib/polyphony/core/debug.rb +1 -1
- data/lib/polyphony/core/global_api.rb +25 -24
- data/lib/polyphony/core/resource_pool.rb +7 -6
- data/lib/polyphony/core/sync.rb +2 -2
- data/lib/polyphony/core/thread_pool.rb +3 -3
- data/lib/polyphony/core/timer.rb +8 -8
- data/lib/polyphony/extensions/exception.rb +2 -0
- data/lib/polyphony/extensions/fiber.rb +15 -13
- data/lib/polyphony/extensions/io.rb +127 -5
- data/lib/polyphony/extensions/kernel.rb +20 -2
- data/lib/polyphony/extensions/openssl.rb +100 -11
- data/lib/polyphony/extensions/pipe.rb +103 -7
- data/lib/polyphony/extensions/process.rb +13 -1
- data/lib/polyphony/extensions/socket.rb +93 -27
- data/lib/polyphony/extensions/thread.rb +9 -1
- data/lib/polyphony/extensions/timeout.rb +1 -1
- data/lib/polyphony/version.rb +2 -1
- data/lib/polyphony.rb +27 -7
- data/polyphony.gemspec +1 -8
- data/test/stress.rb +1 -1
- data/test/test_global_api.rb +45 -7
- data/test/test_socket.rb +96 -0
- data/test/test_timer.rb +5 -5
- metadata +17 -40
- data/docs/_config.yml +0 -64
- data/docs/_includes/head.html +0 -40
- data/docs/_includes/title.html +0 -1
- data/docs/_sass/custom/custom.scss +0 -10
- data/docs/_sass/overrides.scss +0 -0
- data/docs/api-reference/exception.md +0 -31
- data/docs/api-reference/fiber.md +0 -425
- data/docs/api-reference/index.md +0 -9
- data/docs/api-reference/io.md +0 -36
- data/docs/api-reference/object.md +0 -99
- data/docs/api-reference/polyphony-baseexception.md +0 -33
- data/docs/api-reference/polyphony-cancel.md +0 -26
- data/docs/api-reference/polyphony-moveon.md +0 -24
- data/docs/api-reference/polyphony-net.md +0 -20
- data/docs/api-reference/polyphony-process.md +0 -28
- data/docs/api-reference/polyphony-resourcepool.md +0 -59
- data/docs/api-reference/polyphony-restart.md +0 -18
- data/docs/api-reference/polyphony-terminate.md +0 -18
- data/docs/api-reference/polyphony-threadpool.md +0 -67
- data/docs/api-reference/polyphony-throttler.md +0 -77
- data/docs/api-reference/polyphony.md +0 -36
- data/docs/api-reference/thread.md +0 -88
- data/docs/favicon.ico +0 -0
- data/docs/getting-started/index.md +0 -10
- data/docs/getting-started/installing.md +0 -34
- /data/{docs/assets/img → assets}/echo-fibers.svg +0 -0
- /data/{docs → assets}/polyphony-logo.png +0 -0
- /data/{docs/assets/img → assets}/sleeping-fiber.svg +0 -0
|
@@ -5,30 +5,40 @@ require_relative './socket'
|
|
|
5
5
|
|
|
6
6
|
# OpenSSL socket helper methods (to make it compatible with Socket API) and overrides
|
|
7
7
|
class ::OpenSSL::SSL::SSLSocket
|
|
8
|
+
# @!visibility private
|
|
8
9
|
def __read_method__
|
|
9
10
|
:readpartial
|
|
10
11
|
end
|
|
11
12
|
|
|
13
|
+
# @!visibility private
|
|
12
14
|
alias_method :orig_initialize, :initialize
|
|
13
15
|
|
|
14
|
-
#
|
|
16
|
+
# Initializese a new SSL socket
|
|
17
|
+
#
|
|
18
|
+
# @param socket [TCPSocket] socket to wrap
|
|
19
|
+
# @param context [OpenSSL::SSL::SSLContext] optional SSL context
|
|
20
|
+
# @return [void]
|
|
15
21
|
def initialize(socket, context = nil)
|
|
16
22
|
socket = socket.respond_to?(:io) ? socket.io || socket : socket
|
|
17
23
|
context ? orig_initialize(socket, context) : orig_initialize(socket)
|
|
18
24
|
end
|
|
19
25
|
|
|
26
|
+
# Sets DONT_LINGER option
|
|
20
27
|
def dont_linger
|
|
21
28
|
io.dont_linger
|
|
22
29
|
end
|
|
23
30
|
|
|
31
|
+
# Sets NO_DELAY option
|
|
24
32
|
def no_delay
|
|
25
33
|
io.no_delay
|
|
26
34
|
end
|
|
27
35
|
|
|
36
|
+
# Sets REUSE_ADDR option
|
|
28
37
|
def reuse_addr
|
|
29
38
|
io.reuse_addr
|
|
30
39
|
end
|
|
31
40
|
|
|
41
|
+
# @!visibility private
|
|
32
42
|
def fill_rbuff
|
|
33
43
|
data = self.sysread(BLOCK_SIZE)
|
|
34
44
|
if data
|
|
@@ -38,7 +48,10 @@ class ::OpenSSL::SSL::SSLSocket
|
|
|
38
48
|
end
|
|
39
49
|
end
|
|
40
50
|
|
|
51
|
+
# @!visibility private
|
|
41
52
|
alias_method :orig_sysread, :sysread
|
|
53
|
+
|
|
54
|
+
# @!visibility private
|
|
42
55
|
def sysread(maxlen, buf = +'')
|
|
43
56
|
# ensure socket is non blocking
|
|
44
57
|
Polyphony.backend_verify_blocking_mode(io, false)
|
|
@@ -51,7 +64,10 @@ class ::OpenSSL::SSL::SSLSocket
|
|
|
51
64
|
end
|
|
52
65
|
end
|
|
53
66
|
|
|
67
|
+
# @!visibility private
|
|
54
68
|
alias_method :orig_syswrite, :syswrite
|
|
69
|
+
|
|
70
|
+
# @!visibility private
|
|
55
71
|
def syswrite(buf)
|
|
56
72
|
# ensure socket is non blocking
|
|
57
73
|
Polyphony.backend_verify_blocking_mode(io, false)
|
|
@@ -65,16 +81,35 @@ class ::OpenSSL::SSL::SSLSocket
|
|
|
65
81
|
end
|
|
66
82
|
end
|
|
67
83
|
|
|
84
|
+
# @!visibility private
|
|
68
85
|
def flush
|
|
69
|
-
#
|
|
70
|
-
# @sync = true
|
|
71
|
-
# do_write ""
|
|
72
|
-
# return self
|
|
73
|
-
# ensure
|
|
74
|
-
# @sync = osync
|
|
86
|
+
# warn "SSLSocket#flush is not yet implemented in Polyphony"
|
|
75
87
|
end
|
|
76
88
|
|
|
89
|
+
# @!visibility private
|
|
77
90
|
alias_method :orig_read, :read
|
|
91
|
+
|
|
92
|
+
# call-seq:
|
|
93
|
+
# socket.read -> string
|
|
94
|
+
# socket.read(maxlen) -> string
|
|
95
|
+
# socket.read(maxlen, buf) -> buf
|
|
96
|
+
# socket.read(maxlen, buf, buf_pos) -> buf
|
|
97
|
+
#
|
|
98
|
+
# Reads from the socket. If `maxlen` is given, reads up to `maxlen` bytes from
|
|
99
|
+
# the socket, otherwise reads to `EOF`. If `buf` is given, it is used as the
|
|
100
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
|
101
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
|
102
|
+
# given buffer offset is negative, it is calculated from the current end of
|
|
103
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
|
104
|
+
# buffer).
|
|
105
|
+
#
|
|
106
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
|
107
|
+
# the socket is ready to read from.
|
|
108
|
+
#
|
|
109
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
|
110
|
+
# @param buf [String, nil] buffer to read into
|
|
111
|
+
# @param buf_pos [Number] buffer position to read into
|
|
112
|
+
# @return [String] buffer used for reading
|
|
78
113
|
def read(maxlen = nil, buf = nil, buf_pos = 0)
|
|
79
114
|
return readpartial(maxlen, buf, buf_pos) if buf
|
|
80
115
|
|
|
@@ -88,13 +123,35 @@ class ::OpenSSL::SSL::SSLSocket
|
|
|
88
123
|
buf
|
|
89
124
|
end
|
|
90
125
|
|
|
91
|
-
|
|
92
|
-
|
|
126
|
+
# call-seq:
|
|
127
|
+
# socket.readpartial(maxlen) -> string
|
|
128
|
+
# socket.readpartial(maxlen, buf) -> buf
|
|
129
|
+
# socket.readpartial(maxlen, buf, buf_pos) -> buf
|
|
130
|
+
# socket.readpartial(maxlen, buf, buf_pos, raise_on_eof) -> buf
|
|
131
|
+
#
|
|
132
|
+
# Reads up to `maxlen` from the socket. If `buf` is given, it is used as the
|
|
133
|
+
# buffer to read into, otherwise a new string is allocated. If `buf_pos` is
|
|
134
|
+
# given, reads into the given offset (in bytes) in the given buffer. If the
|
|
135
|
+
# given buffer offset is negative, it is calculated from the current end of
|
|
136
|
+
# the buffer (`-1` means the read data will be appended to the end of the
|
|
137
|
+
# buffer). If `raise_on_eof` is `true` (the default,) an `EOFError` will be
|
|
138
|
+
# raised on `EOF`, otherwise `nil` will be returned.
|
|
139
|
+
#
|
|
140
|
+
# If no bytes are available and `EOF` is not hit, this method will block until
|
|
141
|
+
# the socket is ready to read from.
|
|
142
|
+
#
|
|
143
|
+
# @param maxlen [Integer, nil] maximum bytes to read from socket
|
|
144
|
+
# @param buf [String, nil] buffer to read into
|
|
145
|
+
# @param buf_pos [Number] buffer position to read into
|
|
146
|
+
# @param raise_on_eof [bool] whether to raise an exception on `EOF`
|
|
147
|
+
# @return [String, nil] buffer used for reading or nil on `EOF`
|
|
148
|
+
def readpartial(maxlen, buf = +'', buf_pos = 0, raise_on_eof = true)
|
|
149
|
+
if buf_pos != 0
|
|
93
150
|
if (result = sysread(maxlen, +''))
|
|
94
|
-
if
|
|
151
|
+
if buf_pos == -1
|
|
95
152
|
result = buf + result
|
|
96
153
|
else
|
|
97
|
-
result = buf[0...
|
|
154
|
+
result = buf[0...buf_pos] + result
|
|
98
155
|
end
|
|
99
156
|
end
|
|
100
157
|
else
|
|
@@ -105,6 +162,18 @@ class ::OpenSSL::SSL::SSLSocket
|
|
|
105
162
|
result
|
|
106
163
|
end
|
|
107
164
|
|
|
165
|
+
# call-seq:
|
|
166
|
+
# socket.recv_loop { |data| ... }
|
|
167
|
+
# socket.recv_loop(maxlen) { |data| ... }
|
|
168
|
+
# socket.read_loop { |data| ... }
|
|
169
|
+
# socket.read_loop(maxlen) { |data| ... }
|
|
170
|
+
#
|
|
171
|
+
# Receives up to `maxlen` bytes at a time in an infinite loop. Read buffers
|
|
172
|
+
# will be passed to the given block.
|
|
173
|
+
#
|
|
174
|
+
# @param maxlen [Integer] maximum bytes to receive
|
|
175
|
+
# @yield [String] handler block
|
|
176
|
+
# @return [void]
|
|
108
177
|
def read_loop(maxlen = 8192)
|
|
109
178
|
while (data = sysread(maxlen))
|
|
110
179
|
yield data
|
|
@@ -112,7 +181,10 @@ class ::OpenSSL::SSL::SSLSocket
|
|
|
112
181
|
end
|
|
113
182
|
alias_method :recv_loop, :read_loop
|
|
114
183
|
|
|
184
|
+
# @!visibility private
|
|
115
185
|
alias_method :orig_peeraddr, :peeraddr
|
|
186
|
+
|
|
187
|
+
# @!visibility private
|
|
116
188
|
def peeraddr(_ = nil)
|
|
117
189
|
orig_peeraddr
|
|
118
190
|
end
|
|
@@ -122,7 +194,12 @@ end
|
|
|
122
194
|
class ::OpenSSL::SSL::SSLServer
|
|
123
195
|
attr_reader :ctx
|
|
124
196
|
|
|
197
|
+
# @!visibility private
|
|
125
198
|
alias_method :orig_accept, :accept
|
|
199
|
+
|
|
200
|
+
# Accepts a new connection and performs SSL handshake.
|
|
201
|
+
#
|
|
202
|
+
# @return [OpenSSL::SSL::SSLSocket] accepted SSL connection
|
|
126
203
|
def accept
|
|
127
204
|
# when @ctx.servername_cb is set, we use a worker thread to run the
|
|
128
205
|
# ssl.accept call. We need to do this because:
|
|
@@ -165,6 +242,7 @@ class ::OpenSSL::SSL::SSLServer
|
|
|
165
242
|
end
|
|
166
243
|
end
|
|
167
244
|
|
|
245
|
+
# @!visibility private
|
|
168
246
|
def start_accept_worker_thread
|
|
169
247
|
fiber = Fiber.current
|
|
170
248
|
@accept_worker_thread = Thread.new do
|
|
@@ -187,16 +265,27 @@ class ::OpenSSL::SSL::SSLServer
|
|
|
187
265
|
@accept_worker_fiber = receive
|
|
188
266
|
end
|
|
189
267
|
|
|
268
|
+
# @!visibility private
|
|
190
269
|
def use_accept_worker_thread?
|
|
191
270
|
!!@ctx.servername_cb
|
|
192
271
|
end
|
|
193
272
|
|
|
273
|
+
# @!visibility private
|
|
194
274
|
alias_method :orig_close, :close
|
|
275
|
+
|
|
276
|
+
# @!visibility private
|
|
195
277
|
def close
|
|
196
278
|
@accept_worker_thread&.kill
|
|
197
279
|
orig_close
|
|
198
280
|
end
|
|
199
281
|
|
|
282
|
+
# call-seq:
|
|
283
|
+
# socket.accept_loop { |conn| ... }
|
|
284
|
+
#
|
|
285
|
+
# Accepts incoming connections in an infinite loop.
|
|
286
|
+
#
|
|
287
|
+
# @yield [OpenSSL::SSL::SSLSocket] block receiving accepted sockets
|
|
288
|
+
# @return [void]
|
|
200
289
|
def accept_loop(ignore_errors = true)
|
|
201
290
|
loop do
|
|
202
291
|
yield accept
|
|
@@ -1,20 +1,32 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Pipe instance
|
|
3
|
+
# A Pipe instance represents a UNIX pipe that can be read and written to. This
|
|
4
|
+
# API is an alternative to the `IO.pipe` API, that returns two separate fds, one
|
|
5
|
+
# for reading and one for writing. Instead, `Polyphony::Pipe` encapsulates the
|
|
6
|
+
# two fds in a single object, providing methods that enable us to treat the pipe
|
|
7
|
+
# as a normal IO object.
|
|
4
8
|
class Polyphony::Pipe
|
|
9
|
+
# @!visibility private
|
|
5
10
|
def __read_method__
|
|
6
11
|
:backend_read
|
|
7
12
|
end
|
|
8
13
|
|
|
14
|
+
# @!visibility private
|
|
9
15
|
def __write_method__
|
|
10
16
|
:backend_write
|
|
11
17
|
end
|
|
12
18
|
|
|
19
|
+
# Reads a single byte from the pipe.
|
|
20
|
+
#
|
|
21
|
+
# @return [Integer, nil] byte value
|
|
13
22
|
def getbyte
|
|
14
23
|
char = getc
|
|
15
24
|
char ? char.getbyte(0) : nil
|
|
16
25
|
end
|
|
17
26
|
|
|
27
|
+
# Reads a single character from the pipe.
|
|
28
|
+
#
|
|
29
|
+
# @return |String, nil] read character
|
|
18
30
|
def getc
|
|
19
31
|
return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
|
|
20
32
|
|
|
@@ -25,6 +37,12 @@ class Polyphony::Pipe
|
|
|
25
37
|
nil
|
|
26
38
|
end
|
|
27
39
|
|
|
40
|
+
# Reads from the pipe.
|
|
41
|
+
#
|
|
42
|
+
# @param len [Integer, nil] maximum bytes to read
|
|
43
|
+
# @param buf [String, nil] buffer to read into
|
|
44
|
+
# @param buf_pos [Integer] buffer position to read into
|
|
45
|
+
# @return [String] read data
|
|
28
46
|
def read(len = nil, buf = nil, buf_pos = 0)
|
|
29
47
|
if buf
|
|
30
48
|
return Polyphony.backend_read(self, buf, len, true, buf_pos)
|
|
@@ -39,22 +57,48 @@ class Polyphony::Pipe
|
|
|
39
57
|
already_read
|
|
40
58
|
end
|
|
41
59
|
|
|
42
|
-
|
|
43
|
-
|
|
60
|
+
# Reads from the pipe.
|
|
61
|
+
#
|
|
62
|
+
# @param len [Integer, nil] maximum bytes to read
|
|
63
|
+
# @param buf [String, nil] buffer to read into
|
|
64
|
+
# @param buf_pos [Integer] buffer position to read into
|
|
65
|
+
# @param raise_on_eof [boolean] whether to raise an error if EOF is detected
|
|
66
|
+
# @return [String] read data
|
|
67
|
+
def readpartial(len, buf = +'', buf_pos = 0, raise_on_eof = true)
|
|
68
|
+
result = Polyphony.backend_read(self, buf, len, false, buf_pos)
|
|
44
69
|
raise EOFError if !result && raise_on_eof
|
|
45
70
|
|
|
46
71
|
result
|
|
47
72
|
end
|
|
48
73
|
|
|
49
|
-
|
|
50
|
-
|
|
74
|
+
# Writes to the pipe.
|
|
75
|
+
|
|
76
|
+
# @param buf [String] data to write
|
|
77
|
+
# @param args [any] further arguments to pass to Polyphony.backend_write
|
|
78
|
+
# @return [Integer] bytes written
|
|
79
|
+
def write(buf, *args)
|
|
80
|
+
Polyphony.backend_write(self, buf, *args)
|
|
51
81
|
end
|
|
52
82
|
|
|
53
|
-
|
|
54
|
-
|
|
83
|
+
# Writes to the pipe.
|
|
84
|
+
|
|
85
|
+
# @param buf [String] data to write
|
|
86
|
+
# @return [Integer] bytes written
|
|
87
|
+
def <<(buf)
|
|
88
|
+
Polyphony.backend_write(self, buf)
|
|
55
89
|
self
|
|
56
90
|
end
|
|
57
91
|
|
|
92
|
+
# call-seq:
|
|
93
|
+
# pipe.gets(limit, chomp)
|
|
94
|
+
# pipe.gets(separator, limit, chomp)
|
|
95
|
+
#
|
|
96
|
+
# Reads a single line from the pipe.
|
|
97
|
+
#
|
|
98
|
+
# @param sep [String] line separator
|
|
99
|
+
# @param _limit [Integer, nil] line length limit
|
|
100
|
+
# @param _chomp [boolean, nil] whether to chomp the read line
|
|
101
|
+
# @return [String, nil] read line
|
|
58
102
|
def gets(sep = $/, _limit = nil, _chomp: nil)
|
|
59
103
|
if sep.is_a?(Integer)
|
|
60
104
|
sep = $/
|
|
@@ -84,9 +128,14 @@ class Polyphony::Pipe
|
|
|
84
128
|
# def putc(obj)
|
|
85
129
|
# end
|
|
86
130
|
|
|
131
|
+
# @!visibility private
|
|
87
132
|
LINEFEED = "\n"
|
|
133
|
+
# @!visibility private
|
|
88
134
|
LINEFEED_RE = /\n$/.freeze
|
|
89
135
|
|
|
136
|
+
# Writes a line with line feed to the pipe.
|
|
137
|
+
#
|
|
138
|
+
# @param args [Array] zero or more lines
|
|
90
139
|
def puts(*args)
|
|
91
140
|
if args.empty?
|
|
92
141
|
write LINEFEED
|
|
@@ -121,22 +170,55 @@ class Polyphony::Pipe
|
|
|
121
170
|
# def readlines(sep = $/, limit = nil, chomp: nil)
|
|
122
171
|
# end
|
|
123
172
|
|
|
173
|
+
# @!visibility private
|
|
124
174
|
def write_nonblock(string, _options = {})
|
|
125
175
|
write(string)
|
|
126
176
|
end
|
|
127
177
|
|
|
178
|
+
# @!visibility private
|
|
128
179
|
def read_nonblock(maxlen, buf = nil, _options = nil)
|
|
129
180
|
buf ? readpartial(maxlen, buf) : readpartial(maxlen)
|
|
130
181
|
end
|
|
131
182
|
|
|
183
|
+
# Runs a read loop.
|
|
184
|
+
#
|
|
185
|
+
# @param maxlen [Integer] maximum bytes to read
|
|
186
|
+
# @yield [String] read block
|
|
187
|
+
# @return [void]
|
|
132
188
|
def read_loop(maxlen = 8192, &block)
|
|
133
189
|
Polyphony.backend_read_loop(self, maxlen, &block)
|
|
134
190
|
end
|
|
135
191
|
|
|
192
|
+
# call-seq:
|
|
193
|
+
# pipe.feed_loop(receiver, method)
|
|
194
|
+
# pipe.feed_loop(receiver, method) { |result| ... }
|
|
195
|
+
#
|
|
196
|
+
# Receives data from the pipe in an infinite loop, passing the data to the
|
|
197
|
+
# given receiver using the given method. If a block is given, the result of
|
|
198
|
+
# the method call to the receiver is passed to the block.
|
|
199
|
+
#
|
|
200
|
+
# This method can be used to feed data into parser objects. The following
|
|
201
|
+
# example shows how to feed data from a pipe directly into a MessagePack
|
|
202
|
+
# unpacker:
|
|
203
|
+
#
|
|
204
|
+
# unpacker = MessagePack::Unpacker.new
|
|
205
|
+
# buffer = []
|
|
206
|
+
# reader = spin do
|
|
207
|
+
# pipe.feed_loop(unpacker, :feed_each) { |msg| handle_msg(msg) }
|
|
208
|
+
# end
|
|
209
|
+
#
|
|
210
|
+
# @param receiver [any] receiver object
|
|
211
|
+
# @param method [Symbol] method to call
|
|
212
|
+
# @yield [any] block to handle result of method call to receiver
|
|
213
|
+
# @return [void]
|
|
136
214
|
def feed_loop(receiver, method = :call, &block)
|
|
137
215
|
Polyphony.backend_feed_loop(self, receiver, method, &block)
|
|
138
216
|
end
|
|
139
217
|
|
|
218
|
+
# Waits for pipe to become readable.
|
|
219
|
+
#
|
|
220
|
+
# @param timeout [Number, nil] optional timeout in seconds
|
|
221
|
+
# @return [Polyphony::Pipe] self
|
|
140
222
|
def wait_readable(timeout = nil)
|
|
141
223
|
if timeout
|
|
142
224
|
move_on_after(timeout) do
|
|
@@ -149,6 +231,10 @@ class Polyphony::Pipe
|
|
|
149
231
|
end
|
|
150
232
|
end
|
|
151
233
|
|
|
234
|
+
# Waits for pipe to become writeable.
|
|
235
|
+
#
|
|
236
|
+
# @param timeout [Number, nil] optional timeout in seconds
|
|
237
|
+
# @return [Polyphony::Pipe] self
|
|
152
238
|
def wait_writable(timeout = nil)
|
|
153
239
|
if timeout
|
|
154
240
|
move_on_after(timeout) do
|
|
@@ -161,11 +247,21 @@ class Polyphony::Pipe
|
|
|
161
247
|
end
|
|
162
248
|
end
|
|
163
249
|
|
|
250
|
+
# Splices to the pipe from the given source.
|
|
251
|
+
#
|
|
252
|
+
# @param src [IO] source to splice from
|
|
253
|
+
# @param maxlen [Integer] maximum bytes to splice
|
|
254
|
+
# @return [Integer] bytes spliced
|
|
164
255
|
def splice_from(src, maxlen)
|
|
165
256
|
Polyphony.backend_splice(src, self, maxlen)
|
|
166
257
|
end
|
|
167
258
|
|
|
168
259
|
if RUBY_PLATFORM =~ /linux/
|
|
260
|
+
# Tees to the pipe from the given source.
|
|
261
|
+
#
|
|
262
|
+
# @param src [IO] source to tee from
|
|
263
|
+
# @param maxlen [Integer] maximum bytes to tee
|
|
264
|
+
# @return [Integer] bytes teed
|
|
169
265
|
def tee_from(src, maxlen)
|
|
170
266
|
Polyphony.backend_tee(src, self, maxlen)
|
|
171
267
|
end
|
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
# Overrides for Process
|
|
3
|
+
# Overrides for Process module
|
|
4
4
|
module ::Process
|
|
5
5
|
class << self
|
|
6
|
+
# @!visibility private
|
|
6
7
|
alias_method :orig_detach, :detach
|
|
8
|
+
|
|
9
|
+
# Detaches the given pid and returns a fiber waiting on it.
|
|
10
|
+
#
|
|
11
|
+
# @param pid [Integer] child pid
|
|
12
|
+
# @return [Fiber] new fiber waiting on pid
|
|
7
13
|
def detach(pid)
|
|
8
14
|
fiber = spin { Polyphony.backend_waitpid(pid) }
|
|
9
15
|
fiber.define_singleton_method(:pid) { pid }
|
|
10
16
|
fiber
|
|
11
17
|
end
|
|
12
18
|
|
|
19
|
+
# @!visibility private
|
|
13
20
|
alias_method :orig_daemon, :daemon
|
|
21
|
+
|
|
22
|
+
# Starts a daemon with the given arguments.
|
|
23
|
+
#
|
|
24
|
+
# @param args [any] arguments to pass to daemon
|
|
25
|
+
# @return [Integer] daemon pid
|
|
14
26
|
def daemon(*args)
|
|
15
27
|
orig_daemon(*args)
|
|
16
28
|
Polyphony.original_pid = Process.pid
|