polyphony 0.99.3 → 0.99.5
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/.rubocop.yml +10 -0
- data/.yardopts +3 -1
- data/README.md +1 -1
- data/docs/readme.md +102 -0
- data/examples/pipes/gzip_http_server.rb +2 -2
- data/examples/pipes/http_server.rb +1 -1
- data/examples/pipes/tcp_proxy.rb +1 -1
- data/ext/polyphony/backend_common.c +4 -4
- data/ext/polyphony/backend_io_uring.c +8 -8
- data/ext/polyphony/backend_libev.c +5 -5
- data/ext/polyphony/fiber.c +32 -41
- data/ext/polyphony/io_extensions.c +50 -37
- data/ext/polyphony/pipe.c +6 -18
- data/ext/polyphony/polyphony.c +63 -133
- data/ext/polyphony/queue.c +25 -63
- data/ext/polyphony/thread.c +3 -12
- data/lib/polyphony/adapters/process.rb +1 -2
- data/lib/polyphony/adapters/sequel.rb +2 -2
- data/lib/polyphony/core/debug.rb +1 -1
- data/lib/polyphony/core/exceptions.rb +1 -1
- data/lib/polyphony/core/global_api.rb +24 -38
- data/lib/polyphony/core/resource_pool.rb +7 -8
- data/lib/polyphony/core/sync.rb +1 -2
- data/lib/polyphony/core/thread_pool.rb +2 -5
- data/lib/polyphony/core/throttler.rb +1 -5
- data/lib/polyphony/core/timer.rb +24 -25
- data/lib/polyphony/extensions/fiber.rb +507 -540
- data/lib/polyphony/extensions/io.rb +3 -12
- data/lib/polyphony/extensions/openssl.rb +2 -23
- data/lib/polyphony/extensions/pipe.rb +4 -15
- data/lib/polyphony/extensions/socket.rb +15 -109
- data/lib/polyphony/extensions/thread.rb +0 -13
- data/lib/polyphony/extensions/timeout.rb +0 -1
- data/lib/polyphony/net.rb +5 -8
- data/lib/polyphony/version.rb +1 -1
- data/lib/polyphony.rb +2 -6
- data/test/test_io.rb +221 -221
- data/test/test_socket.rb +3 -3
- data/test/test_trace.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d73317fd0bed90e2966bcf71e0f89d13318c21a4d235127162c3ed1d4f7ee2ea
|
4
|
+
data.tar.gz: bad470bf595168aec1e8cac95b6b707d82a1f10a4e9c2cdc33d35194d0bb4a53
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e64aafec751da5932e1782acd28a29c6661ae76a223b9edaa6445b1d4c2728b2a185a98b86d4d87ace5ca35522030d68b902b0679c95dfd82783e3f12d8d9a8
|
7
|
+
data.tar.gz: bdac913bc057e31cb51f47b6624e62e59f071db050480a64f73a5273a187243944487df86383d4970e1082a2032f624205791ab7b43f98f64385bccf6918ac8a
|
data/.rubocop.yml
CHANGED
@@ -85,6 +85,7 @@ Metrics/MethodLength:
|
|
85
85
|
Exclude:
|
86
86
|
- lib/polyphony/http/server/rack.rb
|
87
87
|
- lib/polyphony/extensions/io.rb
|
88
|
+
- lib/polyphony/extensions/fiber.rb
|
88
89
|
- test/**/*.rb
|
89
90
|
- examples/**/*.rb
|
90
91
|
|
@@ -97,9 +98,18 @@ Metrics/ClassLength:
|
|
97
98
|
Exclude:
|
98
99
|
- lib/polyphony/http/server/http1.rb
|
99
100
|
- lib/polyphony/extensions/io.rb
|
101
|
+
- lib/polyphony/extensions/fiber.rb
|
100
102
|
- test/**/*.rb
|
101
103
|
- examples/**/*.rb
|
102
104
|
|
105
|
+
Metrics/CyclomaticComplexity:
|
106
|
+
Exclude:
|
107
|
+
- lib/polyphony/extensions/fiber.rb
|
108
|
+
|
109
|
+
Metrics/PerceivedComplexity:
|
110
|
+
Exclude:
|
111
|
+
- lib/polyphony/extensions/fiber.rb
|
112
|
+
|
103
113
|
Style/RegexpLiteral:
|
104
114
|
Enabled: false
|
105
115
|
|
data/.yardopts
CHANGED
@@ -14,10 +14,12 @@
|
|
14
14
|
--exclude sequel.rb
|
15
15
|
--exclude event.c
|
16
16
|
--exclude backend.+\.c
|
17
|
-
--load ./docs/link_rewriter.rb
|
17
|
+
# --load ./docs/link_rewriter.rb
|
18
|
+
-r docs/readme.md
|
18
19
|
./lib
|
19
20
|
./ext/polyphony
|
20
21
|
-
|
22
|
+
docs/readme.md
|
21
23
|
docs/overview.md
|
22
24
|
docs/tutorial.md
|
23
25
|
docs/faq.md
|
data/README.md
CHANGED
data/docs/readme.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# @title README
|
2
|
+
|
3
|
+
<img src="https://github.com/digital-fabric/polyphony/raw/master/assets/polyphony-logo.png">
|
4
|
+
|
5
|
+
# Polyphony: Fine-Grained Concurrency for Ruby
|
6
|
+
|
7
|
+
<a href="http://rubygems.org/gems/polyphony">
|
8
|
+
<img src="https://badge.fury.io/rb/polyphony.svg" alt="Ruby gem">
|
9
|
+
</a>
|
10
|
+
<a href="https://github.com/digital-fabric/polyphony/actions?query=workflow%3ATests">
|
11
|
+
<img src="https://github.com/digital-fabric/polyphony/workflows/Tests/badge.svg" alt="Tests">
|
12
|
+
</a>
|
13
|
+
<a href="https://github.com/digital-fabric/polyphony/blob/master/LICENSE">
|
14
|
+
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT License">
|
15
|
+
</a>
|
16
|
+
|
17
|
+
> Polyphony \| pəˈlɪf\(ə\)ni \|
|
18
|
+
>
|
19
|
+
> 1. _Music_ the style of simultaneously combining a number of parts, each
|
20
|
+
> forming an individual melody and harmonizing with each other.
|
21
|
+
>
|
22
|
+
> 2. _Programming_ a Ruby gem for concurrent programming focusing on performance
|
23
|
+
> and developer happiness.
|
24
|
+
|
25
|
+
## What is Polyphony?
|
26
|
+
|
27
|
+
Polyphony is a library for building concurrent applications in Ruby. Polyphony
|
28
|
+
harnesses the power of [Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html)
|
29
|
+
to provide a cooperative, sequential coroutine-based concurrency model. Under
|
30
|
+
the hood, Polyphony uses
|
31
|
+
[io_uring](https://unixism.net/loti/what_is_io_uring.html) or
|
32
|
+
[libev](https://github.com/enki/libev) to maximize I/O performance.
|
33
|
+
|
34
|
+
## Features
|
35
|
+
|
36
|
+
* Co-operative scheduling of concurrent tasks using Ruby fibers.
|
37
|
+
* High-performance event reactor for handling I/O events and timers.
|
38
|
+
* Natural, sequential programming style that makes it easy to reason about
|
39
|
+
concurrent code.
|
40
|
+
* Abstractions and constructs for controlling the execution of concurrent code:
|
41
|
+
supervisors, cancel scopes, throttling, resource pools etc.
|
42
|
+
* Code can use native networking classes and libraries, growing support for
|
43
|
+
third-party gems such as `pg` and `redis`.
|
44
|
+
* Use stdlib classes such as `TCPServer`, `TCPSocket` and
|
45
|
+
`OpenSSL::SSL::SSLSocket`.
|
46
|
+
* Competitive performance and scalability characteristics, in terms of both
|
47
|
+
throughput and memory consumption.
|
48
|
+
|
49
|
+
## Installing
|
50
|
+
|
51
|
+
### System Requirements
|
52
|
+
|
53
|
+
In order to use Polyphony you need to have:
|
54
|
+
|
55
|
+
- Linux or MacOS (support for Windows will come at a later stage)
|
56
|
+
- Ruby (MRI) 3.0 or newer
|
57
|
+
|
58
|
+
### Installing the Polyphony Gem
|
59
|
+
|
60
|
+
Add this line to your application's Gemfile:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
gem 'polyphony'
|
64
|
+
```
|
65
|
+
|
66
|
+
And then execute:
|
67
|
+
|
68
|
+
```bash
|
69
|
+
$ bundle
|
70
|
+
```
|
71
|
+
|
72
|
+
Or install it yourself as:
|
73
|
+
|
74
|
+
```bash
|
75
|
+
$ gem install polyphony
|
76
|
+
```
|
77
|
+
|
78
|
+
## Usage
|
79
|
+
|
80
|
+
- {file:/docs/overview.md Overview}
|
81
|
+
- {file:/docs/tutorial.md Tutorial}
|
82
|
+
- {file:/docs/faq.md FAQ}
|
83
|
+
|
84
|
+
## Technical Discussion
|
85
|
+
|
86
|
+
- {file:/docs/concurrency.md Concurrency the Easy Way}
|
87
|
+
- {file:/docs/fiber-scheduling.md How Fibers are Scheduled}
|
88
|
+
- {file:/docs/exception-handling.md Exception Handling}
|
89
|
+
- {file:/docs/extending.md Extending Polyphony}
|
90
|
+
- {file:/docs/design-principles.md Polyphony's Design}
|
91
|
+
|
92
|
+
## Examples
|
93
|
+
|
94
|
+
For examples of specific use cases you can consult the [bundled
|
95
|
+
examples](https://github.com/digital-fabric/polyphony/tree/master/examples) in
|
96
|
+
Polyphony's GitHub repository.
|
97
|
+
|
98
|
+
## Contributing to Polyphony
|
99
|
+
|
100
|
+
Issues and pull requests will be gladly accepted. Please use the [Polyphony git
|
101
|
+
repository](https://github.com/digital-fabric/polyphony) as your primary point
|
102
|
+
of departure for contributing.
|
@@ -13,14 +13,14 @@ require 'h1p'
|
|
13
13
|
def handle_client(conn)
|
14
14
|
spin do
|
15
15
|
parser = H1P::Parser.new(conn, :server)
|
16
|
-
|
16
|
+
|
17
17
|
while true # assuming persistent connection
|
18
18
|
headers = parser.parse_headers
|
19
19
|
break unless headers
|
20
20
|
|
21
21
|
raw_buffer = Polyphony.pipe
|
22
22
|
gzip_buffer = Polyphony.pipe
|
23
|
-
|
23
|
+
|
24
24
|
# splice request body to buffer
|
25
25
|
spin do
|
26
26
|
parser.splice_body_to(raw_buffer)
|
data/examples/pipes/tcp_proxy.rb
CHANGED
@@ -280,14 +280,14 @@ inline VALUE backend_snooze(struct Backend_base *backend) {
|
|
280
280
|
VALUE ret;
|
281
281
|
VALUE fiber = rb_fiber_current();
|
282
282
|
VALUE thread = rb_thread_current();
|
283
|
-
|
283
|
+
|
284
284
|
CHECK_FIBER_THREAD_REF(fiber, thread);
|
285
|
-
|
285
|
+
|
286
286
|
Fiber_make_runnable(fiber, Qnil);
|
287
287
|
ret = Thread_switch_fiber(thread);
|
288
288
|
|
289
289
|
COND_TRACE(backend, 4, SYM_unblock, fiber, ret, CALLER());
|
290
|
-
|
290
|
+
|
291
291
|
return ret;
|
292
292
|
}
|
293
293
|
|
@@ -306,7 +306,7 @@ inline double current_time(void) {
|
|
306
306
|
struct timespec ts;
|
307
307
|
double t;
|
308
308
|
uint64_t ns;
|
309
|
-
|
309
|
+
|
310
310
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
311
311
|
ns = ts.tv_sec;
|
312
312
|
ns = ns * 1e9 + ts.tv_nsec;
|
@@ -101,7 +101,7 @@ static VALUE Backend_initialize(VALUE self) {
|
|
101
101
|
while (1) {
|
102
102
|
int ret = io_uring_queue_init(backend->prepared_limit, &backend->ring, flags);
|
103
103
|
if (!ret) break;
|
104
|
-
|
104
|
+
|
105
105
|
// if ENOMEM is returned, use a smaller limit
|
106
106
|
if (ret == -ENOMEM && backend->prepared_limit > 64)
|
107
107
|
backend->prepared_limit = backend->prepared_limit / 2;
|
@@ -263,10 +263,10 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
263
263
|
if (!is_blocking && backend->pending_sqes) io_uring_backend_immediate_submit(backend);
|
264
264
|
|
265
265
|
COND_TRACE(&backend->base, 2, SYM_enter_poll, rb_fiber_current());
|
266
|
-
|
266
|
+
|
267
267
|
if (is_blocking) io_uring_backend_poll(backend);
|
268
268
|
io_uring_backend_handle_ready_cqes(backend);
|
269
|
-
|
269
|
+
|
270
270
|
COND_TRACE(&backend->base, 2, SYM_leave_poll, rb_fiber_current());
|
271
271
|
|
272
272
|
return self;
|
@@ -414,7 +414,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eo
|
|
414
414
|
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
415
415
|
int result;
|
416
416
|
int completed;
|
417
|
-
|
417
|
+
|
418
418
|
io_uring_prep_read(sqe, fd, buffer_spec.ptr, buffer_spec.len, -1);
|
419
419
|
|
420
420
|
result = io_uring_backend_defer_submit_and_await(backend, sqe, ctx, &resume_value);
|
@@ -449,7 +449,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eo
|
|
449
449
|
}
|
450
450
|
|
451
451
|
if (!total) return Qnil;
|
452
|
-
|
452
|
+
|
453
453
|
if (!buffer_spec.raw) backend_finalize_string_buffer(buffer, &buffer_spec, total, fptr);
|
454
454
|
return buffer_spec.raw ? INT2FIX(total) : buffer;
|
455
455
|
}
|
@@ -1412,7 +1412,7 @@ int io_uring_backend_submit_timeout_and_await(Backend_t *backend, double duratio
|
|
1412
1412
|
struct __kernel_timespec ts = double_to_timespec(duration);
|
1413
1413
|
struct io_uring_sqe *sqe = io_uring_backend_get_sqe(backend);
|
1414
1414
|
op_context_t *ctx = context_store_acquire(&backend->store, OP_TIMEOUT);
|
1415
|
-
|
1415
|
+
|
1416
1416
|
io_uring_prep_timeout(sqe, &ts, 0, 0);
|
1417
1417
|
io_uring_backend_defer_submit_and_await(backend, sqe, ctx, resume_value);
|
1418
1418
|
return context_store_release(&backend->store, ctx);
|
@@ -1723,7 +1723,7 @@ VALUE Backend_chain(int argc,VALUE *argv, VALUE self) {
|
|
1723
1723
|
completed = context_store_release(&backend->store, ctx);
|
1724
1724
|
if (!completed) {
|
1725
1725
|
struct io_uring_sqe *sqe;
|
1726
|
-
|
1726
|
+
|
1727
1727
|
Backend_chain_ctx_attach_buffers(ctx, argc, argv);
|
1728
1728
|
|
1729
1729
|
// op was not completed (an exception was raised), so we need to cancel it
|
@@ -1793,7 +1793,7 @@ static inline void splice_chunks_get_sqe(
|
|
1793
1793
|
|
1794
1794
|
static inline void splice_chunks_cancel(Backend_t *backend, op_context_t *ctx) {
|
1795
1795
|
struct io_uring_sqe *sqe;
|
1796
|
-
|
1796
|
+
|
1797
1797
|
ctx->result = -ECANCELED;
|
1798
1798
|
sqe = io_uring_backend_get_sqe(backend);
|
1799
1799
|
io_uring_prep_cancel(sqe, ctx, 0);
|
@@ -169,14 +169,14 @@ inline VALUE Backend_poll(VALUE self, VALUE blocking) {
|
|
169
169
|
backend->base.poll_count++;
|
170
170
|
|
171
171
|
COND_TRACE(&backend->base, 2, SYM_enter_poll, rb_fiber_current());
|
172
|
-
|
172
|
+
|
173
173
|
ev_run:
|
174
174
|
backend->base.currently_polling = 1;
|
175
175
|
errno = 0;
|
176
176
|
ev_run(backend->ev_loop, blocking == Qtrue ? EVRUN_ONCE : EVRUN_NOWAIT);
|
177
177
|
backend->base.currently_polling = 0;
|
178
178
|
if (errno == EINTR && runqueue_empty_p(&backend->base.runqueue)) goto ev_run;
|
179
|
-
|
179
|
+
|
180
180
|
COND_TRACE(&backend->base, 2, SYM_leave_poll, rb_fiber_current());
|
181
181
|
|
182
182
|
return self;
|
@@ -335,7 +335,7 @@ VALUE Backend_read(VALUE self, VALUE io, VALUE buffer, VALUE length, VALUE to_eo
|
|
335
335
|
}
|
336
336
|
|
337
337
|
if (!total) return Qnil;
|
338
|
-
|
338
|
+
|
339
339
|
if (!buffer_spec.raw) backend_finalize_string_buffer(buffer, &buffer_spec, total, fptr);
|
340
340
|
|
341
341
|
RB_GC_GUARD(watcher.fiber);
|
@@ -359,7 +359,7 @@ VALUE Backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE po
|
|
359
359
|
struct backend_buffer_spec buffer_spec = backend_get_buffer_spec(buffer, 0);
|
360
360
|
long total = 0;
|
361
361
|
VALUE switchpoint_result = Qnil;
|
362
|
-
|
362
|
+
|
363
363
|
GetBackend(self, backend);
|
364
364
|
backend_prepare_read_buffer(buffer, maxlen, &buffer_spec, FIX2INT(pos));
|
365
365
|
fd = fd_from_io(io, &fptr, 0, 1);
|
@@ -403,7 +403,7 @@ VALUE Backend_recvmsg(VALUE self, VALUE io, VALUE buffer, VALUE maxlen, VALUE po
|
|
403
403
|
}
|
404
404
|
|
405
405
|
if (!total) return Qnil;
|
406
|
-
|
406
|
+
|
407
407
|
if (!buffer_spec.raw) backend_finalize_string_buffer(buffer, &buffer_spec, total, fptr);
|
408
408
|
VALUE addr = name_to_addrinfo(msg.msg_name, msg.msg_namelen);
|
409
409
|
VALUE rflags = INT2NUM(msg.msg_flags);
|
data/ext/polyphony/fiber.c
CHANGED
@@ -60,13 +60,14 @@ inline void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
|
|
60
60
|
Thread_schedule_fiber_with_priority(thread, fiber, value);
|
61
61
|
}
|
62
62
|
|
63
|
-
/*
|
64
|
-
*
|
65
|
-
*
|
66
|
-
*
|
67
|
-
*
|
68
|
-
*
|
69
|
-
* @
|
63
|
+
/* Adds the fiber to the runqueue with the given resume value. If no resume
|
64
|
+
* value is given, the fiber will be resumed with `nil`.
|
65
|
+
*
|
66
|
+
* @overload schedule(value)
|
67
|
+
* @param value [any] resume value
|
68
|
+
* @return [Fiber] scheduled fiber
|
69
|
+
* @overload schedule
|
70
|
+
* @return [Fiber] scheduled fiber
|
70
71
|
*/
|
71
72
|
|
72
73
|
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
@@ -75,14 +76,14 @@ static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
|
75
76
|
return self;
|
76
77
|
}
|
77
78
|
|
78
|
-
/*
|
79
|
-
*
|
80
|
-
*
|
81
|
-
*
|
82
|
-
*
|
83
|
-
*
|
84
|
-
*
|
85
|
-
*
|
79
|
+
/* Adds the fiber to the head of the runqueue with the given resume value. If no
|
80
|
+
* resume value is given, the fiber will be resumed with `nil`.
|
81
|
+
*
|
82
|
+
* @overload schedule_with_priority(value)
|
83
|
+
* @param value [any] resume value
|
84
|
+
* @return [Fiber] scheduled fiber
|
85
|
+
* @overload schedule_with_priority
|
86
|
+
* @return [Fiber] scheduled fiber
|
86
87
|
*/
|
87
88
|
|
88
89
|
static VALUE Fiber_schedule_with_priority(int argc, VALUE *argv, VALUE self) {
|
@@ -91,12 +92,14 @@ static VALUE Fiber_schedule_with_priority(int argc, VALUE *argv, VALUE self) {
|
|
91
92
|
return self;
|
92
93
|
}
|
93
94
|
|
94
|
-
/*
|
95
|
-
*
|
96
|
-
*
|
97
|
-
*
|
98
|
-
* `:waiting
|
99
|
-
*
|
95
|
+
/* Returns the current state for the fiber, one of the following:
|
96
|
+
*
|
97
|
+
* - `:running` - the fiber is currently running.
|
98
|
+
* - `:runnable` - the fiber is on the runqueue, scheduled to be resumed ("ran").
|
99
|
+
* - `:waiting` - the fiber is waiting on some blocking operation to complete,
|
100
|
+
* allowing other fibers to run.
|
101
|
+
* - `:dead` - the fiber has finished running.
|
102
|
+
*
|
100
103
|
* @return [Symbol]
|
101
104
|
*/
|
102
105
|
|
@@ -109,12 +112,9 @@ static VALUE Fiber_state(VALUE self) {
|
|
109
112
|
return SYM_waiting;
|
110
113
|
}
|
111
114
|
|
112
|
-
/*
|
113
|
-
* fiber.send(msg)
|
114
|
-
*
|
115
|
-
* Sends a message to the given fiber. The message will be added to the fiber's
|
115
|
+
/* Sends a message to the given fiber. The message will be added to the fiber's
|
116
116
|
* mailbox.
|
117
|
-
*
|
117
|
+
*
|
118
118
|
* @param msg [any]
|
119
119
|
* @return [void]
|
120
120
|
*/
|
@@ -129,12 +129,9 @@ VALUE Fiber_send(VALUE self, VALUE msg) {
|
|
129
129
|
return self;
|
130
130
|
}
|
131
131
|
|
132
|
-
/*
|
133
|
-
* fiber.receive -> msg
|
134
|
-
*
|
135
|
-
* Receive's a message from the fiber's mailbox. If no message is available,
|
132
|
+
/* Receive's a message from the fiber's mailbox. If no message is available,
|
136
133
|
* waits for a message to be sent to it.
|
137
|
-
*
|
134
|
+
*
|
138
135
|
* @return [any] received message
|
139
136
|
*/
|
140
137
|
|
@@ -147,11 +144,8 @@ VALUE Fiber_receive(VALUE self) {
|
|
147
144
|
return Queue_shift(0, 0, mailbox);
|
148
145
|
}
|
149
146
|
|
150
|
-
/*
|
151
|
-
*
|
152
|
-
*
|
153
|
-
* Returns the fiber's mailbox.
|
154
|
-
*
|
147
|
+
/* Returns the fiber's mailbox.
|
148
|
+
*
|
155
149
|
* @return [Queue]
|
156
150
|
*/
|
157
151
|
|
@@ -164,11 +158,8 @@ VALUE Fiber_mailbox(VALUE self) {
|
|
164
158
|
return mailbox;
|
165
159
|
}
|
166
160
|
|
167
|
-
/*
|
168
|
-
*
|
169
|
-
*
|
170
|
-
* Receives all messages currently in the fiber's mailbox.
|
171
|
-
*
|
161
|
+
/* Receives all messages currently in the fiber's mailbox.
|
162
|
+
*
|
172
163
|
* @return [Array]
|
173
164
|
*/
|
174
165
|
|
@@ -322,7 +322,7 @@ void read_gzip_header_str(struct buffer_spec *buffer_spec, VALUE *str, unsigned
|
|
322
322
|
}
|
323
323
|
if (null_pos == *total_read)
|
324
324
|
rb_raise(rb_eRuntimeError, "Invalid gzip header");
|
325
|
-
|
325
|
+
|
326
326
|
*str = rb_str_new_cstr((char *)buffer_spec->ptr + *in_pos);
|
327
327
|
*in_pos = null_pos + 1;
|
328
328
|
}
|
@@ -507,14 +507,18 @@ static inline VALUE z_stream_cleanup(struct z_stream_ctx *ctx) {
|
|
507
507
|
#define Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx) \
|
508
508
|
rb_ensure(SAFE(z_stream_io_loop), (VALUE)&ctx, SAFE(z_stream_cleanup), (VALUE)&ctx)
|
509
509
|
|
510
|
-
/*
|
511
|
-
* IO.gzip(src, dest) -> bytes_written
|
512
|
-
* IO.gzip(src, dest, opt) -> bytes_written
|
513
|
-
*
|
514
|
-
* Gzips data from the source IO to the destination IO, returning the number
|
510
|
+
/* Gzips data from the source IO to the destination IO, returning the number
|
515
511
|
* bytes written to the destination IO.
|
516
|
-
*
|
517
|
-
* @
|
512
|
+
*
|
513
|
+
* @overload gzip(src, dest)
|
514
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
515
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
516
|
+
* @return [Integer]
|
517
|
+
* @overload gzip(src, dest, opt)
|
518
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
519
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
520
|
+
* @param opt [Hash] gzip options
|
521
|
+
* @return [Integer]
|
518
522
|
*/
|
519
523
|
|
520
524
|
VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
@@ -542,20 +546,24 @@ VALUE IO_gzip(int argc, VALUE *argv, VALUE self) {
|
|
542
546
|
ret = deflateInit2(&ctx.strm, DEFAULT_LEVEL, Z_DEFLATED, -MAX_WBITS, DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
|
543
547
|
if (ret != Z_OK)
|
544
548
|
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
545
|
-
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
549
|
+
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
546
550
|
return INT2FIX(ctx.out_total);
|
547
551
|
}
|
548
552
|
|
549
553
|
# define FIX2TIME(v) (rb_funcall(rb_cTime, ID_at, 1, v))
|
550
554
|
|
551
|
-
/*
|
552
|
-
* IO.gunzip(src, dest) -> bytes_written
|
553
|
-
* IO.gunzip(src, dest, opt) -> bytes_written
|
554
|
-
*
|
555
|
-
* Gunzips data from the source IO to the destination IO, returning the number
|
555
|
+
/* Gunzips data from the source IO to the destination IO, returning the number
|
556
556
|
* bytes written to the destination IO.
|
557
|
-
*
|
558
|
-
* @
|
557
|
+
*
|
558
|
+
* @overload gunzip(src, dest)
|
559
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
560
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
561
|
+
* @return [Integer]
|
562
|
+
* @overload gunzip(src, dest, opt)
|
563
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
564
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
565
|
+
* @param opt [Hash] gzip options
|
566
|
+
* @return [Integer]
|
559
567
|
*/
|
560
568
|
|
561
569
|
VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
|
@@ -594,14 +602,18 @@ VALUE IO_gunzip(int argc, VALUE *argv, VALUE self) {
|
|
594
602
|
return INT2FIX(ctx.out_total);
|
595
603
|
}
|
596
604
|
|
597
|
-
/*
|
598
|
-
* IO.deflate(src, dest) -> bytes_written
|
599
|
-
* IO.deflate(src, dest, opt) -> bytes_written
|
600
|
-
*
|
601
|
-
* Defaltes data from the source IO to the destination IO, returning the number
|
605
|
+
/* Deflates data from the source IO to the destination IO, returning the number
|
602
606
|
* bytes written to the destination IO.
|
603
|
-
*
|
604
|
-
* @
|
607
|
+
*
|
608
|
+
* @overload deflate(src, dest)
|
609
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
610
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
611
|
+
* @return [Integer]
|
612
|
+
* @overload deflate(src, dest, opt)
|
613
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
614
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
615
|
+
* @param opt [Hash] gzip options
|
616
|
+
* @return [Integer]
|
605
617
|
*/
|
606
618
|
|
607
619
|
VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
@@ -615,18 +627,22 @@ VALUE IO_deflate(VALUE self, VALUE src, VALUE dest) {
|
|
615
627
|
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
616
628
|
|
617
629
|
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
618
|
-
|
630
|
+
|
619
631
|
return INT2FIX(ctx.out_total);
|
620
632
|
}
|
621
633
|
|
622
|
-
/*
|
623
|
-
* IO.inflate(src, dest) -> bytes_written
|
624
|
-
* IO.inflate(src, dest, opt) -> bytes_written
|
625
|
-
*
|
626
|
-
* Inflates data from the source IO to the destination IO, returning the number
|
634
|
+
/* Inflates data from the source IO to the destination IO, returning the number
|
627
635
|
* bytes written to the destination IO.
|
628
|
-
*
|
629
|
-
* @
|
636
|
+
*
|
637
|
+
* @overload inflate(src, dest)
|
638
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
639
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
640
|
+
* @return [Integer]
|
641
|
+
* @overload inflate(src, dest, opt)
|
642
|
+
* @param src [IO, Polyphony::Pipe] source IO
|
643
|
+
* @param dest [IO, Polyphony::Pipe] destination IO
|
644
|
+
* @param opt [Hash] gzip options
|
645
|
+
* @return [Integer]
|
630
646
|
*/
|
631
647
|
|
632
648
|
VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
|
@@ -639,17 +655,14 @@ VALUE IO_inflate(VALUE self, VALUE src, VALUE dest) {
|
|
639
655
|
rb_raise(rb_eRuntimeError, "zlib error: %s\n", ctx.strm.msg);
|
640
656
|
|
641
657
|
Z_STREAM_SAFE_IO_LOOP_WITH_CLEANUP(ctx);
|
642
|
-
|
658
|
+
|
643
659
|
return INT2FIX(ctx.out_total);
|
644
660
|
}
|
645
661
|
|
646
|
-
/*
|
647
|
-
* IO.http1_splice_chunked(src, dest, maxlen)
|
648
|
-
*
|
649
|
-
* Splices data from the source IO to the destination IO, writing it in HTTP1
|
662
|
+
/* Splices data from the source IO to the destination IO, writing it in HTTP1
|
650
663
|
* chunked encoding. A pipe is automatically created to buffer data between
|
651
664
|
* source and destination.
|
652
|
-
*
|
665
|
+
*
|
653
666
|
* @param src [IO] source
|
654
667
|
* @param dest [IO] destination
|
655
668
|
* @param maxlen [Integer] maximum bytes to splice
|
data/ext/polyphony/pipe.c
CHANGED
@@ -36,11 +36,8 @@ static VALUE Pipe_allocate(VALUE klass) {
|
|
36
36
|
#define GetPipe(obj, pipe) \
|
37
37
|
TypedData_Get_Struct((obj), Pipe_t, &Pipe_type, (pipe))
|
38
38
|
|
39
|
-
/*
|
40
|
-
* Pipe.new -> pipe
|
39
|
+
/* Creates a new pipe.
|
41
40
|
*
|
42
|
-
* Creates a new pipe.
|
43
|
-
*
|
44
41
|
* @return [void]
|
45
42
|
*/
|
46
43
|
|
@@ -80,11 +77,8 @@ int Pipe_get_fd(VALUE self, int write_mode) {
|
|
80
77
|
return pipe->fds[write_mode ? 1 : 0];
|
81
78
|
}
|
82
79
|
|
83
|
-
/*
|
84
|
-
* pipe.closed? -> bool
|
80
|
+
/* Returns true if the pipe is closed.
|
85
81
|
*
|
86
|
-
* Returns true if the pipe is closed.
|
87
|
-
*
|
88
82
|
* @return [boolean]
|
89
83
|
*/
|
90
84
|
|
@@ -94,11 +88,8 @@ VALUE Pipe_closed_p(VALUE self) {
|
|
94
88
|
return pipe->w_closed ? Qtrue : Qfalse;
|
95
89
|
}
|
96
90
|
|
97
|
-
/*
|
98
|
-
* pipe.close -> pipe
|
91
|
+
/* Closes the pipe.
|
99
92
|
*
|
100
|
-
* Closes the pipe.
|
101
|
-
*
|
102
93
|
* @return [Pipe] self
|
103
94
|
*/
|
104
95
|
|
@@ -113,12 +104,9 @@ VALUE Pipe_close(VALUE self) {
|
|
113
104
|
return self;
|
114
105
|
}
|
115
106
|
|
116
|
-
/*
|
117
|
-
* Pipe.fds -> [r, w]
|
118
|
-
*
|
119
|
-
* Returns an array containing the read and write fds for the pipe,
|
107
|
+
/* Returns an array containing the read and write fds for the pipe,
|
120
108
|
* respectively.
|
121
|
-
*
|
109
|
+
*
|
122
110
|
* @return [Array<Integer>]
|
123
111
|
*/
|
124
112
|
|
@@ -131,7 +119,7 @@ VALUE Pipe_fds(VALUE self) {
|
|
131
119
|
|
132
120
|
void Init_Pipe(void) {
|
133
121
|
cPipe = rb_define_class_under(mPolyphony, "Pipe", rb_cObject);
|
134
|
-
|
122
|
+
|
135
123
|
/*
|
136
124
|
* Document-class: Polyphony::Pipe::ClosedPipeError
|
137
125
|
*
|