polyphony 0.53.1 → 0.57.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b769b5e71cbfa8679a639d369817abd8e5870efec8ea21feb60bb1e46ee7ca29
4
- data.tar.gz: 0b2ded84eb0e120d20dd17c9973e2cab784cdf61c20bd20fcb6a13c2b6e9f58a
3
+ metadata.gz: e350937221c476548465a2881e64689042137eab59571a0940f63236a249563f
4
+ data.tar.gz: 14870d9e38e7aa9f300d09cdfa0693929edb59756e0d17e7b3e7ae2d4a9dab0d
5
5
  SHA512:
6
- metadata.gz: e6d3a3d2c130c31483ead4d8f13cc90a87149ac6c461871a43144111cdc37e6e2544c130dc447af26e39e9519b48e3abe1a10197dd4512a7292968e4939e676b
7
- data.tar.gz: dc1b53918032fc74578ca528abb5a96e423ea8e7a070047f7936720cb6553d9f247cbb625e9d82c7b9b58795a4a3a74aae566231a7a4bb8443f5352c00d10b2a
6
+ metadata.gz: 8087b84c7a583c8f3905c20d06aa4ad119fd2901be2594e66f56b577c1fa141f9e203971aedd27ad7c57b9c184adad1b97d0fbe4024702bfe3ef6bdaa861ac92
7
+ data.tar.gz: 6943231ef2b29dac3e33cfee865dbc6b3b35549c62e04dd1ed08d40fbd90a5c179417baf3b27b965e80c3ee7e137cbe167be9e8187dff46d89892978beb8a40d
@@ -26,6 +26,6 @@ jobs:
26
26
  - name: Show Linux kernel version
27
27
  run: uname -r
28
28
  - name: Compile C-extension
29
- run: bundle exec rake compile
29
+ run: POLYPHONY_USE_LIBEV=1 bundle exec rake compile
30
30
  - name: Run tests
31
31
  run: bundle exec rake test
