polyphony 0.43.11 → 0.45.4
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 +8 -1
- data/CHANGELOG.md +40 -0
- data/Gemfile.lock +18 -8
- data/Rakefile +1 -1
- data/TODO.md +22 -9
- data/docs/_posts/2020-07-26-polyphony-0.44.md +77 -0
- data/docs/api-reference/thread.md +1 -1
- data/docs/getting-started/overview.md +14 -14
- data/docs/getting-started/tutorial.md +1 -1
- data/examples/adapters/redis_client.rb +3 -1
- data/examples/adapters/redis_pubsub_perf.rb +11 -8
- data/examples/adapters/sequel_mysql.rb +23 -0
- data/examples/adapters/sequel_mysql_pool.rb +33 -0
- data/examples/adapters/sequel_pg.rb +24 -0
- data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
- data/examples/core/{xx-channels.rb → channels.rb} +0 -0
- data/examples/core/deferring-an-operation.rb +16 -0
- data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
- data/examples/core/{xx-forking.rb → forking.rb} +1 -1
- data/examples/core/handling-signals.rb +11 -0
- data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
- data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
- data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
- data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
- data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
- data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
- data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
- data/examples/core/supervisor.rb +20 -0
- data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
- data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
- data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
- data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
- data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
- data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
- data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
- data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
- data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
- data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
- data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
- data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
- data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
- data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
- data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
- data/examples/io/{xx-irb.rb → irb.rb} +0 -0
- data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
- data/examples/io/{xx-open.rb → open.rb} +0 -0
- data/examples/io/pry.rb +18 -0
- data/examples/io/rack_server.rb +71 -0
- data/examples/io/raw.rb +14 -0
- data/examples/io/reline.rb +18 -0
- data/examples/io/{xx-system.rb → system.rb} +1 -1
- data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
- data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
- data/examples/io/tunnel.rb +6 -1
- data/examples/io/{xx-zip.rb → zip.rb} +0 -0
- data/examples/performance/fiber_transfer.rb +2 -1
- data/examples/performance/fs_read.rb +5 -6
- data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
- data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
- data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
- data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -1
- data/examples/performance/thread-vs-fiber/polyphony_server_read_loop.rb +1 -1
- data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
- data/examples/performance/thread_pool_perf.rb +6 -7
- data/ext/polyphony/backend.h +40 -0
- data/ext/polyphony/event.c +3 -3
- data/ext/polyphony/extconf.rb +1 -1
- data/ext/polyphony/fiber.c +66 -6
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +237 -238
- data/ext/polyphony/polyphony.c +3 -3
- data/ext/polyphony/polyphony.h +15 -20
- data/ext/polyphony/polyphony_ext.c +3 -4
- data/ext/polyphony/queue.c +5 -6
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/thread.c +36 -33
- data/lib/polyphony.rb +26 -39
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +19 -0
- data/lib/polyphony/adapters/postgres.rb +5 -5
- data/lib/polyphony/adapters/process.rb +2 -5
- data/lib/polyphony/adapters/readline.rb +17 -0
- data/lib/polyphony/adapters/redis.rb +1 -1
- data/lib/polyphony/adapters/sequel.rb +45 -0
- data/lib/polyphony/core/exceptions.rb +11 -0
- data/lib/polyphony/core/global_api.rb +17 -12
- data/lib/polyphony/core/resource_pool.rb +20 -7
- data/lib/polyphony/core/sync.rb +46 -8
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +30 -30
- data/lib/polyphony/extensions/fiber.rb +30 -49
- data/lib/polyphony/extensions/io.rb +60 -16
- data/lib/polyphony/extensions/openssl.rb +6 -6
- data/lib/polyphony/extensions/socket.rb +14 -15
- data/lib/polyphony/extensions/thread.rb +6 -5
- data/lib/polyphony/version.rb +1 -1
- data/polyphony.gemspec +7 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_fiber.rb +29 -12
- data/test/test_io.rb +59 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_resource_pool.rb +29 -4
- data/test/test_signal.rb +16 -37
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +52 -0
- metadata +127 -97
- data/.gitbook.yaml +0 -4
- data/examples/adapters/concurrent-ruby.rb +0 -9
- data/examples/core/04-handling-signals.rb +0 -19
- data/examples/core/xx-agent.rb +0 -102
- data/examples/core/xx-at_exit.rb +0 -29
- data/examples/core/xx-caller.rb +0 -12
- data/examples/core/xx-daemon.rb +0 -14
- data/examples/core/xx-deadlock.rb +0 -8
- data/examples/core/xx-deferring-an-operation.rb +0 -14
- data/examples/core/xx-exception-backtrace.rb +0 -40
- data/examples/core/xx-fork-cleanup.rb +0 -22
- data/examples/core/xx-fork-spin.rb +0 -42
- data/examples/core/xx-fork-terminate.rb +0 -27
- data/examples/core/xx-move_on.rb +0 -23
- data/examples/core/xx-queue-async.rb +0 -120
- data/examples/core/xx-readpartial.rb +0 -18
- data/examples/core/xx-signals.rb +0 -16
- data/examples/core/xx-sleep-forever.rb +0 -9
- data/examples/core/xx-sleeping.rb +0 -25
- data/examples/core/xx-snooze-starve.rb +0 -16
- data/examples/core/xx-spin-fork.rb +0 -49
- data/examples/core/xx-state-machine.rb +0 -51
- data/examples/core/xx-stop.rb +0 -20
- data/examples/core/xx-supervisors.rb +0 -21
- data/examples/core/xx-thread-selector-sleep.rb +0 -51
- data/examples/core/xx-thread-selector-snooze.rb +0 -46
- data/examples/core/xx-thread-snooze.rb +0 -34
- data/examples/core/xx-timer-gc.rb +0 -17
- data/examples/core/xx-trace.rb +0 -79
- data/examples/performance/xx-array.rb +0 -11
- data/examples/performance/xx-fiber-switch.rb +0 -9
- data/examples/performance/xx-snooze.rb +0 -15
- data/examples/xx-spin.rb +0 -32
- data/ext/polyphony/agent.h +0 -41
data/examples/io/raw.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
require 'polyphony'
|
|
5
|
+
require 'polyphony/adapters/readline'
|
|
6
|
+
require 'pry'
|
|
7
|
+
|
|
8
|
+
$counter = 0
|
|
9
|
+
timer = spin do
|
|
10
|
+
throttled_loop(5) do
|
|
11
|
+
$counter += 1
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
at_exit { timer.stop }
|
|
16
|
+
|
|
17
|
+
puts 'try typing $counter to see the counter incremented in the background'
|
|
18
|
+
binding.pry
|
|
File without changes
|
|
File without changes
|
data/examples/io/tunnel.rb
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
require 'bundler/setup'
|
|
4
4
|
require 'polyphony'
|
|
5
5
|
|
|
6
|
+
if ARGV.size < 2
|
|
7
|
+
puts "Usage: ruby examples/tunnel.rb <port1> <port2>"
|
|
8
|
+
exit
|
|
9
|
+
end
|
|
10
|
+
|
|
6
11
|
Ports = ARGV[0..1]
|
|
7
12
|
EndPoints = []
|
|
8
13
|
|
|
@@ -24,7 +29,7 @@ def endpoint_loop(idx, peer_idx)
|
|
|
24
29
|
conn.binmode
|
|
25
30
|
EndPoints[idx] = conn
|
|
26
31
|
log "Client connected on port #{port} (#{conn.remote_address.inspect})"
|
|
27
|
-
|
|
32
|
+
conn.read_loop do |data|
|
|
28
33
|
peer = EndPoints[peer_idx]
|
|
29
34
|
if peer
|
|
30
35
|
peer << data
|
|
File without changes
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require 'bundler/setup'
|
|
4
4
|
require 'polyphony'
|
|
5
|
-
require 'polyphony/fs'
|
|
5
|
+
require 'polyphony/adapters/fs'
|
|
6
6
|
|
|
7
7
|
def raw_read_file(x)
|
|
8
8
|
t0 = Time.now
|
|
@@ -14,7 +14,7 @@ def threaded_read_file(x, y)
|
|
|
14
14
|
t0 = Time.now
|
|
15
15
|
threads = []
|
|
16
16
|
y.times do
|
|
17
|
-
threads << Thread.new { x.times { IO.orig_read(
|
|
17
|
+
threads << Thread.new { x.times { IO.orig_read(__FILE__) } }
|
|
18
18
|
end
|
|
19
19
|
threads.each(&:join)
|
|
20
20
|
puts "threaded_read_file: #{Time.now - t0}"
|
|
@@ -22,11 +22,10 @@ end
|
|
|
22
22
|
|
|
23
23
|
def thread_pool_read_file(x, y)
|
|
24
24
|
t0 = Time.now
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
s.spin { x.times { IO.read(PATH) } }
|
|
28
|
-
end
|
|
25
|
+
y.times do
|
|
26
|
+
spin { x.times { IO.read(__FILE__) } }
|
|
29
27
|
end
|
|
28
|
+
Fiber.current.await_all_children
|
|
30
29
|
puts "thread_pool_read_file: #{Time.now - t0}"
|
|
31
30
|
end
|
|
32
31
|
|
|
File without changes
|
|
@@ -24,7 +24,7 @@ def handle_client(socket)
|
|
|
24
24
|
parser.on_message_complete = proc do |env|
|
|
25
25
|
reqs << Object.new # parser
|
|
26
26
|
end
|
|
27
|
-
|
|
27
|
+
socket.read_loop do |data|
|
|
28
28
|
parser << data
|
|
29
29
|
while (req = reqs.shift)
|
|
30
30
|
handle_request(socket, req)
|
|
@@ -13,7 +13,7 @@ def handle_client(socket)
|
|
|
13
13
|
parser.on_message_complete = proc do |env|
|
|
14
14
|
reqs << Object.new # parser
|
|
15
15
|
end
|
|
16
|
-
|
|
16
|
+
socket.read_loop do |data|
|
|
17
17
|
parser << data
|
|
18
18
|
while (req = reqs.shift)
|
|
19
19
|
handle_request(socket, req)
|
|
@@ -11,11 +11,7 @@ def handle_client(client)
|
|
|
11
11
|
headers = "Content-Length: #{data.bytesize}\r\n"
|
|
12
12
|
client.write "HTTP/1.1 #{status_code}\r\n#{headers}\r\n#{data}"
|
|
13
13
|
end
|
|
14
|
-
|
|
15
|
-
while data = client.readpartial(8192) rescue nil
|
|
16
|
-
parser << data
|
|
17
|
-
end
|
|
18
|
-
end
|
|
14
|
+
client.read_loop { |data| parser << data }
|
|
19
15
|
client.close
|
|
20
16
|
end
|
|
21
17
|
end
|
|
@@ -10,7 +10,7 @@ def lengthy_op
|
|
|
10
10
|
# Digest::SHA256.digest(IO.read('doc/Promise.html'))
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
X =
|
|
13
|
+
X = 10000
|
|
14
14
|
|
|
15
15
|
def compare_performance
|
|
16
16
|
t0 = Time.now
|
|
@@ -35,20 +35,19 @@ def compare_performance
|
|
|
35
35
|
|
|
36
36
|
acc = 0
|
|
37
37
|
count = 0
|
|
38
|
-
|
|
38
|
+
1.times do |_i|
|
|
39
39
|
t0 = Time.now
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
s.spin { Polyphony::ThreadPool.process { lengthy_op } }
|
|
43
|
-
end
|
|
40
|
+
X.times do
|
|
41
|
+
spin { Polyphony::ThreadPool.process { lengthy_op } }
|
|
44
42
|
end
|
|
43
|
+
Fiber.current.await_all_children
|
|
45
44
|
thread_pool_perf = X / (Time.now - t0)
|
|
46
45
|
acc += thread_pool_perf
|
|
47
46
|
count += 1
|
|
48
47
|
end
|
|
49
48
|
avg_perf = acc / count
|
|
50
49
|
puts format(
|
|
51
|
-
'
|
|
50
|
+
'spin X thread pool performance: %g (X %0.2f)',
|
|
52
51
|
avg_perf,
|
|
53
52
|
avg_perf / native_perf
|
|
54
53
|
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#ifndef BACKEND_H
|
|
2
|
+
#define BACKEND_H
|
|
3
|
+
|
|
4
|
+
#include "ruby.h"
|
|
5
|
+
|
|
6
|
+
// backend interface function signatures
|
|
7
|
+
|
|
8
|
+
// VALUE LibevBackend_accept(VALUE self, VALUE sock);
|
|
9
|
+
// VALUE LibevBackend_accept_loop(VALUE self, VALUE sock);
|
|
10
|
+
// VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port);
|
|
11
|
+
// VALUE LibevBackend_finalize(VALUE self);
|
|
12
|
+
// VALUE LibevBackend_post_fork(VALUE self);
|
|
13
|
+
// VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof);
|
|
14
|
+
// VALUE LibevBackend_read_loop(VALUE self, VALUE io);
|
|
15
|
+
// VALUE LibevBackend_sleep(VALUE self, VALUE duration);
|
|
16
|
+
// VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write);
|
|
17
|
+
// VALUE LibevBackend_wait_pid(VALUE self, VALUE pid);
|
|
18
|
+
// VALUE LibevBackend_write(int argc, VALUE *argv, VALUE self);
|
|
19
|
+
|
|
20
|
+
typedef VALUE (* backend_pending_count_t)(VALUE self);
|
|
21
|
+
typedef VALUE (*backend_poll_t)(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue);
|
|
22
|
+
typedef VALUE (* backend_ref_t)(VALUE self);
|
|
23
|
+
typedef int (* backend_ref_count_t)(VALUE self);
|
|
24
|
+
typedef void (* backend_reset_ref_count_t)(VALUE self);
|
|
25
|
+
typedef VALUE (* backend_unref_t)(VALUE self);
|
|
26
|
+
typedef VALUE (* backend_wait_event_t)(VALUE self, VALUE raise_on_exception);
|
|
27
|
+
typedef VALUE (* backend_wakeup_t)(VALUE self);
|
|
28
|
+
|
|
29
|
+
typedef struct backend_interface {
|
|
30
|
+
backend_pending_count_t pending_count;
|
|
31
|
+
backend_poll_t poll;
|
|
32
|
+
backend_ref_t ref;
|
|
33
|
+
backend_ref_count_t ref_count;
|
|
34
|
+
backend_reset_ref_count_t reset_ref_count;
|
|
35
|
+
backend_unref_t unref;
|
|
36
|
+
backend_wait_event_t wait_event;
|
|
37
|
+
backend_wakeup_t wakeup;
|
|
38
|
+
} backend_interface_t;
|
|
39
|
+
|
|
40
|
+
#endif /* BACKEND_H */
|
data/ext/polyphony/event.c
CHANGED
|
@@ -64,13 +64,13 @@ VALUE Event_await(VALUE self) {
|
|
|
64
64
|
if (event->waiting_fiber != Qnil)
|
|
65
65
|
rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
|
|
66
66
|
|
|
67
|
-
VALUE
|
|
67
|
+
VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
|
|
68
68
|
event->waiting_fiber = rb_fiber_current();
|
|
69
|
-
VALUE switchpoint_result =
|
|
69
|
+
VALUE switchpoint_result = __BACKEND__.wait_event(backend, Qnil);
|
|
70
70
|
event->waiting_fiber = Qnil;
|
|
71
71
|
|
|
72
72
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
73
|
-
RB_GC_GUARD(
|
|
73
|
+
RB_GC_GUARD(backend);
|
|
74
74
|
RB_GC_GUARD(switchpoint_result);
|
|
75
75
|
|
|
76
76
|
return switchpoint_result;
|
data/ext/polyphony/extconf.rb
CHANGED
data/ext/polyphony/fiber.c
CHANGED
|
@@ -2,12 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
ID ID_fiber_trace;
|
|
4
4
|
ID ID_ivar_auto_watcher;
|
|
5
|
-
ID
|
|
6
|
-
ID
|
|
7
|
-
ID
|
|
8
|
-
ID ID_trace_runnable;
|
|
9
|
-
ID ID_trace_terminate;
|
|
10
|
-
ID ID_trace_wait;
|
|
5
|
+
ID ID_ivar_mailbox;
|
|
6
|
+
ID ID_ivar_result;
|
|
7
|
+
ID ID_ivar_waiting_fibers;
|
|
11
8
|
|
|
12
9
|
VALUE SYM_dead;
|
|
13
10
|
VALUE SYM_running;
|
|
@@ -67,6 +64,57 @@ void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
|
|
67
64
|
}
|
|
68
65
|
}
|
|
69
66
|
|
|
67
|
+
VALUE Fiber_await(VALUE self) {
|
|
68
|
+
VALUE result;
|
|
69
|
+
|
|
70
|
+
// we compare with false, since a fiber that has not yet started will have
|
|
71
|
+
// @running set to nil
|
|
72
|
+
if (rb_ivar_get(self, ID_ivar_running) == Qfalse) {
|
|
73
|
+
result = rb_ivar_get(self, ID_ivar_result);
|
|
74
|
+
TEST_RESUME_EXCEPTION(result);
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
VALUE fiber = rb_fiber_current();
|
|
79
|
+
VALUE waiting_fibers = rb_ivar_get(self, ID_ivar_waiting_fibers);
|
|
80
|
+
if (waiting_fibers == Qnil) {
|
|
81
|
+
waiting_fibers = rb_hash_new();
|
|
82
|
+
rb_ivar_set(self, ID_ivar_waiting_fibers, waiting_fibers);
|
|
83
|
+
}
|
|
84
|
+
rb_hash_aset(waiting_fibers, fiber, Qtrue);
|
|
85
|
+
|
|
86
|
+
result = Thread_switch_fiber(rb_thread_current());
|
|
87
|
+
|
|
88
|
+
rb_hash_delete(waiting_fibers, fiber);
|
|
89
|
+
TEST_RESUME_EXCEPTION(result);
|
|
90
|
+
RB_GC_GUARD(result);
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
VALUE Fiber_send(VALUE self, VALUE value) {
|
|
95
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
96
|
+
if (mailbox == Qnil) {
|
|
97
|
+
mailbox = rb_funcall(cQueue, ID_new, 0);
|
|
98
|
+
rb_ivar_set(self, ID_ivar_mailbox, mailbox);
|
|
99
|
+
}
|
|
100
|
+
Queue_push(mailbox, value);
|
|
101
|
+
return self;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
VALUE Fiber_receive(VALUE self) {
|
|
105
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
106
|
+
if (mailbox == Qnil) {
|
|
107
|
+
mailbox = rb_funcall(cQueue, ID_new, 0);
|
|
108
|
+
rb_ivar_set(self, ID_ivar_mailbox, mailbox);
|
|
109
|
+
}
|
|
110
|
+
return Queue_shift(mailbox);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
VALUE Fiber_receive_all_pending(VALUE self) {
|
|
114
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
115
|
+
return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
|
|
116
|
+
}
|
|
117
|
+
|
|
70
118
|
void Init_Fiber() {
|
|
71
119
|
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
|
72
120
|
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
|
@@ -74,6 +122,15 @@ void Init_Fiber() {
|
|
|
74
122
|
rb_define_method(cFiber, "state", Fiber_state, 0);
|
|
75
123
|
rb_define_method(cFiber, "auto_watcher", Fiber_auto_watcher, 0);
|
|
76
124
|
|
|
125
|
+
rb_define_method(cFiber, "await", Fiber_await, 0);
|
|
126
|
+
rb_define_method(cFiber, "join", Fiber_await, 0);
|
|
127
|
+
|
|
128
|
+
rb_define_method(cFiber, "<<", Fiber_send, 1);
|
|
129
|
+
rb_define_method(cFiber, "send", Fiber_send, 1);
|
|
130
|
+
|
|
131
|
+
rb_define_method(cFiber, "receive", Fiber_receive, 0);
|
|
132
|
+
rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
|
|
133
|
+
|
|
77
134
|
SYM_dead = ID2SYM(rb_intern("dead"));
|
|
78
135
|
SYM_running = ID2SYM(rb_intern("running"));
|
|
79
136
|
SYM_runnable = ID2SYM(rb_intern("runnable"));
|
|
@@ -85,6 +142,9 @@ void Init_Fiber() {
|
|
|
85
142
|
|
|
86
143
|
ID_fiber_trace = rb_intern("__fiber_trace__");
|
|
87
144
|
ID_ivar_auto_watcher = rb_intern("@auto_watcher");
|
|
145
|
+
ID_ivar_mailbox = rb_intern("@mailbox");
|
|
146
|
+
ID_ivar_result = rb_intern("@result");
|
|
147
|
+
ID_ivar_waiting_fibers = rb_intern("@waiting_fibers");
|
|
88
148
|
|
|
89
149
|
SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
|
|
90
150
|
SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
|
|
@@ -11,157 +11,155 @@
|
|
|
11
11
|
|
|
12
12
|
VALUE cTCPSocket;
|
|
13
13
|
|
|
14
|
-
typedef struct
|
|
14
|
+
typedef struct LibevBackend_t {
|
|
15
15
|
struct ev_loop *ev_loop;
|
|
16
16
|
struct ev_async break_async;
|
|
17
17
|
int running;
|
|
18
18
|
int ref_count;
|
|
19
19
|
int run_no_wait_count;
|
|
20
|
-
}
|
|
20
|
+
} LibevBackend_t;
|
|
21
21
|
|
|
22
|
-
static size_t
|
|
23
|
-
return sizeof(
|
|
22
|
+
static size_t LibevBackend_size(const void *ptr) {
|
|
23
|
+
return sizeof(LibevBackend_t);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
static const rb_data_type_t
|
|
26
|
+
static const rb_data_type_t LibevBackend_type = {
|
|
27
27
|
"Libev",
|
|
28
|
-
{0, 0,
|
|
28
|
+
{0, 0, LibevBackend_size,},
|
|
29
29
|
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
static VALUE
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
return TypedData_Wrap_Struct(klass, &
|
|
32
|
+
static VALUE LibevBackend_allocate(VALUE klass) {
|
|
33
|
+
LibevBackend_t *backend = ALLOC(LibevBackend_t);
|
|
34
|
+
|
|
35
|
+
return TypedData_Wrap_Struct(klass, &LibevBackend_type, backend);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
#define
|
|
39
|
-
TypedData_Get_Struct((obj),
|
|
38
|
+
#define GetLibevBackend(obj, backend) \
|
|
39
|
+
TypedData_Get_Struct((obj), LibevBackend_t, &LibevBackend_type, (backend))
|
|
40
40
|
|
|
41
41
|
void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
|
|
42
42
|
// This callback does nothing, the break async is used solely for breaking out
|
|
43
43
|
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
static VALUE
|
|
47
|
-
|
|
46
|
+
static VALUE LibevBackend_initialize(VALUE self) {
|
|
47
|
+
LibevBackend_t *backend;
|
|
48
48
|
VALUE thread = rb_thread_current();
|
|
49
49
|
int is_main_thread = (thread == rb_thread_main());
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
GetLibevBackend(self, backend);
|
|
52
|
+
backend->ev_loop = is_main_thread ? EV_DEFAULT : ev_loop_new(EVFLAG_NOSIGMASK);
|
|
53
53
|
|
|
54
|
-
ev_async_init(&
|
|
55
|
-
ev_async_start(
|
|
56
|
-
ev_unref(
|
|
54
|
+
ev_async_init(&backend->break_async, break_async_callback);
|
|
55
|
+
ev_async_start(backend->ev_loop, &backend->break_async);
|
|
56
|
+
ev_unref(backend->ev_loop); // don't count the break_async watcher
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
backend->running = 0;
|
|
59
|
+
backend->ref_count = 0;
|
|
60
|
+
backend->run_no_wait_count = 0;
|
|
61
61
|
|
|
62
62
|
return Qnil;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
VALUE
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
VALUE LibevBackend_finalize(VALUE self) {
|
|
66
|
+
LibevBackend_t *backend;
|
|
67
|
+
GetLibevBackend(self, backend);
|
|
68
68
|
|
|
69
|
-
ev_async_stop(
|
|
69
|
+
ev_async_stop(backend->ev_loop, &backend->break_async);
|
|
70
70
|
|
|
71
|
-
if (!ev_is_default_loop(
|
|
71
|
+
if (!ev_is_default_loop(backend->ev_loop)) ev_loop_destroy(backend->ev_loop);
|
|
72
72
|
|
|
73
73
|
return self;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
VALUE
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (!ev_is_default_loop(agent->ev_loop)) {
|
|
81
|
-
// post_fork is called only for the main thread of the forked process. If
|
|
82
|
-
// the forked process was forked from a thread other than the main one,
|
|
83
|
-
// we remove the old non-default ev_loop and use the default one instead.
|
|
84
|
-
ev_loop_destroy(agent->ev_loop);
|
|
85
|
-
agent->ev_loop = EV_DEFAULT;
|
|
86
|
-
}
|
|
76
|
+
VALUE LibevBackend_post_fork(VALUE self) {
|
|
77
|
+
LibevBackend_t *backend;
|
|
78
|
+
GetLibevBackend(self, backend);
|
|
87
79
|
|
|
88
|
-
|
|
80
|
+
// After fork there may be some watchers still active left over from the
|
|
81
|
+
// parent, so we destroy the loop, even if it's the default one, then use the
|
|
82
|
+
// default one, as post_fork is called only from the main thread of the forked
|
|
83
|
+
// process. That way we don't need to call ev_loop_fork, since the loop is
|
|
84
|
+
// always a fresh one.
|
|
85
|
+
ev_loop_destroy(backend->ev_loop);
|
|
86
|
+
backend->ev_loop = EV_DEFAULT;
|
|
89
87
|
|
|
90
88
|
return self;
|
|
91
89
|
}
|
|
92
90
|
|
|
93
|
-
VALUE
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
VALUE LibevBackend_ref(VALUE self) {
|
|
92
|
+
LibevBackend_t *backend;
|
|
93
|
+
GetLibevBackend(self, backend);
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
return self;
|
|
95
|
+
backend->ref_count++;
|
|
96
|
+
return self;
|
|
99
97
|
}
|
|
100
98
|
|
|
101
|
-
VALUE
|
|
102
|
-
|
|
103
|
-
|
|
99
|
+
VALUE LibevBackend_unref(VALUE self) {
|
|
100
|
+
LibevBackend_t *backend;
|
|
101
|
+
GetLibevBackend(self, backend);
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
return self;
|
|
103
|
+
backend->ref_count--;
|
|
104
|
+
return self;
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
int
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
int LibevBackend_ref_count(VALUE self) {
|
|
108
|
+
LibevBackend_t *backend;
|
|
109
|
+
GetLibevBackend(self, backend);
|
|
112
110
|
|
|
113
|
-
return
|
|
111
|
+
return backend->ref_count;
|
|
114
112
|
}
|
|
115
113
|
|
|
116
|
-
void
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
void LibevBackend_reset_ref_count(VALUE self) {
|
|
115
|
+
LibevBackend_t *backend;
|
|
116
|
+
GetLibevBackend(self, backend);
|
|
119
117
|
|
|
120
|
-
|
|
118
|
+
backend->ref_count = 0;
|
|
121
119
|
}
|
|
122
120
|
|
|
123
|
-
VALUE
|
|
121
|
+
VALUE LibevBackend_pending_count(VALUE self) {
|
|
124
122
|
int count;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
count = ev_pending_count(
|
|
123
|
+
LibevBackend_t *backend;
|
|
124
|
+
GetLibevBackend(self, backend);
|
|
125
|
+
count = ev_pending_count(backend->ev_loop);
|
|
128
126
|
return INT2NUM(count);
|
|
129
127
|
}
|
|
130
128
|
|
|
131
|
-
VALUE
|
|
129
|
+
VALUE LibevBackend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE queue) {
|
|
132
130
|
int is_nowait = nowait == Qtrue;
|
|
133
|
-
|
|
134
|
-
|
|
131
|
+
LibevBackend_t *backend;
|
|
132
|
+
GetLibevBackend(self, backend);
|
|
135
133
|
|
|
136
134
|
if (is_nowait) {
|
|
137
135
|
long runnable_count = Queue_len(queue);
|
|
138
|
-
|
|
139
|
-
if (
|
|
136
|
+
backend->run_no_wait_count++;
|
|
137
|
+
if (backend->run_no_wait_count < runnable_count || backend->run_no_wait_count < 10)
|
|
140
138
|
return self;
|
|
141
139
|
}
|
|
142
140
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
ev_run(
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
backend->run_no_wait_count = 0;
|
|
142
|
+
|
|
143
|
+
COND_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
|
|
144
|
+
backend->running = 1;
|
|
145
|
+
ev_run(backend->ev_loop, is_nowait ? EVRUN_NOWAIT : EVRUN_ONCE);
|
|
146
|
+
backend->running = 0;
|
|
147
|
+
COND_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
|
|
150
148
|
|
|
151
149
|
return self;
|
|
152
150
|
}
|
|
153
151
|
|
|
154
|
-
VALUE
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
VALUE LibevBackend_wakeup(VALUE self) {
|
|
153
|
+
LibevBackend_t *backend;
|
|
154
|
+
GetLibevBackend(self, backend);
|
|
157
155
|
|
|
158
|
-
if (
|
|
156
|
+
if (backend->running) {
|
|
159
157
|
// Since the loop will run until at least one event has occurred, we signal
|
|
160
158
|
// the selector's associated async watcher, which will cause the ev loop to
|
|
161
159
|
// return. In contrast to using `ev_break` to break out of the loop, which
|
|
162
160
|
// should be called from the same thread (from within the ev_loop), using an
|
|
163
161
|
// `ev_async` allows us to interrupt the event loop across threads.
|
|
164
|
-
ev_async_send(
|
|
162
|
+
ev_async_send(backend->ev_loop, &backend->break_async);
|
|
165
163
|
return Qtrue;
|
|
166
164
|
}
|
|
167
165
|
|
|
@@ -240,40 +238,47 @@ struct libev_io {
|
|
|
240
238
|
VALUE fiber;
|
|
241
239
|
};
|
|
242
240
|
|
|
243
|
-
void
|
|
241
|
+
void LibevBackend_io_callback(EV_P_ ev_io *w, int revents)
|
|
244
242
|
{
|
|
245
243
|
struct libev_io *watcher = (struct libev_io *)w;
|
|
246
244
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
|
247
245
|
}
|
|
248
246
|
|
|
249
|
-
inline VALUE libev_await(
|
|
247
|
+
inline VALUE libev_await(LibevBackend_t *backend) {
|
|
250
248
|
VALUE ret;
|
|
251
|
-
|
|
249
|
+
backend->ref_count++;
|
|
252
250
|
ret = Thread_switch_fiber(rb_thread_current());
|
|
253
|
-
|
|
251
|
+
backend->ref_count--;
|
|
254
252
|
RB_GC_GUARD(ret);
|
|
255
253
|
return ret;
|
|
256
254
|
}
|
|
257
255
|
|
|
258
|
-
VALUE
|
|
259
|
-
LibevAgent_t *agent;
|
|
260
|
-
GetLibevAgent(self, agent);
|
|
261
|
-
return libev_await(agent);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
VALUE libev_io_wait(LibevAgent_t *agent, struct libev_io *watcher, rb_io_t *fptr, int flags) {
|
|
256
|
+
VALUE libev_wait_fd_with_watcher(LibevBackend_t *backend, int fd, struct libev_io *watcher, int events) {
|
|
265
257
|
VALUE switchpoint_result;
|
|
266
258
|
|
|
267
259
|
if (watcher->fiber == Qnil) {
|
|
268
260
|
watcher->fiber = rb_fiber_current();
|
|
269
|
-
ev_io_init(&watcher->io,
|
|
261
|
+
ev_io_init(&watcher->io, LibevBackend_io_callback, fd, events);
|
|
270
262
|
}
|
|
271
|
-
ev_io_start(
|
|
272
|
-
|
|
273
|
-
|
|
263
|
+
ev_io_start(backend->ev_loop, &watcher->io);
|
|
264
|
+
|
|
265
|
+
switchpoint_result = libev_await(backend);
|
|
266
|
+
|
|
267
|
+
ev_io_stop(backend->ev_loop, &watcher->io);
|
|
268
|
+
RB_GC_GUARD(switchpoint_result);
|
|
269
|
+
return switchpoint_result;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
VALUE libev_wait_fd(LibevBackend_t *backend, int fd, int events, int raise_exception) {
|
|
273
|
+
struct libev_io watcher;
|
|
274
|
+
VALUE switchpoint_result = Qnil;
|
|
275
|
+
watcher.fiber = Qnil;
|
|
274
276
|
|
|
277
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fd, &watcher, events);
|
|
278
|
+
|
|
279
|
+
if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
275
280
|
RB_GC_GUARD(switchpoint_result);
|
|
276
|
-
return switchpoint_result;
|
|
281
|
+
return switchpoint_result;
|
|
277
282
|
}
|
|
278
283
|
|
|
279
284
|
VALUE libev_snooze() {
|
|
@@ -290,24 +295,23 @@ ID ID_ivar_is_nonblocking;
|
|
|
290
295
|
// benchmarks (with a "hello world" HTTP server) show throughput is improved
|
|
291
296
|
// by 10-13%.
|
|
292
297
|
inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
|
|
298
|
+
VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
|
|
299
|
+
if (is_nonblocking == Qtrue) return;
|
|
300
|
+
|
|
301
|
+
rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
|
|
302
|
+
|
|
293
303
|
#ifdef _WIN32
|
|
294
|
-
|
|
304
|
+
rb_w32_set_nonblock(fptr->fd);
|
|
295
305
|
#elif defined(F_GETFL)
|
|
296
|
-
|
|
297
|
-
if (
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (oflags == -1) return;
|
|
301
|
-
if (oflags & O_NONBLOCK) return;
|
|
302
|
-
oflags |= O_NONBLOCK;
|
|
303
|
-
fcntl(fptr->fd, F_SETFL, oflags);
|
|
304
|
-
}
|
|
306
|
+
int oflags = fcntl(fptr->fd, F_GETFL);
|
|
307
|
+
if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
|
|
308
|
+
oflags |= O_NONBLOCK;
|
|
309
|
+
fcntl(fptr->fd, F_SETFL, oflags);
|
|
305
310
|
#endif
|
|
306
|
-
return;
|
|
307
311
|
}
|
|
308
312
|
|
|
309
|
-
VALUE
|
|
310
|
-
|
|
313
|
+
VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
|
314
|
+
LibevBackend_t *backend;
|
|
311
315
|
struct libev_io watcher;
|
|
312
316
|
rb_io_t *fptr;
|
|
313
317
|
long dynamic_len = length == Qnil;
|
|
@@ -319,13 +323,13 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
319
323
|
int read_to_eof = RTEST(to_eof);
|
|
320
324
|
VALUE underlying_io = rb_iv_get(io, "@io");
|
|
321
325
|
|
|
322
|
-
|
|
326
|
+
GetLibevBackend(self, backend);
|
|
323
327
|
if (underlying_io != Qnil) io = underlying_io;
|
|
324
328
|
GetOpenFile(io, fptr);
|
|
325
329
|
rb_io_check_byte_readable(fptr);
|
|
326
330
|
io_set_nonblock(fptr, io);
|
|
327
331
|
watcher.fiber = Qnil;
|
|
328
|
-
|
|
332
|
+
|
|
329
333
|
OBJ_TAINT(str);
|
|
330
334
|
|
|
331
335
|
// Apparently after reopening a closed file, the file position is not reset,
|
|
@@ -342,12 +346,14 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
342
346
|
if (n < 0) {
|
|
343
347
|
int e = errno;
|
|
344
348
|
if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
|
|
345
|
-
|
|
346
|
-
switchpoint_result =
|
|
349
|
+
|
|
350
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
351
|
+
|
|
347
352
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
348
353
|
}
|
|
349
354
|
else {
|
|
350
355
|
switchpoint_result = libev_snooze();
|
|
356
|
+
|
|
351
357
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
352
358
|
|
|
353
359
|
if (n == 0) break; // EOF
|
|
@@ -356,7 +362,7 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
356
362
|
|
|
357
363
|
if (total == len) {
|
|
358
364
|
if (!dynamic_len) break;
|
|
359
|
-
|
|
365
|
+
|
|
360
366
|
rb_str_resize(str, total);
|
|
361
367
|
rb_str_modify_expand(str, len);
|
|
362
368
|
buf = RSTRING_PTR(str) + total;
|
|
@@ -366,20 +372,21 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
366
372
|
else buf += n;
|
|
367
373
|
}
|
|
368
374
|
}
|
|
369
|
-
if (total == 0) return Qnil;
|
|
370
375
|
|
|
371
376
|
io_set_read_length(str, total, shrinkable);
|
|
372
377
|
io_enc_str(str, fptr);
|
|
373
|
-
|
|
378
|
+
|
|
379
|
+
if (total == 0) return Qnil;
|
|
380
|
+
|
|
374
381
|
RB_GC_GUARD(watcher.fiber);
|
|
375
382
|
RB_GC_GUARD(switchpoint_result);
|
|
376
383
|
|
|
377
384
|
return str;
|
|
378
385
|
error:
|
|
379
|
-
return
|
|
386
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
380
387
|
}
|
|
381
388
|
|
|
382
|
-
VALUE
|
|
389
|
+
VALUE LibevBackend_read_loop(VALUE self, VALUE io) {
|
|
383
390
|
|
|
384
391
|
#define PREPARE_STR() { \
|
|
385
392
|
str = Qnil; \
|
|
@@ -396,7 +403,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
396
403
|
PREPARE_STR(); \
|
|
397
404
|
}
|
|
398
405
|
|
|
399
|
-
|
|
406
|
+
LibevBackend_t *backend;
|
|
400
407
|
struct libev_io watcher;
|
|
401
408
|
rb_io_t *fptr;
|
|
402
409
|
VALUE str;
|
|
@@ -409,7 +416,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
409
416
|
|
|
410
417
|
PREPARE_STR();
|
|
411
418
|
|
|
412
|
-
|
|
419
|
+
GetLibevBackend(self, backend);
|
|
413
420
|
if (underlying_io != Qnil) io = underlying_io;
|
|
414
421
|
GetOpenFile(io, fptr);
|
|
415
422
|
rb_io_check_byte_readable(fptr);
|
|
@@ -431,22 +438,17 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
431
438
|
int e = errno;
|
|
432
439
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
433
440
|
|
|
434
|
-
switchpoint_result =
|
|
441
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
435
442
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
436
443
|
}
|
|
437
444
|
else {
|
|
438
445
|
switchpoint_result = libev_snooze();
|
|
439
|
-
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
440
446
|
|
|
441
|
-
if (
|
|
447
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
442
448
|
|
|
449
|
+
if (n == 0) break; // EOF
|
|
443
450
|
total = n;
|
|
444
451
|
YIELD_STR();
|
|
445
|
-
Fiber_make_runnable(rb_fiber_current(), Qnil);
|
|
446
|
-
switchpoint_result = Thread_switch_fiber(rb_thread_current());
|
|
447
|
-
if (TEST_EXCEPTION(switchpoint_result)) {
|
|
448
|
-
goto error;
|
|
449
|
-
}
|
|
450
452
|
}
|
|
451
453
|
}
|
|
452
454
|
|
|
@@ -456,11 +458,11 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
456
458
|
|
|
457
459
|
return io;
|
|
458
460
|
error:
|
|
459
|
-
return
|
|
461
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
460
462
|
}
|
|
461
463
|
|
|
462
|
-
VALUE
|
|
463
|
-
|
|
464
|
+
VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
|
|
465
|
+
LibevBackend_t *backend;
|
|
464
466
|
struct libev_io watcher;
|
|
465
467
|
rb_io_t *fptr;
|
|
466
468
|
VALUE switchpoint_result = Qnil;
|
|
@@ -471,7 +473,7 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
471
473
|
|
|
472
474
|
underlying_io = rb_iv_get(io, "@io");
|
|
473
475
|
if (underlying_io != Qnil) io = underlying_io;
|
|
474
|
-
|
|
476
|
+
GetLibevBackend(self, backend);
|
|
475
477
|
io = rb_io_get_write_io(io);
|
|
476
478
|
GetOpenFile(io, fptr);
|
|
477
479
|
watcher.fiber = Qnil;
|
|
@@ -481,7 +483,9 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
481
483
|
if (n < 0) {
|
|
482
484
|
int e = errno;
|
|
483
485
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
484
|
-
|
|
486
|
+
|
|
487
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
|
488
|
+
|
|
485
489
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
486
490
|
}
|
|
487
491
|
else {
|
|
@@ -492,6 +496,7 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
492
496
|
|
|
493
497
|
if (watcher.fiber == Qnil) {
|
|
494
498
|
switchpoint_result = libev_snooze();
|
|
499
|
+
|
|
495
500
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
496
501
|
}
|
|
497
502
|
|
|
@@ -500,11 +505,11 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
500
505
|
|
|
501
506
|
return INT2NUM(len);
|
|
502
507
|
error:
|
|
503
|
-
return
|
|
508
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
504
509
|
}
|
|
505
510
|
|
|
506
|
-
VALUE
|
|
507
|
-
|
|
511
|
+
VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
512
|
+
LibevBackend_t *backend;
|
|
508
513
|
struct libev_io watcher;
|
|
509
514
|
rb_io_t *fptr;
|
|
510
515
|
VALUE switchpoint_result = Qnil;
|
|
@@ -517,7 +522,7 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
517
522
|
|
|
518
523
|
underlying_io = rb_iv_get(io, "@io");
|
|
519
524
|
if (underlying_io != Qnil) io = underlying_io;
|
|
520
|
-
|
|
525
|
+
GetLibevBackend(self, backend);
|
|
521
526
|
io = rb_io_get_write_io(io);
|
|
522
527
|
GetOpenFile(io, fptr);
|
|
523
528
|
watcher.fiber = Qnil;
|
|
@@ -537,7 +542,8 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
537
542
|
int e = errno;
|
|
538
543
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
539
544
|
|
|
540
|
-
switchpoint_result =
|
|
545
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
|
546
|
+
|
|
541
547
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
542
548
|
}
|
|
543
549
|
else {
|
|
@@ -560,6 +566,7 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
560
566
|
}
|
|
561
567
|
if (watcher.fiber == Qnil) {
|
|
562
568
|
switchpoint_result = libev_snooze();
|
|
569
|
+
|
|
563
570
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
564
571
|
}
|
|
565
572
|
|
|
@@ -570,23 +577,23 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
570
577
|
return INT2NUM(total_written);
|
|
571
578
|
error:
|
|
572
579
|
free(iov);
|
|
573
|
-
return
|
|
580
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
574
581
|
}
|
|
575
582
|
|
|
576
|
-
VALUE
|
|
583
|
+
VALUE LibevBackend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
577
584
|
if (argc < 2)
|
|
578
585
|
// TODO: raise ArgumentError
|
|
579
586
|
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
|
580
|
-
|
|
587
|
+
|
|
581
588
|
return (argc == 2) ?
|
|
582
|
-
|
|
583
|
-
|
|
589
|
+
LibevBackend_write(self, argv[0], argv[1]) :
|
|
590
|
+
LibevBackend_writev(self, argv[0], argc - 1, argv + 1);
|
|
584
591
|
}
|
|
585
592
|
|
|
586
593
|
///////////////////////////////////////////////////////////////////////////
|
|
587
594
|
|
|
588
|
-
VALUE
|
|
589
|
-
|
|
595
|
+
VALUE LibevBackend_accept(VALUE self, VALUE sock) {
|
|
596
|
+
LibevBackend_t *backend;
|
|
590
597
|
struct libev_io watcher;
|
|
591
598
|
rb_io_t *fptr;
|
|
592
599
|
int fd;
|
|
@@ -596,7 +603,7 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
596
603
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
|
597
604
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
|
598
605
|
|
|
599
|
-
|
|
606
|
+
GetLibevBackend(self, backend);
|
|
600
607
|
GetOpenFile(sock, fptr);
|
|
601
608
|
io_set_nonblock(fptr, sock);
|
|
602
609
|
watcher.fiber = Qnil;
|
|
@@ -606,13 +613,15 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
606
613
|
int e = errno;
|
|
607
614
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
608
615
|
|
|
609
|
-
switchpoint_result =
|
|
616
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
617
|
+
|
|
610
618
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
611
619
|
}
|
|
612
620
|
else {
|
|
613
621
|
VALUE socket;
|
|
614
622
|
rb_io_t *fp;
|
|
615
623
|
switchpoint_result = libev_snooze();
|
|
624
|
+
|
|
616
625
|
if (TEST_EXCEPTION(switchpoint_result)) {
|
|
617
626
|
close(fd); // close fd since we're raising an exception
|
|
618
627
|
goto error;
|
|
@@ -626,7 +635,7 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
626
635
|
rb_io_ascii8bit_binmode(socket);
|
|
627
636
|
io_set_nonblock(fp, socket);
|
|
628
637
|
rb_io_synchronized(fp);
|
|
629
|
-
|
|
638
|
+
|
|
630
639
|
// if (rsock_do_not_reverse_lookup) {
|
|
631
640
|
// fp->mode |= FMODE_NOREVLOOKUP;
|
|
632
641
|
// }
|
|
@@ -636,11 +645,11 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
636
645
|
RB_GC_GUARD(switchpoint_result);
|
|
637
646
|
return Qnil;
|
|
638
647
|
error:
|
|
639
|
-
return
|
|
648
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
640
649
|
}
|
|
641
650
|
|
|
642
|
-
VALUE
|
|
643
|
-
|
|
651
|
+
VALUE LibevBackend_accept_loop(VALUE self, VALUE sock) {
|
|
652
|
+
LibevBackend_t *backend;
|
|
644
653
|
struct libev_io watcher;
|
|
645
654
|
rb_io_t *fptr;
|
|
646
655
|
int fd;
|
|
@@ -651,7 +660,7 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
|
651
660
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
|
652
661
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
|
653
662
|
|
|
654
|
-
|
|
663
|
+
GetLibevBackend(self, backend);
|
|
655
664
|
GetOpenFile(sock, fptr);
|
|
656
665
|
io_set_nonblock(fptr, sock);
|
|
657
666
|
watcher.fiber = Qnil;
|
|
@@ -662,17 +671,19 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
|
662
671
|
int e = errno;
|
|
663
672
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
664
673
|
|
|
665
|
-
switchpoint_result =
|
|
674
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
675
|
+
|
|
666
676
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
667
677
|
}
|
|
668
678
|
else {
|
|
669
679
|
rb_io_t *fp;
|
|
670
680
|
switchpoint_result = libev_snooze();
|
|
681
|
+
|
|
671
682
|
if (TEST_EXCEPTION(switchpoint_result)) {
|
|
672
683
|
close(fd); // close fd since we're raising an exception
|
|
673
684
|
goto error;
|
|
674
685
|
}
|
|
675
|
-
|
|
686
|
+
|
|
676
687
|
socket = rb_obj_alloc(cTCPSocket);
|
|
677
688
|
MakeOpenFile(socket, fp);
|
|
678
689
|
rb_update_max_fd(fd);
|
|
@@ -692,11 +703,11 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
|
692
703
|
RB_GC_GUARD(switchpoint_result);
|
|
693
704
|
return Qnil;
|
|
694
705
|
error:
|
|
695
|
-
return
|
|
706
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
696
707
|
}
|
|
697
708
|
|
|
698
|
-
VALUE
|
|
699
|
-
|
|
709
|
+
VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
710
|
+
LibevBackend_t *backend;
|
|
700
711
|
struct libev_io watcher;
|
|
701
712
|
rb_io_t *fptr;
|
|
702
713
|
struct sockaddr_in addr;
|
|
@@ -705,12 +716,12 @@ VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
|
705
716
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
|
706
717
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
|
707
718
|
|
|
708
|
-
|
|
719
|
+
GetLibevBackend(self, backend);
|
|
709
720
|
GetOpenFile(sock, fptr);
|
|
710
721
|
io_set_nonblock(fptr, sock);
|
|
711
722
|
watcher.fiber = Qnil;
|
|
712
723
|
|
|
713
|
-
addr.sin_family = AF_INET;
|
|
724
|
+
addr.sin_family = AF_INET;
|
|
714
725
|
addr.sin_addr.s_addr = inet_addr(host_buf);
|
|
715
726
|
addr.sin_port = htons(NUM2INT(port));
|
|
716
727
|
|
|
@@ -718,44 +729,32 @@ VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
|
718
729
|
if (result < 0) {
|
|
719
730
|
int e = errno;
|
|
720
731
|
if (e != EINPROGRESS) rb_syserr_fail(e, strerror(e));
|
|
721
|
-
|
|
732
|
+
|
|
733
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
|
734
|
+
|
|
722
735
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
723
736
|
}
|
|
724
737
|
else {
|
|
725
738
|
switchpoint_result = libev_snooze();
|
|
739
|
+
|
|
726
740
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
727
741
|
}
|
|
728
742
|
RB_GC_GUARD(switchpoint_result);
|
|
729
743
|
return sock;
|
|
730
744
|
error:
|
|
731
|
-
return
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
VALUE libev_wait_fd(LibevAgent_t *agent, int fd, int events, int raise_exception) {
|
|
735
|
-
struct libev_io watcher;
|
|
736
|
-
VALUE switchpoint_result = Qnil;
|
|
737
|
-
|
|
738
|
-
watcher.fiber = rb_fiber_current();
|
|
739
|
-
ev_io_init(&watcher.io, LibevAgent_io_callback, fd, events);
|
|
740
|
-
ev_io_start(agent->ev_loop, &watcher.io);
|
|
741
|
-
switchpoint_result = libev_await(agent);
|
|
742
|
-
ev_io_stop(agent->ev_loop, &watcher.io);
|
|
743
|
-
|
|
744
|
-
if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
745
|
-
RB_GC_GUARD(switchpoint_result);
|
|
746
|
-
return switchpoint_result;
|
|
745
|
+
return RAISE_EXCEPTION(switchpoint_result);
|
|
747
746
|
}
|
|
748
747
|
|
|
749
|
-
VALUE
|
|
750
|
-
|
|
748
|
+
VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
749
|
+
LibevBackend_t *backend;
|
|
751
750
|
rb_io_t *fptr;
|
|
752
751
|
int events = RTEST(write) ? EV_WRITE : EV_READ;
|
|
753
752
|
VALUE underlying_io = rb_iv_get(io, "@io");
|
|
754
753
|
if (underlying_io != Qnil) io = underlying_io;
|
|
755
|
-
|
|
754
|
+
GetLibevBackend(self, backend);
|
|
756
755
|
GetOpenFile(io, fptr);
|
|
757
|
-
|
|
758
|
-
return libev_wait_fd(
|
|
756
|
+
|
|
757
|
+
return libev_wait_fd(backend, fptr->fd, events, 1);
|
|
759
758
|
}
|
|
760
759
|
|
|
761
760
|
struct libev_timer {
|
|
@@ -763,26 +762,25 @@ struct libev_timer {
|
|
|
763
762
|
VALUE fiber;
|
|
764
763
|
};
|
|
765
764
|
|
|
766
|
-
void
|
|
765
|
+
void LibevBackend_timer_callback(EV_P_ ev_timer *w, int revents)
|
|
767
766
|
{
|
|
768
767
|
struct libev_timer *watcher = (struct libev_timer *)w;
|
|
769
768
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
|
770
769
|
}
|
|
771
770
|
|
|
772
|
-
VALUE
|
|
773
|
-
|
|
771
|
+
VALUE LibevBackend_sleep(VALUE self, VALUE duration) {
|
|
772
|
+
LibevBackend_t *backend;
|
|
774
773
|
struct libev_timer watcher;
|
|
775
774
|
VALUE switchpoint_result = Qnil;
|
|
776
775
|
|
|
777
|
-
|
|
776
|
+
GetLibevBackend(self, backend);
|
|
778
777
|
watcher.fiber = rb_fiber_current();
|
|
779
|
-
ev_timer_init(&watcher.timer,
|
|
780
|
-
ev_timer_start(
|
|
781
|
-
|
|
782
|
-
switchpoint_result = libev_await(agent);
|
|
778
|
+
ev_timer_init(&watcher.timer, LibevBackend_timer_callback, NUM2DBL(duration), 0.);
|
|
779
|
+
ev_timer_start(backend->ev_loop, &watcher.timer);
|
|
783
780
|
|
|
784
|
-
|
|
781
|
+
switchpoint_result = libev_await(backend);
|
|
785
782
|
|
|
783
|
+
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
|
786
784
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
787
785
|
RB_GC_GUARD(watcher.fiber);
|
|
788
786
|
RB_GC_GUARD(switchpoint_result);
|
|
@@ -794,7 +792,7 @@ struct libev_child {
|
|
|
794
792
|
VALUE fiber;
|
|
795
793
|
};
|
|
796
794
|
|
|
797
|
-
void
|
|
795
|
+
void LibevBackend_child_callback(EV_P_ ev_child *w, int revents)
|
|
798
796
|
{
|
|
799
797
|
struct libev_child *watcher = (struct libev_child *)w;
|
|
800
798
|
int exit_status = w->rstatus >> 8; // weird, why should we do this?
|
|
@@ -804,87 +802,88 @@ void LibevAgent_child_callback(EV_P_ ev_child *w, int revents)
|
|
|
804
802
|
Fiber_make_runnable(watcher->fiber, status);
|
|
805
803
|
}
|
|
806
804
|
|
|
807
|
-
VALUE
|
|
808
|
-
|
|
805
|
+
VALUE LibevBackend_waitpid(VALUE self, VALUE pid) {
|
|
806
|
+
LibevBackend_t *backend;
|
|
809
807
|
struct libev_child watcher;
|
|
810
808
|
VALUE switchpoint_result = Qnil;
|
|
811
|
-
|
|
809
|
+
GetLibevBackend(self, backend);
|
|
812
810
|
|
|
813
811
|
watcher.fiber = rb_fiber_current();
|
|
814
|
-
ev_child_init(&watcher.child,
|
|
815
|
-
ev_child_start(
|
|
816
|
-
|
|
817
|
-
switchpoint_result = libev_await(agent);
|
|
818
|
-
ev_child_stop(agent->ev_loop, &watcher.child);
|
|
812
|
+
ev_child_init(&watcher.child, LibevBackend_child_callback, NUM2INT(pid), 0);
|
|
813
|
+
ev_child_start(backend->ev_loop, &watcher.child);
|
|
819
814
|
|
|
815
|
+
switchpoint_result = libev_await(backend);
|
|
816
|
+
|
|
817
|
+
ev_child_stop(backend->ev_loop, &watcher.child);
|
|
820
818
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
821
819
|
RB_GC_GUARD(watcher.fiber);
|
|
822
820
|
RB_GC_GUARD(switchpoint_result);
|
|
823
821
|
return switchpoint_result;
|
|
824
822
|
}
|
|
825
823
|
|
|
826
|
-
struct ev_loop *
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
return
|
|
824
|
+
struct ev_loop *LibevBackend_ev_loop(VALUE self) {
|
|
825
|
+
LibevBackend_t *backend;
|
|
826
|
+
GetLibevBackend(self, backend);
|
|
827
|
+
return backend->ev_loop;
|
|
830
828
|
}
|
|
831
829
|
|
|
832
|
-
void
|
|
830
|
+
void LibevBackend_async_callback(EV_P_ ev_async *w, int revents) { }
|
|
833
831
|
|
|
834
|
-
VALUE
|
|
835
|
-
|
|
832
|
+
VALUE LibevBackend_wait_event(VALUE self, VALUE raise) {
|
|
833
|
+
LibevBackend_t *backend;
|
|
836
834
|
VALUE switchpoint_result = Qnil;
|
|
837
|
-
|
|
835
|
+
GetLibevBackend(self, backend);
|
|
838
836
|
|
|
839
837
|
struct ev_async async;
|
|
840
838
|
|
|
841
|
-
ev_async_init(&async,
|
|
842
|
-
ev_async_start(
|
|
843
|
-
|
|
844
|
-
|
|
839
|
+
ev_async_init(&async, LibevBackend_async_callback);
|
|
840
|
+
ev_async_start(backend->ev_loop, &async);
|
|
841
|
+
|
|
842
|
+
switchpoint_result = libev_await(backend);
|
|
845
843
|
|
|
844
|
+
ev_async_stop(backend->ev_loop, &async);
|
|
846
845
|
if (RTEST(raise)) TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
847
846
|
RB_GC_GUARD(switchpoint_result);
|
|
848
847
|
return switchpoint_result;
|
|
849
848
|
}
|
|
850
849
|
|
|
851
|
-
void
|
|
850
|
+
void Init_LibevBackend() {
|
|
852
851
|
rb_require("socket");
|
|
853
852
|
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
|
854
853
|
|
|
855
|
-
VALUE
|
|
856
|
-
rb_define_alloc_func(
|
|
854
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
|
855
|
+
rb_define_alloc_func(cBackend, LibevBackend_allocate);
|
|
857
856
|
|
|
858
|
-
rb_define_method(
|
|
859
|
-
rb_define_method(
|
|
860
|
-
rb_define_method(
|
|
861
|
-
rb_define_method(
|
|
857
|
+
rb_define_method(cBackend, "initialize", LibevBackend_initialize, 0);
|
|
858
|
+
rb_define_method(cBackend, "finalize", LibevBackend_finalize, 0);
|
|
859
|
+
rb_define_method(cBackend, "post_fork", LibevBackend_post_fork, 0);
|
|
860
|
+
rb_define_method(cBackend, "pending_count", LibevBackend_pending_count, 0);
|
|
862
861
|
|
|
863
|
-
rb_define_method(
|
|
864
|
-
rb_define_method(
|
|
862
|
+
rb_define_method(cBackend, "ref", LibevBackend_ref, 0);
|
|
863
|
+
rb_define_method(cBackend, "unref", LibevBackend_unref, 0);
|
|
865
864
|
|
|
866
|
-
rb_define_method(
|
|
867
|
-
rb_define_method(
|
|
865
|
+
rb_define_method(cBackend, "poll", LibevBackend_poll, 3);
|
|
866
|
+
rb_define_method(cBackend, "break", LibevBackend_wakeup, 0);
|
|
868
867
|
|
|
869
|
-
rb_define_method(
|
|
870
|
-
rb_define_method(
|
|
871
|
-
rb_define_method(
|
|
872
|
-
rb_define_method(
|
|
873
|
-
rb_define_method(
|
|
874
|
-
rb_define_method(
|
|
875
|
-
rb_define_method(
|
|
876
|
-
rb_define_method(
|
|
877
|
-
rb_define_method(
|
|
878
|
-
rb_define_method(
|
|
868
|
+
rb_define_method(cBackend, "read", LibevBackend_read, 4);
|
|
869
|
+
rb_define_method(cBackend, "read_loop", LibevBackend_read_loop, 1);
|
|
870
|
+
rb_define_method(cBackend, "write", LibevBackend_write_m, -1);
|
|
871
|
+
rb_define_method(cBackend, "accept", LibevBackend_accept, 1);
|
|
872
|
+
rb_define_method(cBackend, "accept_loop", LibevBackend_accept_loop, 1);
|
|
873
|
+
rb_define_method(cBackend, "connect", LibevBackend_connect, 3);
|
|
874
|
+
rb_define_method(cBackend, "wait_io", LibevBackend_wait_io, 2);
|
|
875
|
+
rb_define_method(cBackend, "sleep", LibevBackend_sleep, 1);
|
|
876
|
+
rb_define_method(cBackend, "waitpid", LibevBackend_waitpid, 1);
|
|
877
|
+
rb_define_method(cBackend, "wait_event", LibevBackend_wait_event, 1);
|
|
879
878
|
|
|
880
879
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
|
881
880
|
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
881
|
+
__BACKEND__.pending_count = LibevBackend_pending_count;
|
|
882
|
+
__BACKEND__.poll = LibevBackend_poll;
|
|
883
|
+
__BACKEND__.ref = LibevBackend_ref;
|
|
884
|
+
__BACKEND__.ref_count = LibevBackend_ref_count;
|
|
885
|
+
__BACKEND__.reset_ref_count = LibevBackend_reset_ref_count;
|
|
886
|
+
__BACKEND__.unref = LibevBackend_unref;
|
|
887
|
+
__BACKEND__.wait_event = LibevBackend_wait_event;
|
|
888
|
+
__BACKEND__.wakeup = LibevBackend_wakeup;
|
|
890
889
|
}
|