polyphony 0.99 → 0.99.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|