data/.gitignore CHANGED
@@ -56,4 +56,6 @@ lib/*.bundle
56
56
  lib/*.so
57
57
 
58
58
  _site
59
- .sass-cache
59
+ .sass-cache
60
+
61
+ log
data/CHANGELOG.md CHANGED
@@ -1,12 +1,38 @@
1
- ## 0.53.1
1
+ ## 0.57.0 2021-06-23
2
+
3
+ - Implement `Backend#splice_chunks` method for both libev and io_uring backends
4
+ - Improve waiting for readiness in libev `Backend#splice`, `#splice_to_eof`
5
+ - Enable splice op in libev `Backend#chain` for non-Linux OS
6
+
7
+ ## 0.56.0 2021-06-22
8
+
9
+ - Implement fake `Backend#splice`, `Backend#splice_to_eof` methods for non-Linux
10
+ OS
11
+
12
+ ## 0.55.0 2021-06-17
13
+
14
+ - Finish io_uring implementation of Backend#chain
15
+ - Reimplement io_uring op_context acquire/release algorithm (using ref count)
16
+ - Fix #gets on sockets
17
+ - Redesign event anti-starvation mechanism
18
+
19
+ ## 0.54.0 2021-06-14
20
+
21
+ - Implement Mutex#owned?, #locked? (#50)
22
+ - Fix arity for SSLSocket#peeraddr (#55)
23
+ - Add missing SSLServer#accept_loop method (#53)
24
+ - Fix SSLSocket buffering behaviour
25
+ - Add recv_loop alias for SSLSocket (#54)
26
+
27
+ ## 0.53.2 2021-05-10
2
28
 
3
29
  - Remove `splice` methods on libev backend on non-Linux OS (#43)
4
30
 
5
- ## 0.53.0
31
+ ## 0.53.0 2021-04-23
6
32
 
7
33
  - Implement `Backend#splice`, `Backend#splice_to_eof`, along with `IO#splice`, `IO#splice_to_eof`
8
34
 
9
- ## 0.52.0
35
+ ## 0.52.0 2021-02-28
10
36
 
11
37
  - Polyphony is now compatible with Ruby 3.0
12
38
  - Add `Backend#sendv` method for sending multiple strings
@@ -16,19 +42,19 @@
16
42
  - libev backend: Use` pidfd_open` for Linux 5.3+, otherwise use a libev child watcher
17
43
  - Use `:call` as default method in `#feed_loop`
18
44
 
19
- ## 0.51.0
45
+ ## 0.51.0 2021-02-02
20
46
 
21
47
  - Implement `IO#feed_loop`, `Socket#feed_loop`
22
48
  - Fix error handling in `Process.kill_and_await`
23
49
 
24
- ## 0.50.1
50
+ ## 0.50.1 2021-01-31
25
51
 
26
52
  - Set `IOSQE_ASYNC` flag in io_uring backend
27
53
  - Fix error handling in `Backend#waitpid`
28
54
  - Reimplement libev backend's `#waitpid` by using pidfd_open (in similar manner
29
55
  to the io_uring backend)
30
56
 
31
- ## 0.50.0
57
+ ## 0.50.0 2021-01-28
32
58
 
33
59
  - Use `Process::CLOCK_MONOTONIC` in Timer
34
60
  - Add `Timer#sleep`, `Timer#after`, `Timer#every`
@@ -36,50 +62,50 @@
36
62
  - Add `Thread#fiber_index_of` method
37
63
  - Use `Backend#wait_event` in `Fiber#await`
38
64
 
39
- ## 0.49.2
65
+ ## 0.49.2 2021-01-19
40
66
 
41
67
  - Fix hang with 100s or more child fibers when terminating
42
68
  - Fix double pending_count increment in io_uring backend
43
69
 
44
- ## 0.49.1
70
+ ## 0.49.1 2021-01-13
45
71
 
46
72
  - Use `TCPSocket` instead of `Socket` in `Net.tcp_connect`
47
73
  - Catch `Errno::ERSCH` in `Process.kill_and_await`
48
74
  - Set io_uring queue size to 2048
49
75
 
50
- ## 0.49.0
76
+ ## 0.49.0 2021-01-11
51
77
 
52
78
  - Implement `Polyphony::Timer` for performant timeouts
53
79
 
54
- ## 0.48.0
80
+ ## 0.48.0 2021-01-05
55
81
 
56
82
  - Implement graceful shutdown
57
83
  - Add support for `break` / `StopIteration` in `spin_loop`
58
84
  - Fix `IO#gets`, `IO#readpartial`
59
85
 
60
- ## 0.47.5.1
86
+ ## 0.47.5.1 2020-11-20
61
87
 
62
88
  - Add missing `Socket#accept_loop` method
63
89
 
64
- ## 0.47.5
90
+ ## 0.47.5 2020-11-20
65
91
 
66
92
  - Add `socket_class` argument to `Backend#accept`, `Backend#accept_loop`
67
93
  - Fix `#supervise` to stop when all children fibers are done
68
94
 
69
- ## 0.47.4
95
+ ## 0.47.4 2020-11-14
70
96
 
71
97
  - Add support for Unix sockets
72
98
 
73
- ## 0.47.3
99
+ ## 0.47.3 2020-11-12
74
100
 
75
101
  - Enable I/O in signal handlers (#45)
76
102
  - Accept `:interval` argument in `#spin_loop`
77
103
 
78
- ## 0.47.2
104
+ ## 0.47.2 2020-11-10
79
105
 
80
106
  - Fix API compatibility between TCPSocket and IO
81
107
 
82
- ## 0.47.0
108
+ ## 0.47.0 2020-11-10
83
109
 
84
110
  - Implement `#spin_scope` used for creating blocking fiber scopes
85
111
  - Reimplement `move_on_after`, `cancel_after`, `Timeout.timeout` using
@@ -87,18 +113,18 @@
87
113
  - Implement `Backend#timeout` API
88
114
  - Implemented capped queues
89
115
 
90
- ## 0.46.1
116
+ ## 0.46.1 2020-11-04
91
117
 
92
118
  - Add `TCPServer#accept_loop`, `OpenSSL::SSL::SSLSocket#accept_loop` method
93
119
  - Fix compilation error on MacOS (#43)
94
120
  - Fix backtrace for `Timeout.timeout`
95
121
  - Add `Backend#timer_loop`
96
122
 
97
- ## 0.46.0
123
+ ## 0.46.0 2020-10-08
98
124
 
99
125
  - Implement [io_uring backend](https://github.com/digital-fabric/polyphony/pull/44)
100
126
 
101
- ## 0.45.5
127
+ ## 0.45.5 2020-10-04
102
128
 
103
129
  - Fix compilation error (#43)
104
130
  - Add support for resetting move_on_after, cancel_after timeouts
@@ -107,22 +133,22 @@
107
133
  - Schedule parent with priority on uncaught exception
108
134
  - Fix race condition in `Mutex#synchronize` (#41)
109
135
 
110
- ## 0.45.4
136
+ ## 0.45.4 2020-09-06
111
137
 
112
138
  - Improve signal trapping mechanism
113
139
 
114
- ## 0.45.3
140
+ ## 0.45.3 2020-09-02
115
141
 
116
142
  - Don't swallow error in `Process#kill_and_await`
117
143
  - Add `Fiber#mailbox` attribute reader
118
144
  - Fix bug in `Fiber.await`
119
145
  - Implement `IO#getc`, `IO#getbyte`
120
146
 
121
- ## 0.45.2
147
+ ## 0.45.2 2020-08-03
122
148
 
123
149
  - Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
124
150
 
125
- ## 0.45.1
151
+ ## 0.45.1 2020-08-01
126
152
 
127
153
  - Fix Net::HTTP compatibility
128
154
  - Fix fs adapter
@@ -132,7 +158,7 @@
132
158
  - Cleanup code
133
159
  - Improve support for Ruby 3 keyword args
134
160
 
135
- ## 0.45.0
161
+ ## 0.45.0 2020-07-29
136
162
 
137
163
  - Cleanup code
138
164
  - Rename `Agent` to `Backend`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.53.1)
4
+ polyphony (0.57.0)
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
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ i, o = IO.pipe
7
+ f = spin { p i.read }
8
+
9
+ o << 'hello'
10
+ o.close
11
+ f.await
@@ -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,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ puts 'Please enter your name:'
7
+ name = gets.chomp
8
+ puts "Hello, #{name}!"
@@ -0,0 +1,186 @@
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
+ #ifdef POLYPHONY_USE_PIDFD_OPEN
9
+ #ifndef __NR_pidfd_open
10
+ #define __NR_pidfd_open 434 /* System call # on most architectures */
11
+ #endif
12
+
13
+ inline int pidfd_open(pid_t pid, unsigned int flags) {
14
+ return syscall(__NR_pidfd_open, pid, flags);
15
+ }
16
+ #endif
17
+
18
+ //////////////////////////////////////////////////////////////////////
19
+ //////////////////////////////////////////////////////////////////////
20
+ // the following is copied verbatim from the Ruby source code (io.c)
21
+
22
+ inline int io_setstrbuf(VALUE *str, long len) {
23
+ #ifdef _WIN32
24
+ len = (len + 1) & ~1L; /* round up for wide char */
25
+ #endif
26
+ if (*str == Qnil) {
27
+ *str = rb_str_new(0, len);
28
+ return 1;
29
+ }
30
+ else {
31
+ VALUE s = StringValue(*str);
32
+ long clen = RSTRING_LEN(s);
33
+ if (clen >= len) {
34
+ rb_str_modify(s);
35
+ return 0;
36
+ }
37
+ len -= clen;
38
+ }
39
+ rb_str_modify_expand(*str, len);
40
+ return 0;
41
+ }
42
+
43
+ #define MAX_REALLOC_GAP 4096
44
+
45
+ inline void io_shrink_read_string(VALUE str, long n) {
46
+ if (rb_str_capacity(str) - n > MAX_REALLOC_GAP) {
47
+ rb_str_resize(str, n);
48
+ }
49
+ }
50
+
51
+ inline void io_set_read_length(VALUE str, long n, int shrinkable) {
52
+ if (RSTRING_LEN(str) != n) {
53
+ rb_str_modify(str);
54
+ rb_str_set_len(str, n);
55
+ if (shrinkable) io_shrink_read_string(str, n);
56
+ }
57
+ }
58
+
59
+ inline rb_encoding* io_read_encoding(rb_io_t *fptr) {
60
+ if (fptr->encs.enc) {
61
+ return fptr->encs.enc;
62
+ }
63
+ return rb_default_external_encoding();
64
+ }
65
+
66
+ inline VALUE io_enc_str(VALUE str, rb_io_t *fptr) {
67
+ OBJ_TAINT(str);
68
+ rb_enc_associate(str, io_read_encoding(fptr));
69
+ return str;
70
+ }
71
+
72
+ //////////////////////////////////////////////////////////////////////
73
+ //////////////////////////////////////////////////////////////////////
74
+
75
+ VALUE backend_await(struct Backend_base *backend) {
76
+ VALUE ret;
77
+ backend->pending_count++;
78
+ ret = Thread_switch_fiber(rb_thread_current());
79
+ backend->pending_count--;
80
+ RB_GC_GUARD(ret);
81
+ return ret;
82
+ }
83
+
84
+ VALUE backend_snooze() {
85
+ Fiber_make_runnable(rb_fiber_current(), Qnil);
86
+ VALUE ret = Thread_switch_fiber(rb_thread_current());
87
+ return ret;
88
+ }
89
+
90
+ inline void rectify_io_file_pos(rb_io_t *fptr) {
91
+ // Apparently after reopening a closed file, the file position is not reset,
92
+ // which causes the read to fail. Fortunately we can use fptr->rbuf.len to
93
+ // find out if that's the case.
94
+ // See: https://github.com/digital-fabric/polyphony/issues/30
95
+ if (fptr->rbuf.len > 0) {
96
+ lseek(fptr->fd, -fptr->rbuf.len, SEEK_CUR);
97
+ fptr->rbuf.len = 0;
98
+ }
99
+ }
100
+
101
+ inline double current_time() {
102
+ struct timespec ts;
103
+ clock_gettime(CLOCK_MONOTONIC, &ts);
104
+ long long ns = ts.tv_sec;
105
+ ns = ns * 1e9 + ts.tv_nsec;
106
+ double t = ns;
107
+ return t / 1e9;
108
+ }
109
+
110
+ inline VALUE backend_timeout_exception(VALUE exception) {
111
+ if (rb_obj_is_kind_of(exception, rb_cArray) == Qtrue)
112
+ return rb_funcall(rb_ary_entry(exception, 0), ID_new, 1, rb_ary_entry(exception, 1));
113
+ else if (rb_obj_is_kind_of(exception, rb_cClass) == Qtrue)
114
+ return rb_funcall(exception, ID_new, 0);
115
+ else
116
+ return rb_funcall(rb_eRuntimeError, ID_new, 1, exception);
117
+ }
118
+
119
+ VALUE Backend_timeout_safe(VALUE arg) {
120
+ return rb_yield(arg);
121
+ }
122
+
123
+ VALUE Backend_timeout_rescue(VALUE arg, VALUE exception) {
124
+ return exception;
125
+ }
126
+
127
+ VALUE Backend_timeout_ensure_safe(VALUE arg) {
128
+ return rb_rescue2(Backend_timeout_safe, Qnil, Backend_timeout_rescue, Qnil, rb_eException, (VALUE)0);
129
+ }
130
+
131
+ static VALUE empty_string = Qnil;
132
+
133
+ VALUE Backend_sendv(VALUE self, VALUE io, VALUE ary, VALUE flags) {
134
+ switch (RARRAY_LEN(ary)) {
135
+ case 0:
136
+ return Qnil;
137
+ case 1:
138
+ return Backend_send(self, io, RARRAY_AREF(ary, 0), flags);
139
+ default:
140
+ if (empty_string == Qnil) {
141
+ empty_string = rb_str_new_literal("");
142
+ rb_global_variable(&empty_string);
143
+ }
144
+ VALUE joined = rb_ary_join(ary, empty_string);
145
+ VALUE result = Backend_send(self, io, joined, flags);
146
+ RB_GC_GUARD(joined);
147
+ return result;
148
+ }
149
+ }
150
+
151
+ inline void io_verify_blocking_mode(rb_io_t *fptr, VALUE io, VALUE blocking) {
152
+ VALUE blocking_mode = rb_ivar_get(io, ID_ivar_blocking_mode);
153
+ if (blocking == blocking_mode) return;
154
+
155
+ rb_ivar_set(io, ID_ivar_blocking_mode, blocking);
156
+
157
+ #ifdef _WIN32
158
+ if (blocking != Qtrue)
159
+ rb_w32_set_nonblock(fptr->fd);
160
+ #elif defined(F_GETFL)
161
+ int flags = fcntl(fptr->fd, F_GETFL);
162
+ if (flags == -1) return;
163
+ int is_nonblocking = flags & O_NONBLOCK;
164
+
165
+ if (blocking == Qtrue) {
166
+ if (!is_nonblocking) return;
167
+ flags &= ~O_NONBLOCK;
168
+ } else {
169
+ if (is_nonblocking) return;
170
+ flags |= O_NONBLOCK;
171
+ }
172
+ fcntl(fptr->fd, F_SETFL, flags);
173
+ #endif
174
+ }
175
+
176
+ inline void backend_run_idle_tasks(struct Backend_base *base) {
177
+ if (base->idle_gc_period == 0) return;
178
+
179
+ double now = current_time();
180
+ if (now - base->idle_gc_last_time < base->idle_gc_period) return;
181
+
182
+ base->idle_gc_last_time = now;
183
+ rb_gc_enable();
184
+ rb_gc_start();
185
+ rb_gc_disable();
186
+ }