polyphony 0.44.0 → 0.45.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile.lock +14 -8
- data/Rakefile +1 -1
- data/TODO.md +12 -15
- 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 +1 -1
- 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/performance/multi_snooze.rb +0 -1
- 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 +90 -13
- data/ext/polyphony/{libev_agent.c → libev_backend.c} +226 -224
- data/ext/polyphony/polyphony.c +5 -7
- data/ext/polyphony/polyphony.h +18 -18
- data/ext/polyphony/polyphony_ext.c +5 -4
- data/ext/polyphony/queue.c +5 -6
- data/ext/polyphony/ring_buffer.c +0 -1
- data/ext/polyphony/runqueue.c +102 -0
- data/ext/polyphony/runqueue_ring_buffer.c +85 -0
- data/ext/polyphony/runqueue_ring_buffer.h +31 -0
- data/ext/polyphony/thread.c +53 -102
- data/lib/polyphony.rb +15 -14
- data/lib/polyphony/adapters/fs.rb +1 -1
- data/lib/polyphony/adapters/irb.rb +2 -17
- data/lib/polyphony/adapters/mysql2.rb +1 -1
- 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 +1 -1
- data/lib/polyphony/core/global_api.rb +19 -14
- data/lib/polyphony/core/resource_pool.rb +2 -2
- data/lib/polyphony/core/sync.rb +43 -3
- data/lib/polyphony/core/throttler.rb +1 -1
- data/lib/polyphony/extensions/core.rb +25 -32
- data/lib/polyphony/extensions/fiber.rb +22 -45
- 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 +5 -3
- data/test/helper.rb +1 -1
- data/test/{test_agent.rb → test_backend.rb} +22 -22
- data/test/test_fiber.rb +13 -12
- data/test/test_global_api.rb +29 -0
- data/test/test_io.rb +59 -1
- data/test/test_kernel.rb +5 -0
- data/test/test_signal.rb +14 -11
- data/test/test_socket.rb +17 -0
- data/test/test_sync.rb +73 -0
- metadata +99 -98
- 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 runqueue);
|
|
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,8 @@
|
|
|
2
2
|
|
|
3
3
|
ID ID_fiber_trace;
|
|
4
4
|
ID ID_ivar_auto_watcher;
|
|
5
|
-
ID
|
|
6
|
-
ID
|
|
7
|
-
ID ID_trace_run;
|
|
8
|
-
ID ID_trace_runnable;
|
|
9
|
-
ID ID_trace_terminate;
|
|
10
|
-
ID ID_trace_wait;
|
|
5
|
+
ID ID_ivar_mailbox;
|
|
6
|
+
ID ID_ivar_waiting_fibers;
|
|
11
7
|
|
|
12
8
|
VALUE SYM_dead;
|
|
13
9
|
VALUE SYM_running;
|
|
@@ -42,38 +38,117 @@ inline VALUE Fiber_auto_watcher(VALUE self) {
|
|
|
42
38
|
return watcher;
|
|
43
39
|
}
|
|
44
40
|
|
|
41
|
+
void Fiber_make_runnable(VALUE fiber, VALUE value) {
|
|
42
|
+
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
|
43
|
+
if (thread == Qnil) {
|
|
44
|
+
// rb_raise(rb_eRuntimeError, "No thread set for fiber");
|
|
45
|
+
rb_warn("No thread set for fiber");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
Thread_schedule_fiber(thread, fiber, value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void Fiber_make_runnable_with_priority(VALUE fiber, VALUE value) {
|
|
53
|
+
VALUE thread = rb_ivar_get(fiber, ID_ivar_thread);
|
|
54
|
+
if (thread == Qnil) {
|
|
55
|
+
// rb_raise(rb_eRuntimeError, "No thread set for fiber");
|
|
56
|
+
rb_warn("No thread set for fiber");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
Thread_schedule_fiber_with_priority(thread, fiber, value);
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
static VALUE Fiber_schedule(int argc, VALUE *argv, VALUE self) {
|
|
46
64
|
VALUE value = (argc == 0) ? Qnil : argv[0];
|
|
47
65
|
Fiber_make_runnable(self, value);
|
|
48
66
|
return self;
|
|
49
67
|
}
|
|
50
68
|
|
|
69
|
+
static VALUE Fiber_schedule_with_priority(int argc, VALUE *argv, VALUE self) {
|
|
70
|
+
VALUE value = (argc == 0) ? Qnil : argv[0];
|
|
71
|
+
Fiber_make_runnable_with_priority(self, value);
|
|
72
|
+
return self;
|
|
73
|
+
}
|
|
74
|
+
|
|
51
75
|
static VALUE Fiber_state(VALUE self) {
|
|
52
76
|
if (!rb_fiber_alive_p(self) || (rb_ivar_get(self, ID_ivar_running) == Qfalse))
|
|
53
77
|
return SYM_dead;
|
|
54
78
|
if (rb_fiber_current() == self) return SYM_running;
|
|
55
|
-
if (rb_ivar_get(self,
|
|
79
|
+
if (rb_ivar_get(self, ID_ivar_runnable) != Qnil) return SYM_runnable;
|
|
56
80
|
|
|
57
81
|
return SYM_waiting;
|
|
58
82
|
}
|
|
59
83
|
|
|
60
|
-
|
|
61
|
-
VALUE
|
|
62
|
-
|
|
63
|
-
|
|
84
|
+
VALUE Fiber_await(VALUE self) {
|
|
85
|
+
VALUE result;
|
|
86
|
+
|
|
87
|
+
// we compare with false, since a fiber that has not yet started will have
|
|
88
|
+
// @running set to nil
|
|
89
|
+
if (rb_ivar_get(self, ID_ivar_running) == Qfalse) {
|
|
90
|
+
result = rb_ivar_get(self, ID_ivar_result);
|
|
91
|
+
TEST_RESUME_EXCEPTION(result);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
VALUE fiber = rb_fiber_current();
|
|
96
|
+
VALUE waiting_fibers = rb_ivar_get(self, ID_ivar_waiting_fibers);
|
|
97
|
+
if (waiting_fibers == Qnil) {
|
|
98
|
+
waiting_fibers = rb_hash_new();
|
|
99
|
+
rb_ivar_set(self, ID_ivar_waiting_fibers, waiting_fibers);
|
|
100
|
+
}
|
|
101
|
+
rb_hash_aset(waiting_fibers, fiber, Qtrue);
|
|
102
|
+
|
|
103
|
+
result = Thread_switch_fiber(rb_thread_current());
|
|
104
|
+
|
|
105
|
+
rb_hash_delete(waiting_fibers, fiber);
|
|
106
|
+
TEST_RESUME_EXCEPTION(result);
|
|
107
|
+
RB_GC_GUARD(result);
|
|
108
|
+
return result;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
VALUE Fiber_send(VALUE self, VALUE value) {
|
|
112
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
113
|
+
if (mailbox == Qnil) {
|
|
114
|
+
mailbox = rb_funcall(cQueue, ID_new, 0);
|
|
115
|
+
rb_ivar_set(self, ID_ivar_mailbox, mailbox);
|
|
64
116
|
}
|
|
65
|
-
|
|
66
|
-
|
|
117
|
+
Queue_push(mailbox, value);
|
|
118
|
+
return self;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
VALUE Fiber_receive(VALUE self) {
|
|
122
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
123
|
+
if (mailbox == Qnil) {
|
|
124
|
+
mailbox = rb_funcall(cQueue, ID_new, 0);
|
|
125
|
+
rb_ivar_set(self, ID_ivar_mailbox, mailbox);
|
|
67
126
|
}
|
|
127
|
+
return Queue_shift(mailbox);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
VALUE Fiber_receive_all_pending(VALUE self) {
|
|
131
|
+
VALUE mailbox = rb_ivar_get(self, ID_ivar_mailbox);
|
|
132
|
+
return (mailbox == Qnil) ? rb_ary_new() : Queue_shift_all(mailbox);
|
|
68
133
|
}
|
|
69
134
|
|
|
70
135
|
void Init_Fiber() {
|
|
71
136
|
VALUE cFiber = rb_const_get(rb_cObject, rb_intern("Fiber"));
|
|
72
137
|
rb_define_method(cFiber, "safe_transfer", Fiber_safe_transfer, -1);
|
|
73
138
|
rb_define_method(cFiber, "schedule", Fiber_schedule, -1);
|
|
139
|
+
rb_define_method(cFiber, "schedule_with_priority", Fiber_schedule_with_priority, -1);
|
|
74
140
|
rb_define_method(cFiber, "state", Fiber_state, 0);
|
|
75
141
|
rb_define_method(cFiber, "auto_watcher", Fiber_auto_watcher, 0);
|
|
76
142
|
|
|
143
|
+
rb_define_method(cFiber, "await", Fiber_await, 0);
|
|
144
|
+
rb_define_method(cFiber, "join", Fiber_await, 0);
|
|
145
|
+
|
|
146
|
+
rb_define_method(cFiber, "<<", Fiber_send, 1);
|
|
147
|
+
rb_define_method(cFiber, "send", Fiber_send, 1);
|
|
148
|
+
|
|
149
|
+
rb_define_method(cFiber, "receive", Fiber_receive, 0);
|
|
150
|
+
rb_define_method(cFiber, "receive_all_pending", Fiber_receive_all_pending, 0);
|
|
151
|
+
|
|
77
152
|
SYM_dead = ID2SYM(rb_intern("dead"));
|
|
78
153
|
SYM_running = ID2SYM(rb_intern("running"));
|
|
79
154
|
SYM_runnable = ID2SYM(rb_intern("runnable"));
|
|
@@ -85,6 +160,8 @@ void Init_Fiber() {
|
|
|
85
160
|
|
|
86
161
|
ID_fiber_trace = rb_intern("__fiber_trace__");
|
|
87
162
|
ID_ivar_auto_watcher = rb_intern("@auto_watcher");
|
|
163
|
+
ID_ivar_mailbox = rb_intern("@mailbox");
|
|
164
|
+
ID_ivar_waiting_fibers = rb_intern("@waiting_fibers");
|
|
88
165
|
|
|
89
166
|
SYM_fiber_create = ID2SYM(rb_intern("fiber_create"));
|
|
90
167
|
SYM_fiber_ev_loop_enter = ID2SYM(rb_intern("fiber_ev_loop_enter"));
|
|
@@ -11,155 +11,156 @@
|
|
|
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
|
-
|
|
76
|
+
VALUE LibevBackend_post_fork(VALUE self) {
|
|
77
|
+
LibevBackend_t *backend;
|
|
78
|
+
GetLibevBackend(self, backend);
|
|
79
79
|
|
|
80
80
|
// After fork there may be some watchers still active left over from the
|
|
81
81
|
// parent, so we destroy the loop, even if it's the default one, then use the
|
|
82
82
|
// default one, as post_fork is called only from the main thread of the forked
|
|
83
83
|
// process. That way we don't need to call ev_loop_fork, since the loop is
|
|
84
84
|
// always a fresh one.
|
|
85
|
-
ev_loop_destroy(
|
|
86
|
-
|
|
85
|
+
ev_loop_destroy(backend->ev_loop);
|
|
86
|
+
backend->ev_loop = EV_DEFAULT;
|
|
87
87
|
|
|
88
88
|
return self;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
VALUE
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
VALUE LibevBackend_ref(VALUE self) {
|
|
92
|
+
LibevBackend_t *backend;
|
|
93
|
+
GetLibevBackend(self, backend);
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
return self;
|
|
95
|
+
backend->ref_count++;
|
|
96
|
+
return self;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
VALUE
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
VALUE LibevBackend_unref(VALUE self) {
|
|
100
|
+
LibevBackend_t *backend;
|
|
101
|
+
GetLibevBackend(self, backend);
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
return self;
|
|
103
|
+
backend->ref_count--;
|
|
104
|
+
return self;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
int
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
int LibevBackend_ref_count(VALUE self) {
|
|
108
|
+
LibevBackend_t *backend;
|
|
109
|
+
GetLibevBackend(self, backend);
|
|
110
110
|
|
|
111
|
-
return
|
|
111
|
+
return backend->ref_count;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
void
|
|
115
|
-
|
|
116
|
-
|
|
114
|
+
void LibevBackend_reset_ref_count(VALUE self) {
|
|
115
|
+
LibevBackend_t *backend;
|
|
116
|
+
GetLibevBackend(self, backend);
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
backend->ref_count = 0;
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
-
VALUE
|
|
121
|
+
VALUE LibevBackend_pending_count(VALUE self) {
|
|
122
122
|
int count;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
count = ev_pending_count(
|
|
123
|
+
LibevBackend_t *backend;
|
|
124
|
+
GetLibevBackend(self, backend);
|
|
125
|
+
count = ev_pending_count(backend->ev_loop);
|
|
126
126
|
return INT2NUM(count);
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
VALUE
|
|
129
|
+
VALUE LibevBackend_poll(VALUE self, VALUE nowait, VALUE current_fiber, VALUE runqueue) {
|
|
130
130
|
int is_nowait = nowait == Qtrue;
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
LibevBackend_t *backend;
|
|
132
|
+
GetLibevBackend(self, backend);
|
|
133
133
|
|
|
134
134
|
if (is_nowait) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
135
|
+
backend->run_no_wait_count++;
|
|
136
|
+
if (backend->run_no_wait_count < 10) return self;
|
|
137
|
+
|
|
138
|
+
long runnable_count = Runqueue_len(runqueue);
|
|
139
|
+
if (backend->run_no_wait_count < runnable_count) return self;
|
|
139
140
|
}
|
|
140
141
|
|
|
141
|
-
|
|
142
|
-
|
|
142
|
+
backend->run_no_wait_count = 0;
|
|
143
|
+
|
|
143
144
|
COND_TRACE(2, SYM_fiber_ev_loop_enter, current_fiber);
|
|
144
|
-
|
|
145
|
-
ev_run(
|
|
146
|
-
|
|
145
|
+
backend->running = 1;
|
|
146
|
+
ev_run(backend->ev_loop, is_nowait ? EVRUN_NOWAIT : EVRUN_ONCE);
|
|
147
|
+
backend->running = 0;
|
|
147
148
|
COND_TRACE(2, SYM_fiber_ev_loop_leave, current_fiber);
|
|
148
149
|
|
|
149
150
|
return self;
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
VALUE
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
VALUE LibevBackend_wakeup(VALUE self) {
|
|
154
|
+
LibevBackend_t *backend;
|
|
155
|
+
GetLibevBackend(self, backend);
|
|
155
156
|
|
|
156
|
-
if (
|
|
157
|
+
if (backend->running) {
|
|
157
158
|
// Since the loop will run until at least one event has occurred, we signal
|
|
158
159
|
// the selector's associated async watcher, which will cause the ev loop to
|
|
159
160
|
// return. In contrast to using `ev_break` to break out of the loop, which
|
|
160
161
|
// should be called from the same thread (from within the ev_loop), using an
|
|
161
162
|
// `ev_async` allows us to interrupt the event loop across threads.
|
|
162
|
-
ev_async_send(
|
|
163
|
+
ev_async_send(backend->ev_loop, &backend->break_async);
|
|
163
164
|
return Qtrue;
|
|
164
165
|
}
|
|
165
166
|
|
|
@@ -238,40 +239,47 @@ struct libev_io {
|
|
|
238
239
|
VALUE fiber;
|
|
239
240
|
};
|
|
240
241
|
|
|
241
|
-
void
|
|
242
|
+
void LibevBackend_io_callback(EV_P_ ev_io *w, int revents)
|
|
242
243
|
{
|
|
243
244
|
struct libev_io *watcher = (struct libev_io *)w;
|
|
244
245
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
|
245
246
|
}
|
|
246
247
|
|
|
247
|
-
inline VALUE libev_await(
|
|
248
|
+
inline VALUE libev_await(LibevBackend_t *backend) {
|
|
248
249
|
VALUE ret;
|
|
249
|
-
|
|
250
|
+
backend->ref_count++;
|
|
250
251
|
ret = Thread_switch_fiber(rb_thread_current());
|
|
251
|
-
|
|
252
|
+
backend->ref_count--;
|
|
252
253
|
RB_GC_GUARD(ret);
|
|
253
254
|
return ret;
|
|
254
255
|
}
|
|
255
256
|
|
|
256
|
-
VALUE
|
|
257
|
-
LibevAgent_t *agent;
|
|
258
|
-
GetLibevAgent(self, agent);
|
|
259
|
-
return libev_await(agent);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
VALUE libev_io_wait(LibevAgent_t *agent, struct libev_io *watcher, rb_io_t *fptr, int flags) {
|
|
257
|
+
VALUE libev_wait_fd_with_watcher(LibevBackend_t *backend, int fd, struct libev_io *watcher, int events) {
|
|
263
258
|
VALUE switchpoint_result;
|
|
264
259
|
|
|
265
260
|
if (watcher->fiber == Qnil) {
|
|
266
261
|
watcher->fiber = rb_fiber_current();
|
|
267
|
-
ev_io_init(&watcher->io,
|
|
262
|
+
ev_io_init(&watcher->io, LibevBackend_io_callback, fd, events);
|
|
268
263
|
}
|
|
269
|
-
ev_io_start(
|
|
270
|
-
switchpoint_result = libev_await(agent);
|
|
271
|
-
ev_io_stop(agent->ev_loop, &watcher->io);
|
|
264
|
+
ev_io_start(backend->ev_loop, &watcher->io);
|
|
272
265
|
|
|
266
|
+
switchpoint_result = libev_await(backend);
|
|
267
|
+
|
|
268
|
+
ev_io_stop(backend->ev_loop, &watcher->io);
|
|
273
269
|
RB_GC_GUARD(switchpoint_result);
|
|
274
|
-
return switchpoint_result;
|
|
270
|
+
return switchpoint_result;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
VALUE libev_wait_fd(LibevBackend_t *backend, int fd, int events, int raise_exception) {
|
|
274
|
+
struct libev_io watcher;
|
|
275
|
+
VALUE switchpoint_result = Qnil;
|
|
276
|
+
watcher.fiber = Qnil;
|
|
277
|
+
|
|
278
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fd, &watcher, events);
|
|
279
|
+
|
|
280
|
+
if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
281
|
+
RB_GC_GUARD(switchpoint_result);
|
|
282
|
+
return switchpoint_result;
|
|
275
283
|
}
|
|
276
284
|
|
|
277
285
|
VALUE libev_snooze() {
|
|
@@ -288,24 +296,23 @@ ID ID_ivar_is_nonblocking;
|
|
|
288
296
|
// benchmarks (with a "hello world" HTTP server) show throughput is improved
|
|
289
297
|
// by 10-13%.
|
|
290
298
|
inline void io_set_nonblock(rb_io_t *fptr, VALUE io) {
|
|
299
|
+
VALUE is_nonblocking = rb_ivar_get(io, ID_ivar_is_nonblocking);
|
|
300
|
+
if (is_nonblocking == Qtrue) return;
|
|
301
|
+
|
|
302
|
+
rb_ivar_set(io, ID_ivar_is_nonblocking, Qtrue);
|
|
303
|
+
|
|
291
304
|
#ifdef _WIN32
|
|
292
|
-
|
|
305
|
+
rb_w32_set_nonblock(fptr->fd);
|
|
293
306
|
#elif defined(F_GETFL)
|
|
294
|
-
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (oflags == -1) return;
|
|
299
|
-
if (oflags & O_NONBLOCK) return;
|
|
300
|
-
oflags |= O_NONBLOCK;
|
|
301
|
-
fcntl(fptr->fd, F_SETFL, oflags);
|
|
302
|
-
}
|
|
307
|
+
int oflags = fcntl(fptr->fd, F_GETFL);
|
|
308
|
+
if ((oflags == -1) && (oflags & O_NONBLOCK)) return;
|
|
309
|
+
oflags |= O_NONBLOCK;
|
|
310
|
+
fcntl(fptr->fd, F_SETFL, oflags);
|
|
303
311
|
#endif
|
|
304
|
-
return;
|
|
305
312
|
}
|
|
306
313
|
|
|
307
|
-
VALUE
|
|
308
|
-
|
|
314
|
+
VALUE LibevBackend_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eof) {
|
|
315
|
+
LibevBackend_t *backend;
|
|
309
316
|
struct libev_io watcher;
|
|
310
317
|
rb_io_t *fptr;
|
|
311
318
|
long dynamic_len = length == Qnil;
|
|
@@ -317,13 +324,13 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
317
324
|
int read_to_eof = RTEST(to_eof);
|
|
318
325
|
VALUE underlying_io = rb_iv_get(io, "@io");
|
|
319
326
|
|
|
320
|
-
|
|
327
|
+
GetLibevBackend(self, backend);
|
|
321
328
|
if (underlying_io != Qnil) io = underlying_io;
|
|
322
329
|
GetOpenFile(io, fptr);
|
|
323
330
|
rb_io_check_byte_readable(fptr);
|
|
324
331
|
io_set_nonblock(fptr, io);
|
|
325
332
|
watcher.fiber = Qnil;
|
|
326
|
-
|
|
333
|
+
|
|
327
334
|
OBJ_TAINT(str);
|
|
328
335
|
|
|
329
336
|
// Apparently after reopening a closed file, the file position is not reset,
|
|
@@ -340,12 +347,14 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
340
347
|
if (n < 0) {
|
|
341
348
|
int e = errno;
|
|
342
349
|
if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
|
|
343
|
-
|
|
344
|
-
switchpoint_result =
|
|
350
|
+
|
|
351
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
352
|
+
|
|
345
353
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
346
354
|
}
|
|
347
355
|
else {
|
|
348
356
|
switchpoint_result = libev_snooze();
|
|
357
|
+
|
|
349
358
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
350
359
|
|
|
351
360
|
if (n == 0) break; // EOF
|
|
@@ -354,7 +363,7 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
354
363
|
|
|
355
364
|
if (total == len) {
|
|
356
365
|
if (!dynamic_len) break;
|
|
357
|
-
|
|
366
|
+
|
|
358
367
|
rb_str_resize(str, total);
|
|
359
368
|
rb_str_modify_expand(str, len);
|
|
360
369
|
buf = RSTRING_PTR(str) + total;
|
|
@@ -364,11 +373,12 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
|
|
|
364
373
|
else buf += n;
|
|
365
374
|
}
|
|
366
375
|
}
|
|
367
|
-
if (total == 0) return Qnil;
|
|
368
376
|
|
|
369
377
|
io_set_read_length(str, total, shrinkable);
|
|
370
378
|
io_enc_str(str, fptr);
|
|
371
|
-
|
|
379
|
+
|
|
380
|
+
if (total == 0) return Qnil;
|
|
381
|
+
|
|
372
382
|
RB_GC_GUARD(watcher.fiber);
|
|
373
383
|
RB_GC_GUARD(switchpoint_result);
|
|
374
384
|
|
|
@@ -377,7 +387,7 @@ error:
|
|
|
377
387
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
378
388
|
}
|
|
379
389
|
|
|
380
|
-
VALUE
|
|
390
|
+
VALUE LibevBackend_read_loop(VALUE self, VALUE io) {
|
|
381
391
|
|
|
382
392
|
#define PREPARE_STR() { \
|
|
383
393
|
str = Qnil; \
|
|
@@ -394,7 +404,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
394
404
|
PREPARE_STR(); \
|
|
395
405
|
}
|
|
396
406
|
|
|
397
|
-
|
|
407
|
+
LibevBackend_t *backend;
|
|
398
408
|
struct libev_io watcher;
|
|
399
409
|
rb_io_t *fptr;
|
|
400
410
|
VALUE str;
|
|
@@ -407,7 +417,7 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
407
417
|
|
|
408
418
|
PREPARE_STR();
|
|
409
419
|
|
|
410
|
-
|
|
420
|
+
GetLibevBackend(self, backend);
|
|
411
421
|
if (underlying_io != Qnil) io = underlying_io;
|
|
412
422
|
GetOpenFile(io, fptr);
|
|
413
423
|
rb_io_check_byte_readable(fptr);
|
|
@@ -429,22 +439,17 @@ VALUE LibevAgent_read_loop(VALUE self, VALUE io) {
|
|
|
429
439
|
int e = errno;
|
|
430
440
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
431
441
|
|
|
432
|
-
switchpoint_result =
|
|
442
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
433
443
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
434
444
|
}
|
|
435
445
|
else {
|
|
436
446
|
switchpoint_result = libev_snooze();
|
|
437
|
-
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
438
447
|
|
|
439
|
-
if (
|
|
448
|
+
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
440
449
|
|
|
450
|
+
if (n == 0) break; // EOF
|
|
441
451
|
total = n;
|
|
442
452
|
YIELD_STR();
|
|
443
|
-
Fiber_make_runnable(rb_fiber_current(), Qnil);
|
|
444
|
-
switchpoint_result = Thread_switch_fiber(rb_thread_current());
|
|
445
|
-
if (TEST_EXCEPTION(switchpoint_result)) {
|
|
446
|
-
goto error;
|
|
447
|
-
}
|
|
448
453
|
}
|
|
449
454
|
}
|
|
450
455
|
|
|
@@ -457,8 +462,8 @@ error:
|
|
|
457
462
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
458
463
|
}
|
|
459
464
|
|
|
460
|
-
VALUE
|
|
461
|
-
|
|
465
|
+
VALUE LibevBackend_write(VALUE self, VALUE io, VALUE str) {
|
|
466
|
+
LibevBackend_t *backend;
|
|
462
467
|
struct libev_io watcher;
|
|
463
468
|
rb_io_t *fptr;
|
|
464
469
|
VALUE switchpoint_result = Qnil;
|
|
@@ -469,7 +474,7 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
469
474
|
|
|
470
475
|
underlying_io = rb_iv_get(io, "@io");
|
|
471
476
|
if (underlying_io != Qnil) io = underlying_io;
|
|
472
|
-
|
|
477
|
+
GetLibevBackend(self, backend);
|
|
473
478
|
io = rb_io_get_write_io(io);
|
|
474
479
|
GetOpenFile(io, fptr);
|
|
475
480
|
watcher.fiber = Qnil;
|
|
@@ -479,7 +484,9 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
479
484
|
if (n < 0) {
|
|
480
485
|
int e = errno;
|
|
481
486
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
482
|
-
|
|
487
|
+
|
|
488
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
|
489
|
+
|
|
483
490
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
484
491
|
}
|
|
485
492
|
else {
|
|
@@ -490,6 +497,7 @@ VALUE LibevAgent_write(VALUE self, VALUE io, VALUE str) {
|
|
|
490
497
|
|
|
491
498
|
if (watcher.fiber == Qnil) {
|
|
492
499
|
switchpoint_result = libev_snooze();
|
|
500
|
+
|
|
493
501
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
494
502
|
}
|
|
495
503
|
|
|
@@ -501,8 +509,8 @@ error:
|
|
|
501
509
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
502
510
|
}
|
|
503
511
|
|
|
504
|
-
VALUE
|
|
505
|
-
|
|
512
|
+
VALUE LibevBackend_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
513
|
+
LibevBackend_t *backend;
|
|
506
514
|
struct libev_io watcher;
|
|
507
515
|
rb_io_t *fptr;
|
|
508
516
|
VALUE switchpoint_result = Qnil;
|
|
@@ -515,7 +523,7 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
515
523
|
|
|
516
524
|
underlying_io = rb_iv_get(io, "@io");
|
|
517
525
|
if (underlying_io != Qnil) io = underlying_io;
|
|
518
|
-
|
|
526
|
+
GetLibevBackend(self, backend);
|
|
519
527
|
io = rb_io_get_write_io(io);
|
|
520
528
|
GetOpenFile(io, fptr);
|
|
521
529
|
watcher.fiber = Qnil;
|
|
@@ -535,7 +543,8 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
535
543
|
int e = errno;
|
|
536
544
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
537
545
|
|
|
538
|
-
switchpoint_result =
|
|
546
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
|
547
|
+
|
|
539
548
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
540
549
|
}
|
|
541
550
|
else {
|
|
@@ -558,6 +567,7 @@ VALUE LibevAgent_writev(VALUE self, VALUE io, int argc, VALUE *argv) {
|
|
|
558
567
|
}
|
|
559
568
|
if (watcher.fiber == Qnil) {
|
|
560
569
|
switchpoint_result = libev_snooze();
|
|
570
|
+
|
|
561
571
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
562
572
|
}
|
|
563
573
|
|
|
@@ -571,20 +581,20 @@ error:
|
|
|
571
581
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
572
582
|
}
|
|
573
583
|
|
|
574
|
-
VALUE
|
|
584
|
+
VALUE LibevBackend_write_m(int argc, VALUE *argv, VALUE self) {
|
|
575
585
|
if (argc < 2)
|
|
576
586
|
// TODO: raise ArgumentError
|
|
577
587
|
rb_raise(rb_eRuntimeError, "(wrong number of arguments (expected 2 or more))");
|
|
578
|
-
|
|
588
|
+
|
|
579
589
|
return (argc == 2) ?
|
|
580
|
-
|
|
581
|
-
|
|
590
|
+
LibevBackend_write(self, argv[0], argv[1]) :
|
|
591
|
+
LibevBackend_writev(self, argv[0], argc - 1, argv + 1);
|
|
582
592
|
}
|
|
583
593
|
|
|
584
594
|
///////////////////////////////////////////////////////////////////////////
|
|
585
595
|
|
|
586
|
-
VALUE
|
|
587
|
-
|
|
596
|
+
VALUE LibevBackend_accept(VALUE self, VALUE sock) {
|
|
597
|
+
LibevBackend_t *backend;
|
|
588
598
|
struct libev_io watcher;
|
|
589
599
|
rb_io_t *fptr;
|
|
590
600
|
int fd;
|
|
@@ -594,7 +604,7 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
594
604
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
|
595
605
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
|
596
606
|
|
|
597
|
-
|
|
607
|
+
GetLibevBackend(self, backend);
|
|
598
608
|
GetOpenFile(sock, fptr);
|
|
599
609
|
io_set_nonblock(fptr, sock);
|
|
600
610
|
watcher.fiber = Qnil;
|
|
@@ -604,13 +614,15 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
604
614
|
int e = errno;
|
|
605
615
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
606
616
|
|
|
607
|
-
switchpoint_result =
|
|
617
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
618
|
+
|
|
608
619
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
609
620
|
}
|
|
610
621
|
else {
|
|
611
622
|
VALUE socket;
|
|
612
623
|
rb_io_t *fp;
|
|
613
624
|
switchpoint_result = libev_snooze();
|
|
625
|
+
|
|
614
626
|
if (TEST_EXCEPTION(switchpoint_result)) {
|
|
615
627
|
close(fd); // close fd since we're raising an exception
|
|
616
628
|
goto error;
|
|
@@ -624,7 +636,7 @@ VALUE LibevAgent_accept(VALUE self, VALUE sock) {
|
|
|
624
636
|
rb_io_ascii8bit_binmode(socket);
|
|
625
637
|
io_set_nonblock(fp, socket);
|
|
626
638
|
rb_io_synchronized(fp);
|
|
627
|
-
|
|
639
|
+
|
|
628
640
|
// if (rsock_do_not_reverse_lookup) {
|
|
629
641
|
// fp->mode |= FMODE_NOREVLOOKUP;
|
|
630
642
|
// }
|
|
@@ -637,8 +649,8 @@ error:
|
|
|
637
649
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
638
650
|
}
|
|
639
651
|
|
|
640
|
-
VALUE
|
|
641
|
-
|
|
652
|
+
VALUE LibevBackend_accept_loop(VALUE self, VALUE sock) {
|
|
653
|
+
LibevBackend_t *backend;
|
|
642
654
|
struct libev_io watcher;
|
|
643
655
|
rb_io_t *fptr;
|
|
644
656
|
int fd;
|
|
@@ -649,7 +661,7 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
|
649
661
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
|
650
662
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
|
651
663
|
|
|
652
|
-
|
|
664
|
+
GetLibevBackend(self, backend);
|
|
653
665
|
GetOpenFile(sock, fptr);
|
|
654
666
|
io_set_nonblock(fptr, sock);
|
|
655
667
|
watcher.fiber = Qnil;
|
|
@@ -660,17 +672,19 @@ VALUE LibevAgent_accept_loop(VALUE self, VALUE sock) {
|
|
|
660
672
|
int e = errno;
|
|
661
673
|
if ((e != EWOULDBLOCK && e != EAGAIN)) rb_syserr_fail(e, strerror(e));
|
|
662
674
|
|
|
663
|
-
switchpoint_result =
|
|
675
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_READ);
|
|
676
|
+
|
|
664
677
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
665
678
|
}
|
|
666
679
|
else {
|
|
667
680
|
rb_io_t *fp;
|
|
668
681
|
switchpoint_result = libev_snooze();
|
|
682
|
+
|
|
669
683
|
if (TEST_EXCEPTION(switchpoint_result)) {
|
|
670
684
|
close(fd); // close fd since we're raising an exception
|
|
671
685
|
goto error;
|
|
672
686
|
}
|
|
673
|
-
|
|
687
|
+
|
|
674
688
|
socket = rb_obj_alloc(cTCPSocket);
|
|
675
689
|
MakeOpenFile(socket, fp);
|
|
676
690
|
rb_update_max_fd(fd);
|
|
@@ -693,8 +707,8 @@ error:
|
|
|
693
707
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
694
708
|
}
|
|
695
709
|
|
|
696
|
-
VALUE
|
|
697
|
-
|
|
710
|
+
VALUE LibevBackend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
711
|
+
LibevBackend_t *backend;
|
|
698
712
|
struct libev_io watcher;
|
|
699
713
|
rb_io_t *fptr;
|
|
700
714
|
struct sockaddr_in addr;
|
|
@@ -703,12 +717,12 @@ VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
|
703
717
|
VALUE underlying_sock = rb_iv_get(sock, "@io");
|
|
704
718
|
if (underlying_sock != Qnil) sock = underlying_sock;
|
|
705
719
|
|
|
706
|
-
|
|
720
|
+
GetLibevBackend(self, backend);
|
|
707
721
|
GetOpenFile(sock, fptr);
|
|
708
722
|
io_set_nonblock(fptr, sock);
|
|
709
723
|
watcher.fiber = Qnil;
|
|
710
724
|
|
|
711
|
-
addr.sin_family = AF_INET;
|
|
725
|
+
addr.sin_family = AF_INET;
|
|
712
726
|
addr.sin_addr.s_addr = inet_addr(host_buf);
|
|
713
727
|
addr.sin_port = htons(NUM2INT(port));
|
|
714
728
|
|
|
@@ -716,11 +730,14 @@ VALUE LibevAgent_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
|
|
|
716
730
|
if (result < 0) {
|
|
717
731
|
int e = errno;
|
|
718
732
|
if (e != EINPROGRESS) rb_syserr_fail(e, strerror(e));
|
|
719
|
-
|
|
733
|
+
|
|
734
|
+
switchpoint_result = libev_wait_fd_with_watcher(backend, fptr->fd, &watcher, EV_WRITE);
|
|
735
|
+
|
|
720
736
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
721
737
|
}
|
|
722
738
|
else {
|
|
723
739
|
switchpoint_result = libev_snooze();
|
|
740
|
+
|
|
724
741
|
if (TEST_EXCEPTION(switchpoint_result)) goto error;
|
|
725
742
|
}
|
|
726
743
|
RB_GC_GUARD(switchpoint_result);
|
|
@@ -729,31 +746,16 @@ error:
|
|
|
729
746
|
return RAISE_EXCEPTION(switchpoint_result);
|
|
730
747
|
}
|
|
731
748
|
|
|
732
|
-
VALUE
|
|
733
|
-
|
|
734
|
-
VALUE switchpoint_result = Qnil;
|
|
735
|
-
|
|
736
|
-
watcher.fiber = rb_fiber_current();
|
|
737
|
-
ev_io_init(&watcher.io, LibevAgent_io_callback, fd, events);
|
|
738
|
-
ev_io_start(agent->ev_loop, &watcher.io);
|
|
739
|
-
switchpoint_result = libev_await(agent);
|
|
740
|
-
ev_io_stop(agent->ev_loop, &watcher.io);
|
|
741
|
-
|
|
742
|
-
if (raise_exception) TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
743
|
-
RB_GC_GUARD(switchpoint_result);
|
|
744
|
-
return switchpoint_result;
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
VALUE LibevAgent_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
748
|
-
LibevAgent_t *agent;
|
|
749
|
+
VALUE LibevBackend_wait_io(VALUE self, VALUE io, VALUE write) {
|
|
750
|
+
LibevBackend_t *backend;
|
|
749
751
|
rb_io_t *fptr;
|
|
750
752
|
int events = RTEST(write) ? EV_WRITE : EV_READ;
|
|
751
753
|
VALUE underlying_io = rb_iv_get(io, "@io");
|
|
752
754
|
if (underlying_io != Qnil) io = underlying_io;
|
|
753
|
-
|
|
755
|
+
GetLibevBackend(self, backend);
|
|
754
756
|
GetOpenFile(io, fptr);
|
|
755
|
-
|
|
756
|
-
return libev_wait_fd(
|
|
757
|
+
|
|
758
|
+
return libev_wait_fd(backend, fptr->fd, events, 1);
|
|
757
759
|
}
|
|
758
760
|
|
|
759
761
|
struct libev_timer {
|
|
@@ -761,26 +763,25 @@ struct libev_timer {
|
|
|
761
763
|
VALUE fiber;
|
|
762
764
|
};
|
|
763
765
|
|
|
764
|
-
void
|
|
766
|
+
void LibevBackend_timer_callback(EV_P_ ev_timer *w, int revents)
|
|
765
767
|
{
|
|
766
768
|
struct libev_timer *watcher = (struct libev_timer *)w;
|
|
767
769
|
Fiber_make_runnable(watcher->fiber, Qnil);
|
|
768
770
|
}
|
|
769
771
|
|
|
770
|
-
VALUE
|
|
771
|
-
|
|
772
|
+
VALUE LibevBackend_sleep(VALUE self, VALUE duration) {
|
|
773
|
+
LibevBackend_t *backend;
|
|
772
774
|
struct libev_timer watcher;
|
|
773
775
|
VALUE switchpoint_result = Qnil;
|
|
774
776
|
|
|
775
|
-
|
|
777
|
+
GetLibevBackend(self, backend);
|
|
776
778
|
watcher.fiber = rb_fiber_current();
|
|
777
|
-
ev_timer_init(&watcher.timer,
|
|
778
|
-
ev_timer_start(
|
|
779
|
-
|
|
780
|
-
switchpoint_result = libev_await(agent);
|
|
779
|
+
ev_timer_init(&watcher.timer, LibevBackend_timer_callback, NUM2DBL(duration), 0.);
|
|
780
|
+
ev_timer_start(backend->ev_loop, &watcher.timer);
|
|
781
781
|
|
|
782
|
-
|
|
782
|
+
switchpoint_result = libev_await(backend);
|
|
783
783
|
|
|
784
|
+
ev_timer_stop(backend->ev_loop, &watcher.timer);
|
|
784
785
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
785
786
|
RB_GC_GUARD(watcher.fiber);
|
|
786
787
|
RB_GC_GUARD(switchpoint_result);
|
|
@@ -792,7 +793,7 @@ struct libev_child {
|
|
|
792
793
|
VALUE fiber;
|
|
793
794
|
};
|
|
794
795
|
|
|
795
|
-
void
|
|
796
|
+
void LibevBackend_child_callback(EV_P_ ev_child *w, int revents)
|
|
796
797
|
{
|
|
797
798
|
struct libev_child *watcher = (struct libev_child *)w;
|
|
798
799
|
int exit_status = w->rstatus >> 8; // weird, why should we do this?
|
|
@@ -802,87 +803,88 @@ void LibevAgent_child_callback(EV_P_ ev_child *w, int revents)
|
|
|
802
803
|
Fiber_make_runnable(watcher->fiber, status);
|
|
803
804
|
}
|
|
804
805
|
|
|
805
|
-
VALUE
|
|
806
|
-
|
|
806
|
+
VALUE LibevBackend_waitpid(VALUE self, VALUE pid) {
|
|
807
|
+
LibevBackend_t *backend;
|
|
807
808
|
struct libev_child watcher;
|
|
808
809
|
VALUE switchpoint_result = Qnil;
|
|
809
|
-
|
|
810
|
+
GetLibevBackend(self, backend);
|
|
810
811
|
|
|
811
812
|
watcher.fiber = rb_fiber_current();
|
|
812
|
-
ev_child_init(&watcher.child,
|
|
813
|
-
ev_child_start(
|
|
814
|
-
|
|
815
|
-
switchpoint_result = libev_await(agent);
|
|
816
|
-
ev_child_stop(agent->ev_loop, &watcher.child);
|
|
813
|
+
ev_child_init(&watcher.child, LibevBackend_child_callback, NUM2INT(pid), 0);
|
|
814
|
+
ev_child_start(backend->ev_loop, &watcher.child);
|
|
817
815
|
|
|
816
|
+
switchpoint_result = libev_await(backend);
|
|
817
|
+
|
|
818
|
+
ev_child_stop(backend->ev_loop, &watcher.child);
|
|
818
819
|
TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
819
820
|
RB_GC_GUARD(watcher.fiber);
|
|
820
821
|
RB_GC_GUARD(switchpoint_result);
|
|
821
822
|
return switchpoint_result;
|
|
822
823
|
}
|
|
823
824
|
|
|
824
|
-
struct ev_loop *
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
return
|
|
825
|
+
struct ev_loop *LibevBackend_ev_loop(VALUE self) {
|
|
826
|
+
LibevBackend_t *backend;
|
|
827
|
+
GetLibevBackend(self, backend);
|
|
828
|
+
return backend->ev_loop;
|
|
828
829
|
}
|
|
829
830
|
|
|
830
|
-
void
|
|
831
|
+
void LibevBackend_async_callback(EV_P_ ev_async *w, int revents) { }
|
|
831
832
|
|
|
832
|
-
VALUE
|
|
833
|
-
|
|
833
|
+
VALUE LibevBackend_wait_event(VALUE self, VALUE raise) {
|
|
834
|
+
LibevBackend_t *backend;
|
|
834
835
|
VALUE switchpoint_result = Qnil;
|
|
835
|
-
|
|
836
|
+
GetLibevBackend(self, backend);
|
|
836
837
|
|
|
837
838
|
struct ev_async async;
|
|
838
839
|
|
|
839
|
-
ev_async_init(&async,
|
|
840
|
-
ev_async_start(
|
|
841
|
-
|
|
842
|
-
|
|
840
|
+
ev_async_init(&async, LibevBackend_async_callback);
|
|
841
|
+
ev_async_start(backend->ev_loop, &async);
|
|
842
|
+
|
|
843
|
+
switchpoint_result = libev_await(backend);
|
|
843
844
|
|
|
845
|
+
ev_async_stop(backend->ev_loop, &async);
|
|
844
846
|
if (RTEST(raise)) TEST_RESUME_EXCEPTION(switchpoint_result);
|
|
845
847
|
RB_GC_GUARD(switchpoint_result);
|
|
846
848
|
return switchpoint_result;
|
|
847
849
|
}
|
|
848
850
|
|
|
849
|
-
void
|
|
851
|
+
void Init_LibevBackend() {
|
|
850
852
|
rb_require("socket");
|
|
851
853
|
cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
|
|
852
854
|
|
|
853
|
-
VALUE
|
|
854
|
-
rb_define_alloc_func(
|
|
855
|
+
VALUE cBackend = rb_define_class_under(mPolyphony, "Backend", rb_cData);
|
|
856
|
+
rb_define_alloc_func(cBackend, LibevBackend_allocate);
|
|
855
857
|
|
|
856
|
-
rb_define_method(
|
|
857
|
-
rb_define_method(
|
|
858
|
-
rb_define_method(
|
|
859
|
-
rb_define_method(
|
|
858
|
+
rb_define_method(cBackend, "initialize", LibevBackend_initialize, 0);
|
|
859
|
+
rb_define_method(cBackend, "finalize", LibevBackend_finalize, 0);
|
|
860
|
+
rb_define_method(cBackend, "post_fork", LibevBackend_post_fork, 0);
|
|
861
|
+
rb_define_method(cBackend, "pending_count", LibevBackend_pending_count, 0);
|
|
860
862
|
|
|
861
|
-
rb_define_method(
|
|
862
|
-
rb_define_method(
|
|
863
|
+
rb_define_method(cBackend, "ref", LibevBackend_ref, 0);
|
|
864
|
+
rb_define_method(cBackend, "unref", LibevBackend_unref, 0);
|
|
863
865
|
|
|
864
|
-
rb_define_method(
|
|
865
|
-
rb_define_method(
|
|
866
|
+
rb_define_method(cBackend, "poll", LibevBackend_poll, 3);
|
|
867
|
+
rb_define_method(cBackend, "break", LibevBackend_wakeup, 0);
|
|
866
868
|
|
|
867
|
-
rb_define_method(
|
|
868
|
-
rb_define_method(
|
|
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(
|
|
869
|
+
rb_define_method(cBackend, "read", LibevBackend_read, 4);
|
|
870
|
+
rb_define_method(cBackend, "read_loop", LibevBackend_read_loop, 1);
|
|
871
|
+
rb_define_method(cBackend, "write", LibevBackend_write_m, -1);
|
|
872
|
+
rb_define_method(cBackend, "accept", LibevBackend_accept, 1);
|
|
873
|
+
rb_define_method(cBackend, "accept_loop", LibevBackend_accept_loop, 1);
|
|
874
|
+
rb_define_method(cBackend, "connect", LibevBackend_connect, 3);
|
|
875
|
+
rb_define_method(cBackend, "wait_io", LibevBackend_wait_io, 2);
|
|
876
|
+
rb_define_method(cBackend, "sleep", LibevBackend_sleep, 1);
|
|
877
|
+
rb_define_method(cBackend, "waitpid", LibevBackend_waitpid, 1);
|
|
878
|
+
rb_define_method(cBackend, "wait_event", LibevBackend_wait_event, 1);
|
|
877
879
|
|
|
878
880
|
ID_ivar_is_nonblocking = rb_intern("@is_nonblocking");
|
|
879
881
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
882
|
+
__BACKEND__.pending_count = LibevBackend_pending_count;
|
|
883
|
+
__BACKEND__.poll = LibevBackend_poll;
|
|
884
|
+
__BACKEND__.ref = LibevBackend_ref;
|
|
885
|
+
__BACKEND__.ref_count = LibevBackend_ref_count;
|
|
886
|
+
__BACKEND__.reset_ref_count = LibevBackend_reset_ref_count;
|
|
887
|
+
__BACKEND__.unref = LibevBackend_unref;
|
|
888
|
+
__BACKEND__.wait_event = LibevBackend_wait_event;
|
|
889
|
+
__BACKEND__.wakeup = LibevBackend_wakeup;
|
|
888
890
|
}
|