polyphony 0.53.2 → 0.58
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/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
|
+
}
|