polyphony 0.53.2 → 0.58
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +1 -1
- data/.gitignore +3 -1
- data/CHANGELOG.md +55 -24
- data/Gemfile.lock +3 -1
- data/TODO.md +0 -3
- data/examples/core/idle_gc.rb +21 -0
- data/examples/core/queue.rb +19 -0
- data/examples/io/https_server.rb +30 -0
- data/examples/io/pipe.rb +11 -0
- data/examples/io/splice_chunks.rb +29 -0
- data/examples/io/stdio.rb +8 -0
- data/ext/polyphony/backend_common.c +197 -0
- data/ext/polyphony/backend_common.h +28 -130
- data/ext/polyphony/backend_io_uring.c +380 -109
- data/ext/polyphony/backend_io_uring_context.c +14 -3
- data/ext/polyphony/backend_io_uring_context.h +11 -11
- data/ext/polyphony/backend_libev.c +417 -94
- data/ext/polyphony/polyphony.c +17 -15
- data/ext/polyphony/polyphony.h +3 -0
- data/ext/polyphony/runqueue.c +29 -1
- data/ext/polyphony/thread.c +19 -4
- data/lib/polyphony/core/sync.rb +8 -0
- data/lib/polyphony/extensions/openssl.rb +24 -17
- data/lib/polyphony/extensions/socket.rb +6 -20
- data/lib/polyphony/extensions/thread.rb +8 -0
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +1 -0
- data/test/helper.rb +3 -3
- data/test/test_backend.rb +137 -2
- data/test/test_fiber.rb +0 -1
- data/test/test_io.rb +6 -3
- data/test/test_signal.rb +1 -1
- data/test/test_sync.rb +43 -0
- data/test/test_thread.rb +52 -0
- data/test/test_thread_pool.rb +1 -1
- data/test/test_timer.rb +16 -10
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8002b8c0e03afa8e915b5ed67d64c1fc288a5fa220dfb2c32d3966a78046eee
|
4
|
+
data.tar.gz: c3a46eeae1f048f4adee9d3130f5dd3593936e843c1874d928f742d1fa83053f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6681155761daee35b73c9674e69aa505786e576814db0c909028cb576d8609f99bccc79f80b7d06d90c7658747bc2589c9837d3bdb3419782147e573d39f278
|
7
|
+
data.tar.gz: 90197a8db54405ca37492a54a20adf00c85f142af606cad26ad823161825ccf6bd9a414adcbbf3e27eaf93eea1d94a7cbc50a2fb5982ee4ce48969d4378400cd
|
data/.github/workflows/test.yml
CHANGED
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,12 +1,43 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.58 2021-06-25
|
2
|
+
|
3
|
+
- Implement `Thread#idle_gc_period`, `#on_idle` (#56)
|
4
|
+
- Implement `Backend#idle_block=` (#56)
|
5
|
+
|
6
|
+
## 0.57.0 2021-06-23
|
7
|
+
|
8
|
+
- Implement `Backend#splice_chunks` method for both libev and io_uring backends
|
9
|
+
- Improve waiting for readiness in libev `Backend#splice`, `#splice_to_eof`
|
10
|
+
- Enable splice op in libev `Backend#chain` for non-Linux OS
|
11
|
+
|
12
|
+
## 0.56.0 2021-06-22
|
13
|
+
|
14
|
+
- Implement fake `Backend#splice`, `Backend#splice_to_eof` methods for non-Linux
|
15
|
+
OS
|
16
|
+
|
17
|
+
## 0.55.0 2021-06-17
|
18
|
+
|
19
|
+
- Finish io_uring implementation of Backend#chain
|
20
|
+
- Reimplement io_uring op_context acquire/release algorithm (using ref count)
|
21
|
+
- Fix #gets on sockets
|
22
|
+
- Redesign event anti-starvation mechanism
|
23
|
+
|
24
|
+
## 0.54.0 2021-06-14
|
25
|
+
|
26
|
+
- Implement Mutex#owned?, #locked? (#50)
|
27
|
+
- Fix arity for SSLSocket#peeraddr (#55)
|
28
|
+
- Add missing SSLServer#accept_loop method (#53)
|
29
|
+
- Fix SSLSocket buffering behaviour
|
30
|
+
- Add recv_loop alias for SSLSocket (#54)
|
31
|
+
|
32
|
+
## 0.53.2 2021-05-10
|
2
33
|
|
3
34
|
- Remove `splice` methods on libev backend on non-Linux OS (#43)
|
4
35
|
|
5
|
-
## 0.53.0
|
36
|
+
## 0.53.0 2021-04-23
|
6
37
|
|
7
38
|
- Implement `Backend#splice`, `Backend#splice_to_eof`, along with `IO#splice`, `IO#splice_to_eof`
|
8
39
|
|
9
|
-
## 0.52.0
|
40
|
+
## 0.52.0 2021-02-28
|
10
41
|
|
11
42
|
- Polyphony is now compatible with Ruby 3.0
|
12
43
|
- Add `Backend#sendv` method for sending multiple strings
|
@@ -16,19 +47,19 @@
|
|
16
47
|
- libev backend: Use` pidfd_open` for Linux 5.3+, otherwise use a libev child watcher
|
17
48
|
- Use `:call` as default method in `#feed_loop`
|
18
49
|
|
19
|
-
## 0.51.0
|
50
|
+
## 0.51.0 2021-02-02
|
20
51
|
|
21
52
|
- Implement `IO#feed_loop`, `Socket#feed_loop`
|
22
53
|
- Fix error handling in `Process.kill_and_await`
|
23
54
|
|
24
|
-
## 0.50.1
|
55
|
+
## 0.50.1 2021-01-31
|
25
56
|
|
26
57
|
- Set `IOSQE_ASYNC` flag in io_uring backend
|
27
58
|
- Fix error handling in `Backend#waitpid`
|
28
59
|
- Reimplement libev backend's `#waitpid` by using pidfd_open (in similar manner
|
29
60
|
to the io_uring backend)
|
30
61
|
|
31
|
-
## 0.50.0
|
62
|
+
## 0.50.0 2021-01-28
|
32
63
|
|
33
64
|
- Use `Process::CLOCK_MONOTONIC` in Timer
|
34
65
|
- Add `Timer#sleep`, `Timer#after`, `Timer#every`
|
@@ -36,50 +67,50 @@
|
|
36
67
|
- Add `Thread#fiber_index_of` method
|
37
68
|
- Use `Backend#wait_event` in `Fiber#await`
|
38
69
|
|
39
|
-
## 0.49.2
|
70
|
+
## 0.49.2 2021-01-19
|
40
71
|
|
41
72
|
- Fix hang with 100s or more child fibers when terminating
|
42
73
|
- Fix double pending_count increment in io_uring backend
|
43
74
|
|
44
|
-
## 0.49.1
|
75
|
+
## 0.49.1 2021-01-13
|
45
76
|
|
46
77
|
- Use `TCPSocket` instead of `Socket` in `Net.tcp_connect`
|
47
78
|
- Catch `Errno::ERSCH` in `Process.kill_and_await`
|
48
79
|
- Set io_uring queue size to 2048
|
49
80
|
|
50
|
-
## 0.49.0
|
81
|
+
## 0.49.0 2021-01-11
|
51
82
|
|
52
83
|
- Implement `Polyphony::Timer` for performant timeouts
|
53
84
|
|
54
|
-
## 0.48.0
|
85
|
+
## 0.48.0 2021-01-05
|
55
86
|
|
56
87
|
- Implement graceful shutdown
|
57
88
|
- Add support for `break` / `StopIteration` in `spin_loop`
|
58
89
|
- Fix `IO#gets`, `IO#readpartial`
|
59
90
|
|
60
|
-
## 0.47.5.1
|
91
|
+
## 0.47.5.1 2020-11-20
|
61
92
|
|
62
93
|
- Add missing `Socket#accept_loop` method
|
63
94
|
|
64
|
-
## 0.47.5
|
95
|
+
## 0.47.5 2020-11-20
|
65
96
|
|
66
97
|
- Add `socket_class` argument to `Backend#accept`, `Backend#accept_loop`
|
67
98
|
- Fix `#supervise` to stop when all children fibers are done
|
68
99
|
|
69
|
-
## 0.47.4
|
100
|
+
## 0.47.4 2020-11-14
|
70
101
|
|
71
102
|
- Add support for Unix sockets
|
72
103
|
|
73
|
-
## 0.47.3
|
104
|
+
## 0.47.3 2020-11-12
|
74
105
|
|
75
106
|
- Enable I/O in signal handlers (#45)
|
76
107
|
- Accept `:interval` argument in `#spin_loop`
|
77
108
|
|
78
|
-
## 0.47.2
|
109
|
+
## 0.47.2 2020-11-10
|
79
110
|
|
80
111
|
- Fix API compatibility between TCPSocket and IO
|
81
112
|
|
82
|
-
## 0.47.0
|
113
|
+
## 0.47.0 2020-11-10
|
83
114
|
|
84
115
|
- Implement `#spin_scope` used for creating blocking fiber scopes
|
85
116
|
- Reimplement `move_on_after`, `cancel_after`, `Timeout.timeout` using
|
@@ -87,18 +118,18 @@
|
|
87
118
|
- Implement `Backend#timeout` API
|
88
119
|
- Implemented capped queues
|
89
120
|
|
90
|
-
## 0.46.1
|
121
|
+
## 0.46.1 2020-11-04
|
91
122
|
|
92
123
|
- Add `TCPServer#accept_loop`, `OpenSSL::SSL::SSLSocket#accept_loop` method
|
93
124
|
- Fix compilation error on MacOS (#43)
|
94
125
|
- Fix backtrace for `Timeout.timeout`
|
95
126
|
- Add `Backend#timer_loop`
|
96
127
|
|
97
|
-
## 0.46.0
|
128
|
+
## 0.46.0 2020-10-08
|
98
129
|
|
99
130
|
- Implement [io_uring backend](https://github.com/digital-fabric/polyphony/pull/44)
|
100
131
|
|
101
|
-
## 0.45.5
|
132
|
+
## 0.45.5 2020-10-04
|
102
133
|
|
103
134
|
- Fix compilation error (#43)
|
104
135
|
- Add support for resetting move_on_after, cancel_after timeouts
|
@@ -107,22 +138,22 @@
|
|
107
138
|
- Schedule parent with priority on uncaught exception
|
108
139
|
- Fix race condition in `Mutex#synchronize` (#41)
|
109
140
|
|
110
|
-
## 0.45.4
|
141
|
+
## 0.45.4 2020-09-06
|
111
142
|
|
112
143
|
- Improve signal trapping mechanism
|
113
144
|
|
114
|
-
## 0.45.3
|
145
|
+
## 0.45.3 2020-09-02
|
115
146
|
|
116
147
|
- Don't swallow error in `Process#kill_and_await`
|
117
148
|
- Add `Fiber#mailbox` attribute reader
|
118
149
|
- Fix bug in `Fiber.await`
|
119
150
|
- Implement `IO#getc`, `IO#getbyte`
|
120
151
|
|
121
|
-
## 0.45.2
|
152
|
+
## 0.45.2 2020-08-03
|
122
153
|
|
123
154
|
- Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
|
124
155
|
|
125
|
-
## 0.45.1
|
156
|
+
## 0.45.1 2020-08-01
|
126
157
|
|
127
158
|
- Fix Net::HTTP compatibility
|
128
159
|
- Fix fs adapter
|
@@ -132,7 +163,7 @@
|
|
132
163
|
- Cleanup code
|
133
164
|
- Improve support for Ruby 3 keyword args
|
134
165
|
|
135
|
-
## 0.45.0
|
166
|
+
## 0.45.0 2020-07-29
|
136
167
|
|
137
168
|
- Cleanup code
|
138
169
|
- Rename `Agent` to `Backend`
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
polyphony (0.
|
4
|
+
polyphony (0.58)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -17,6 +17,7 @@ GEM
|
|
17
17
|
mime-types (~> 3.0)
|
18
18
|
multi_xml (>= 0.5.2)
|
19
19
|
json (2.3.0)
|
20
|
+
localhost (1.1.8)
|
20
21
|
method_source (1.0.0)
|
21
22
|
mime-types (3.3.1)
|
22
23
|
mime-types-data (~> 3.2015)
|
@@ -72,6 +73,7 @@ DEPENDENCIES
|
|
72
73
|
hiredis (= 0.6.3)
|
73
74
|
http_parser.rb (~> 0.6.0)
|
74
75
|
httparty (= 0.17.1)
|
76
|
+
localhost (~> 1.1.4)
|
75
77
|
minitest (= 5.14.4)
|
76
78
|
minitest-reporters (= 1.4.2)
|
77
79
|
msgpack (= 1.4.2)
|
data/TODO.md
CHANGED
@@ -10,9 +10,6 @@
|
|
10
10
|
|
11
11
|
- Add support for `break` and `StopIteration` in all loops (with tests)
|
12
12
|
|
13
|
-
- Change `IO#gets` to use `String#split` to cut into lines, much faster (see
|
14
|
-
examples/performance/line_splitting.rb)
|
15
|
-
|
16
13
|
- More tight loops
|
17
14
|
- `IO#gets_loop`, `Socket#gets_loop`, `OpenSSL::Socket#gets_loop` (medium effort)
|
18
15
|
- `Fiber#receive_loop` (very little effort, should be implemented in C)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
require 'polyphony'
|
6
|
+
|
7
|
+
GC.disable
|
8
|
+
|
9
|
+
p count: GC.count
|
10
|
+
snooze
|
11
|
+
p count_after_snooze: GC.count
|
12
|
+
sleep 0.1
|
13
|
+
p count_after_sleep: GC.count
|
14
|
+
|
15
|
+
Thread.current.backend.idle_gc_period = 60
|
16
|
+
|
17
|
+
p count: GC.count
|
18
|
+
snooze
|
19
|
+
p count_after_snooze: GC.count
|
20
|
+
sleep 0.1
|
21
|
+
p count_after_sleep: GC.count
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
queue = Queue.new
|
7
|
+
|
8
|
+
4.times { |i|
|
9
|
+
spin_loop {
|
10
|
+
job = queue.pop
|
11
|
+
puts("worker %d job %s" % [i, job.inspect])
|
12
|
+
}
|
13
|
+
}
|
14
|
+
|
15
|
+
(1..10).each do |i|
|
16
|
+
queue << "job#{i}"
|
17
|
+
end
|
18
|
+
|
19
|
+
sleep 0.1 until queue.empty?
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
require 'localhost/authority'
|
6
|
+
|
7
|
+
authority = Localhost::Authority.fetch
|
8
|
+
opts = {
|
9
|
+
reuse_addr: true,
|
10
|
+
dont_linger: true,
|
11
|
+
secure_context: authority.server_context
|
12
|
+
}
|
13
|
+
|
14
|
+
server = Polyphony::Net.tcp_listen('localhost', 1234, opts)
|
15
|
+
|
16
|
+
puts 'Serving HTTPS on port 1234'
|
17
|
+
|
18
|
+
spin_loop(interval: 1) { STDOUT << '.' }
|
19
|
+
|
20
|
+
# server.accept_loop do |socket|
|
21
|
+
while (socket = server.accept)
|
22
|
+
spin do
|
23
|
+
while (data = socket.gets("\n", 8192))
|
24
|
+
if data.chomp.empty?
|
25
|
+
socket << "HTTP/1.1 200 OK\nConnection: close\nContent-Length: 4\n\nfoo\n"
|
26
|
+
break
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/examples/io/pipe.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'polyphony'
|
5
|
+
|
6
|
+
i, o = IO.pipe
|
7
|
+
|
8
|
+
f = spin do
|
9
|
+
i.read_loop { |data| STDOUT << data }
|
10
|
+
end
|
11
|
+
|
12
|
+
result = nil
|
13
|
+
# File.open(__FILE__, 'r') do |f|
|
14
|
+
File.open('../tipi/log', 'r') do |f|
|
15
|
+
result = Thread.current.backend.splice_chunks(
|
16
|
+
f,
|
17
|
+
o,
|
18
|
+
"Content-Type: ruby\n\n",
|
19
|
+
"0\r\n\r\n",
|
20
|
+
->(len) { "#{len.to_s(16)}\r\n" },
|
21
|
+
"\r\n",
|
22
|
+
16384
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
o.close
|
28
|
+
f.await
|
29
|
+
p result: result
|
@@ -0,0 +1,197 @@
|
|
1
|
+
#include <time.h>
|
2
|
+
#include <fcntl.h>
|
3
|
+
#include "ruby.h"
|
4
|
+
#include "ruby/io.h"
|
5
|
+
#include "polyphony.h"
|
6
|
+
#include "backend_common.h"
|
7
|
+
|
8
|
+
inline void initialize_backend_base(struct Backend_base *base) {
|
9
|
+
base->currently_polling = 0;
|
10
|
+
base->pending_count = 0;
|
11
|
+
base->idle_gc_period = 0;
|
12
|
+
base->idle_gc_last_time = 0;
|
13
|
+
base->idle_block = Qnil;
|
14
|
+
}
|
15
|
+
|
16
|
+
#ifdef POLYPHONY_USE_PIDFD_OPEN
|
17
|
+
#ifndef __NR_pidfd_open
|
18
|
+
#define __NR_pidfd_open 434 /* System call # on most architectures */
|
19
|
+
#endif
|
20
|
+
|
21
|
+
inline int pidfd_open(pid_t pid, unsigned int flags) {
|
22
|
+
return syscall(__NR_pidfd_open, pid, flags);
|
23
|
+
}
|
24
|
+
#endif
|
25
|
+
|
26
|
+
//////////////////////////////////////////////////////////////////////
|
27
|
+
//////////////////////////////////////////////////////////////////////
|
28
|
+
// the following is copied verbatim from the Ruby source code (io.c)
|
29
|
+
|
30
|
+
inline int io_setstrbuf(VALUE *str, long len) {
|
31
|
+
#ifdef _WIN32
|
32
|
+
len = (len + 1) & ~1L; /* round up for wide char */
|
33
|
+
#endif
|
34
|
+
if (*str == Qnil) {
|
35
|
+
*str = rb_str_new(0, len);
|
36
|
+
return 1;
|
37
|
+
}
|
38
|
+
else {
|
39
|
+
VALUE s = StringValue(*str);
|
40
|
+
long clen = RSTRING_LEN(s);
|
41
|
+
if (clen >= len) {
|
42
|
+
rb_str_modify(s);
|
43
|
+
return 0;
|
44
|
+
}
|
45
|
+
len -= clen;
|
46
|
+
}
|
47
|
+
rb_str_modify_expand(*str, len);
|
48
|
+
return 0;
|
49
|
+
}
|
50
|
+
|
51
|
+
#define MAX_REALLOC_GAP 4096
|
52
|
+
|
53
|
+
inline void io_shrink_read_string(VALUE str, long n) {
|
54
|
+
if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
|
55
|
+
rb_str_resize(str, n);
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
inline void io_set_read_length(VALUE str, long n, int shrinkable) {
|
60
|
+
if (RSTRING_LEN(str) != n) {
|
61
|
+
rb_str_modify(str);
|
62
|
+
rb_str_set_len(str, n);
|
63
|
+
if (shrinkable) io_shrink_read_string(str, n);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
|
68
|
+
if (fptr->encs.enc) {
|
69
|
+
return fptr->encs.enc;
|
70
|
+
}
|
71
|
+
return rb_default_external_encoding();
|
72
|
+
}
|
73
|
+
|
74
|
+
inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
|
75
|
+
OBJ_TAINT(str);
|
76
|
+
rb_enc_associate(str, io_read_encoding(fptr));
|
77
|
+
return str;
|
78
|
+
}
|
79
|
+
|
80
|
+
//////////////////////////////////////////////////////////////////////
|
81
|
+
//////////////////////////////////////////////////////////////////////
|
82
|
+
|
83
|
+
VALUE backend_await(struct Backend_base *backend) {
|
84
|
+
VALUE ret;
|
85
|
+
backend->pending_count++;
|
86
|
+
ret = Thread_switch_fiber(rb_thread_current());
|
87
|
+
backend->pending_count--;
|
88
|
+
RB_GC_GUARD(ret);
|
89
|
+
return ret;
|
90
|
+
}
|
91
|
+
|
92
|
+
VALUE backend_snooze() {
|
93
|
+
Fiber_make_runnable(rb_fiber_current(), Qnil);
|
94
|
+
VALUE ret = Thread_switch_fiber(rb_thread_current());
|
95
|
+
return ret;
|
96
|
+
}
|
97
|
+
|
98
|
+
inline void rectify_io_file_pos(rb_io_t *fptr) {
|
99
|
+
// Apparently after reopening a closed file, the file position is not reset,
|
100
|
+
// which causes the read to fail. Fortunately we can use fptr->rbuf.len to
|
101
|
+
// find out if that's the case.
|
102
|
+
// See: https://github.com/digital-fabric/polyphony/issues/30
|
103
|
+
if (fptr->rbuf.len > 0) {
|
104
|
+
lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
|
105
|
+
fptr->rbuf.len = 0;
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
inline double current_time() {
|
110
|
+
struct timespec ts;
|
111
|
+
clock_gettime(CLOCK_MONOTONIC, &ts);
|
112
|
+
long long ns = ts.tv_sec;
|
113
|
+
ns = ns * 1e9 + ts.tv_nsec;
|
114
|
+
double t = ns;
|
115
|
+
return t / 1e9;
|
116
|
+
}
|
117
|
+
|
118
|
+
inline VALUE backend_timeout_exception(VALUE exception) {
|
119
|
+
if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
|
120
|
+
return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
|
121
|
+
else if (rb_obj_is_kind_of(exception, rb_cClass) == Qtrue)
|
122
|
+
return rb_funcall(exception, ID_new, 0);
|
123
|
+
else
|
124
|
+
return rb_funcall(rb_eRuntimeError, ID_new, 1, exception);
|
125
|
+
}
|
126
|
+
|
127
|
+
VALUE Backend_timeout_safe(VALUE arg) {
|
128
|
+
return rb_yield(arg);
|
129
|
+
}
|
130
|
+
|
131
|
+
VALUE Backend_timeout_rescue(VALUE arg, VALUE exception) {
|
132
|
+
return exception;
|
133
|
+
}
|
134
|
+
|
135
|
+
VALUE Backend_timeout_ensure_safe(VALUE arg) {
|
136
|
+
return rb_rescue2(Backend_timeout_safe, Qnil, Backend_timeout_rescue, Qnil, rb_eException, (VALUE)0);
|
137
|
+
}
|
138
|
+
|
139
|
+
static VALUE empty_string = Qnil;
|
140
|
+
|
141
|
+
VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
|
142
|
+
switch (RARRAY_LEN(ary)) {
|
143
|
+
case 0:
|
144
|
+
return Qnil;
|
145
|
+
case 1:
|
146
|
+
return Backend_send(self, io, RARRAY_AREF(ary, 0), flags);
|
147
|
+
default:
|
148
|
+
if (empty_string == Qnil) {
|
149
|
+
empty_string = rb_str_new_literal("");
|
150
|
+
rb_global_variable(&empty_string);
|
151
|
+
}
|
152
|
+
VALUE joined = rb_ary_join(ary, empty_string);
|
153
|
+
VALUE result = Backend_send(self, io, joined, flags);
|
154
|
+
RB_GC_GUARD(joined);
|
155
|
+
return result;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
|
160
|
+
VALUE blocking_mode = rb_ivar_get(io, ID_ivar_blocking_mode);
|
161
|
+
if (blocking == blocking_mode) return;
|
162
|
+
|
163
|
+
rb_ivar_set(io, ID_ivar_blocking_mode, blocking);
|
164
|
+
|
165
|
+
#ifdef _WIN32
|
166
|
+
if (blocking != Qtrue)
|
167
|
+
rb_w32_set_nonblock(fptr->fd);
|
168
|
+
#elif defined(F_GETFL)
|
169
|
+
int flags = fcntl(fptr->fd, F_GETFL);
|
170
|
+
if (flags == -1) return;
|
171
|
+
int is_nonblocking = flags & O_NONBLOCK;
|
172
|
+
|
173
|
+
if (blocking == Qtrue) {
|
174
|
+
if (!is_nonblocking) return;
|
175
|
+
flags &= ~O_NONBLOCK;
|
176
|
+
} else {
|
177
|
+
if (is_nonblocking) return;
|
178
|
+
flags |= O_NONBLOCK;
|
179
|
+
}
|
180
|
+
fcntl(fptr->fd, F_SETFL, flags);
|
181
|
+
#endif
|
182
|
+
}
|
183
|
+
|
184
|
+
inline void backend_run_idle_tasks(struct Backend_base *base) {
|
185
|
+
if (base->idle_block != Qnil)
|
186
|
+
rb_funcall(base->idle_block, ID_call, 0);
|
187
|
+
|
188
|
+
if (base->idle_gc_period == 0) return;
|
189
|
+
|
190
|
+
double now = current_time();
|
191
|
+
if (now - base->idle_gc_last_time < base->idle_gc_period) return;
|
192
|
+
|
193
|
+
base->idle_gc_last_time = now;
|
194
|
+
rb_gc_enable();
|
195
|
+
rb_gc_start();
|
196
|
+
rb_gc_disable();
|
197
|
+
}
|