rbuv 0.0.2 → 0.0.3
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/.gitignore +2 -0
- data/ext/rbuv/extconf.rb +3 -0
- data/ext/rbuv/rbuv.c +3 -0
- data/ext/rbuv/rbuv.h +19 -6
- data/ext/rbuv/{debug.h → rbuv_debug.h} +1 -1
- data/ext/rbuv/{error.c → rbuv_error.c} +2 -2
- data/ext/rbuv/{error.h → rbuv_error.h} +1 -1
- data/ext/rbuv/rbuv_handle.c +124 -0
- data/ext/rbuv/rbuv_handle.h +16 -0
- data/ext/rbuv/{loop.c → rbuv_loop.c} +18 -2
- data/ext/rbuv/{loop.h → rbuv_loop.h} +1 -2
- data/ext/rbuv/rbuv_signal.c +119 -0
- data/ext/rbuv/rbuv_signal.h +12 -0
- data/ext/rbuv/rbuv_stream.c +253 -0
- data/ext/rbuv/rbuv_stream.h +12 -0
- data/ext/rbuv/rbuv_tcp.c +102 -0
- data/ext/rbuv/rbuv_tcp.h +12 -0
- data/ext/rbuv/{timer.c → rbuv_timer.c} +31 -10
- data/ext/rbuv/{timer.h → rbuv_timer.h} +1 -2
- data/lib/rbuv/signal.rb +10 -0
- data/lib/rbuv/timer.rb +1 -1
- data/lib/rbuv/version.rb +1 -1
- data/lib/rbuv.rb +18 -15
- data/spec/signal_spec.rb +33 -0
- data/spec/tcp_spec.rb +161 -0
- data/spec/timer_spec.rb +72 -55
- metadata +22 -11
- data/ext/rbuv/handle.c +0 -40
- data/ext/rbuv/handle.h +0 -14
data/ext/rbuv/rbuv_tcp.c
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
#include "rbuv_tcp.h"
|
2
|
+
|
3
|
+
struct rbuv_tcp_s {
|
4
|
+
uv_tcp_t *uv_handle;
|
5
|
+
VALUE cb_on_close;
|
6
|
+
VALUE cb_on_connection;
|
7
|
+
VALUE cb_on_read;
|
8
|
+
};
|
9
|
+
|
10
|
+
VALUE cRbuvTcp;
|
11
|
+
|
12
|
+
/* Allocator/deallocator */
|
13
|
+
static VALUE rbuv_tcp_alloc(VALUE klass);
|
14
|
+
static void rbuv_tcp_mark(rbuv_tcp_t *rbuv_tcp);
|
15
|
+
static void rbuv_tcp_free(rbuv_tcp_t *rbuv_tcp);
|
16
|
+
|
17
|
+
/* Methods */
|
18
|
+
/*
|
19
|
+
uv_tcp_bind(uv_tcp_t* handle, struct sockaddr_in)
|
20
|
+
uv_tcp_bind6(uv_tcp_t* handle, struct sockaddr_in6)
|
21
|
+
uv_tcp_connect(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in address, uv_connect❯
|
22
|
+
uv_tcp_connect6(uv_connect_t* req, uv_tcp_t* handle, struct sockaddr_in6 address, uv_conne❯
|
23
|
+
uv_tcp_getpeername(uv_tcp_t* handle, struct sockaddr* name, int* namelen)
|
24
|
+
uv_tcp_getsockname(uv_tcp_t* handle, struct sockaddr* name, int* namelen)
|
25
|
+
uv_tcp_init(uv_loop_t*, uv_tcp_t* handle)
|
26
|
+
uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay)
|
27
|
+
uv_tcp_nodelay(uv_tcp_t* handle, int enable)
|
28
|
+
uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock)
|
29
|
+
uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable)
|
30
|
+
*/
|
31
|
+
static VALUE rbuv_tcp_bind(VALUE self, VALUE ip, VALUE port);
|
32
|
+
//static VALUE rbuv_tcp_bind6(VALUE self, VALUE ip, VALUE port);
|
33
|
+
|
34
|
+
void Init_rbuv_tcp() {
|
35
|
+
cRbuvTcp = rb_define_class_under(mRbuv, "Tcp", cRbuvStream);
|
36
|
+
rb_define_alloc_func(cRbuvTcp, rbuv_tcp_alloc);
|
37
|
+
|
38
|
+
rb_define_method(cRbuvTcp, "bind", rbuv_tcp_bind, 2);
|
39
|
+
//rb_define_method(cRbuvTcp, "bind6", rbuv_tcp_bind6, 2);
|
40
|
+
}
|
41
|
+
|
42
|
+
VALUE rbuv_tcp_alloc(VALUE klass) {
|
43
|
+
rbuv_tcp_t *rbuv_tcp;
|
44
|
+
VALUE tcp;
|
45
|
+
|
46
|
+
rbuv_tcp = malloc(sizeof(*rbuv_tcp));
|
47
|
+
rbuv_tcp->uv_handle = malloc(sizeof(*rbuv_tcp->uv_handle));
|
48
|
+
uv_tcp_init(uv_default_loop(), rbuv_tcp->uv_handle);
|
49
|
+
rbuv_tcp->cb_on_close = Qnil;
|
50
|
+
rbuv_tcp->cb_on_connection = Qnil;
|
51
|
+
rbuv_tcp->cb_on_read = Qnil;
|
52
|
+
|
53
|
+
tcp = Data_Wrap_Struct(klass, rbuv_tcp_mark, rbuv_tcp_free, rbuv_tcp);
|
54
|
+
rbuv_tcp->uv_handle->data = (void *)tcp;
|
55
|
+
|
56
|
+
RBUV_DEBUG_LOG_DETAIL("rbuv_tcp: %p, uv_handle: %p, tcp: %s",
|
57
|
+
rbuv_tcp, rbuv_tcp->uv_handle,
|
58
|
+
RSTRING_PTR(rb_inspect(tcp)));
|
59
|
+
|
60
|
+
return tcp;
|
61
|
+
}
|
62
|
+
|
63
|
+
void rbuv_tcp_mark(rbuv_tcp_t *rbuv_tcp) {
|
64
|
+
assert(rbuv_tcp);
|
65
|
+
RBUV_DEBUG_LOG_DETAIL("rbuv_tcp: %p, uv_handle: %p, self: %lx",
|
66
|
+
rbuv_tcp, rbuv_tcp->uv_handle,
|
67
|
+
(VALUE)rbuv_tcp->uv_handle->data);
|
68
|
+
rb_gc_mark(rbuv_tcp->cb_on_close);
|
69
|
+
rb_gc_mark(rbuv_tcp->cb_on_connection);
|
70
|
+
rb_gc_mark(rbuv_tcp->cb_on_read);
|
71
|
+
}
|
72
|
+
|
73
|
+
void rbuv_tcp_free(rbuv_tcp_t *rbuv_tcp) {
|
74
|
+
RBUV_DEBUG_LOG_DETAIL("rbuv_tcp: %p, uv_handle: %p", rbuv_tcp, rbuv_tcp->uv_handle);
|
75
|
+
|
76
|
+
if (!_rbuv_handle_is_closing((rbuv_handle_t *)rbuv_tcp)) {
|
77
|
+
uv_close((uv_handle_t *)rbuv_tcp->uv_handle, NULL);
|
78
|
+
}
|
79
|
+
|
80
|
+
free(rbuv_tcp);
|
81
|
+
}
|
82
|
+
|
83
|
+
VALUE rbuv_tcp_bind(VALUE self, VALUE ip, VALUE port) {
|
84
|
+
const char *uv_ip;
|
85
|
+
int uv_port;
|
86
|
+
rbuv_tcp_t *rbuv_tcp;
|
87
|
+
struct sockaddr_in bind_addr;
|
88
|
+
|
89
|
+
uv_ip = RSTRING_PTR(ip);
|
90
|
+
uv_port = FIX2INT(port);
|
91
|
+
|
92
|
+
bind_addr = uv_ip4_addr(uv_ip, uv_port);
|
93
|
+
|
94
|
+
Data_Get_Struct(self, rbuv_tcp_t, rbuv_tcp);
|
95
|
+
RBUV_CHECK_UV_RETURN(uv_tcp_bind(rbuv_tcp->uv_handle, bind_addr));
|
96
|
+
|
97
|
+
RBUV_DEBUG_LOG_DETAIL("self: %s, ip: %s, port: %d, rbuv_tcp: %p, uv_handle: %p",
|
98
|
+
RSTRING_PTR(rb_inspect(self)), uv_ip, uv_port, rbuv_tcp,
|
99
|
+
rbuv_tcp->uv_handle);
|
100
|
+
|
101
|
+
return self;
|
102
|
+
}
|
data/ext/rbuv/rbuv_tcp.h
ADDED
@@ -1,12 +1,18 @@
|
|
1
|
-
#include "
|
1
|
+
#include "rbuv_timer.h"
|
2
2
|
|
3
3
|
VALUE cRbuvTimer;
|
4
4
|
|
5
5
|
struct rbuv_timer_s {
|
6
6
|
uv_timer_t *uv_handle;
|
7
|
-
VALUE
|
7
|
+
VALUE cb_on_close;
|
8
|
+
VALUE cb_on_timeout;
|
8
9
|
};
|
9
10
|
|
11
|
+
typedef struct {
|
12
|
+
uv_timer_t *uv_timer;
|
13
|
+
int status;
|
14
|
+
} _uv_timer_on_timeout_no_gvl_arg_t;
|
15
|
+
|
10
16
|
/* Allocator/deallocator */
|
11
17
|
static VALUE rbuv_timer_alloc(VALUE klass);
|
12
18
|
static void rbuv_timer_mark(rbuv_timer_t *rbuv_timer);
|
@@ -20,6 +26,7 @@ static VALUE rbuv_timer_repeat_set(VALUE self, VALUE repeat);
|
|
20
26
|
|
21
27
|
/* Private methods */
|
22
28
|
static void _uv_timer_on_timeout(uv_timer_t *uv_timer, int status);
|
29
|
+
static void _uv_timer_on_timeout_no_gvl(_uv_timer_on_timeout_no_gvl_arg_t *arg);
|
23
30
|
|
24
31
|
void Init_rbuv_timer() {
|
25
32
|
cRbuvTimer = rb_define_class_under(mRbuv, "Timer", cRbuvHandle);
|
@@ -38,7 +45,8 @@ VALUE rbuv_timer_alloc(VALUE klass) {
|
|
38
45
|
rbuv_timer = malloc(sizeof(*rbuv_timer));
|
39
46
|
rbuv_timer->uv_handle = malloc(sizeof(*rbuv_timer->uv_handle));
|
40
47
|
uv_timer_init(uv_default_loop(), rbuv_timer->uv_handle);
|
41
|
-
rbuv_timer->
|
48
|
+
rbuv_timer->cb_on_close = Qnil;
|
49
|
+
rbuv_timer->cb_on_timeout = Qnil;
|
42
50
|
|
43
51
|
timer = Data_Wrap_Struct(klass, rbuv_timer_mark, rbuv_timer_free, rbuv_timer);
|
44
52
|
rbuv_timer->uv_handle->data = (void *)timer;
|
@@ -48,12 +56,16 @@ VALUE rbuv_timer_alloc(VALUE klass) {
|
|
48
56
|
|
49
57
|
void rbuv_timer_mark(rbuv_timer_t *rbuv_timer) {
|
50
58
|
assert(rbuv_timer);
|
51
|
-
rb_gc_mark(rbuv_timer->
|
59
|
+
rb_gc_mark(rbuv_timer->cb_on_close);
|
60
|
+
rb_gc_mark(rbuv_timer->cb_on_timeout);
|
52
61
|
}
|
53
62
|
|
54
63
|
void rbuv_timer_free(rbuv_timer_t *rbuv_timer) {
|
55
64
|
assert(rbuv_timer);
|
56
|
-
|
65
|
+
RBUV_DEBUG_LOG_DETAIL("rbuv_timer: %p, uv_handle: %p", rbuv_timer, rbuv_timer->uv_handle);
|
66
|
+
if (!_rbuv_handle_is_closing((rbuv_handle_t *)rbuv_timer)) {
|
67
|
+
uv_close((uv_handle_t *)rbuv_timer->uv_handle, NULL);
|
68
|
+
}
|
57
69
|
free(rbuv_timer);
|
58
70
|
}
|
59
71
|
|
@@ -75,10 +87,11 @@ VALUE rbuv_timer_start(VALUE self, VALUE timeout, VALUE repeat) {
|
|
75
87
|
uv_repeat = NUM2ULL(repeat);
|
76
88
|
|
77
89
|
Data_Get_Struct(self, rbuv_timer_t, rbuv_timer);
|
78
|
-
rbuv_timer->
|
90
|
+
rbuv_timer->cb_on_timeout = block;
|
79
91
|
|
80
|
-
RBUV_DEBUG_LOG_DETAIL("rbuv_timer: %p, uv_handle: %p, _uv_timer_on_timeout: %p, timer: %
|
81
|
-
rbuv_timer, rbuv_timer->uv_handle, _uv_timer_on_timeout,
|
92
|
+
RBUV_DEBUG_LOG_DETAIL("rbuv_timer: %p, uv_handle: %p, _uv_timer_on_timeout: %p, timer: %s",
|
93
|
+
rbuv_timer, rbuv_timer->uv_handle, _uv_timer_on_timeout,
|
94
|
+
RSTRING_PTR(rb_inspect(self)));
|
82
95
|
uv_timer_start(rbuv_timer->uv_handle, _uv_timer_on_timeout,
|
83
96
|
uv_timeout, uv_repeat);
|
84
97
|
|
@@ -123,11 +136,19 @@ VALUE rbuv_timer_repeat_set(VALUE self, VALUE repeat) {
|
|
123
136
|
}
|
124
137
|
|
125
138
|
void _uv_timer_on_timeout(uv_timer_t *uv_timer, int status) {
|
139
|
+
_uv_timer_on_timeout_no_gvl_arg_t reg = { .uv_timer = uv_timer, .status = status };
|
140
|
+
rb_thread_call_with_gvl((rbuv_rb_blocking_function_t)_uv_timer_on_timeout_no_gvl, ®);
|
141
|
+
}
|
142
|
+
|
143
|
+
void _uv_timer_on_timeout_no_gvl(_uv_timer_on_timeout_no_gvl_arg_t *arg) {
|
144
|
+
uv_timer_t *uv_timer = arg->uv_timer;
|
145
|
+
int status = arg->status;
|
146
|
+
|
126
147
|
VALUE timer;
|
127
148
|
rbuv_timer_t *rbuv_timer;
|
128
149
|
|
129
150
|
timer = (VALUE)uv_timer->data;
|
130
151
|
Data_Get_Struct(timer, struct rbuv_timer_s, rbuv_timer);
|
131
152
|
|
132
|
-
rb_funcall(rbuv_timer->
|
133
|
-
}
|
153
|
+
rb_funcall(rbuv_timer->cb_on_timeout, id_call, 1, timer);
|
154
|
+
}
|
data/lib/rbuv/signal.rb
ADDED
data/lib/rbuv/timer.rb
CHANGED
data/lib/rbuv/version.rb
CHANGED
data/lib/rbuv.rb
CHANGED
@@ -1,27 +1,30 @@
|
|
1
1
|
require 'rbuv/rbuv'
|
2
2
|
require 'rbuv/version'
|
3
3
|
require 'rbuv/timer'
|
4
|
+
require 'rbuv/signal'
|
4
5
|
|
5
6
|
module Rbuv
|
6
|
-
|
7
|
-
Loop.run
|
8
|
-
end
|
7
|
+
class << self
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def run_loop
|
10
|
+
Loop.run
|
11
|
+
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
yield
|
13
|
+
def stop_loop
|
14
|
+
Loop.stop
|
17
15
|
end
|
18
|
-
self.run_loop
|
19
|
-
end
|
20
16
|
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
alias stop stop_loop
|
18
|
+
|
19
|
+
def run
|
20
|
+
Timer.start(0, 0) { yield }
|
21
|
+
self.run_loop
|
22
|
+
end
|
23
|
+
|
24
|
+
def run_block
|
25
|
+
Timer.start(0, 0) { yield }
|
26
|
+
Loop.run_once
|
24
27
|
end
|
25
|
-
|
28
|
+
|
26
29
|
end
|
27
30
|
end
|
data/spec/signal_spec.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rbuv::Signal do
|
4
|
+
it "#start" do
|
5
|
+
block = mock
|
6
|
+
block.should_receive(:call).once
|
7
|
+
|
8
|
+
Rbuv.run do
|
9
|
+
sig = Rbuv::Signal.new
|
10
|
+
sig.start 2 do
|
11
|
+
block.call
|
12
|
+
sig.close
|
13
|
+
end
|
14
|
+
|
15
|
+
Process.kill(2, Process.pid)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "#stop" do
|
20
|
+
block = mock
|
21
|
+
block.should_receive(:call).once
|
22
|
+
|
23
|
+
Rbuv.run do
|
24
|
+
sig = Rbuv::Signal.new
|
25
|
+
sig.start 2 do
|
26
|
+
block.call
|
27
|
+
sig.stop
|
28
|
+
end
|
29
|
+
|
30
|
+
Process.kill(2, Process.pid)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/spec/tcp_spec.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'socket'
|
3
|
+
|
4
|
+
def port_in_use?(port, host='127.0.0.1')
|
5
|
+
s = TCPServer.new host, port
|
6
|
+
s.close
|
7
|
+
false
|
8
|
+
rescue Errno::EADDRINUSE
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def port_alive?(port, host='127.0.0.1')
|
13
|
+
s = TCPSocket.new host, port
|
14
|
+
s.close
|
15
|
+
false
|
16
|
+
rescue Errno::ECONNREFUSED
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
describe Rbuv::Tcp do
|
21
|
+
it { should be_a_kind_of Rbuv::Stream }
|
22
|
+
|
23
|
+
it "#bind" do
|
24
|
+
port_in_use?(60000).should be_false
|
25
|
+
|
26
|
+
Rbuv.run do
|
27
|
+
pending "this spec does't pass on linux machines, see #1 on github"
|
28
|
+
begin
|
29
|
+
tcp = Rbuv::Tcp.new
|
30
|
+
tcp.bind '127.0.0.1', 60000
|
31
|
+
|
32
|
+
port_in_use?(60000).should be_true
|
33
|
+
ensure
|
34
|
+
tcp.close
|
35
|
+
end
|
36
|
+
|
37
|
+
port_in_use?(60000).should be_false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "#listen" do
|
42
|
+
it "when address not in use" do
|
43
|
+
port_in_use?(60000).should be_false
|
44
|
+
|
45
|
+
Rbuv.run do
|
46
|
+
begin
|
47
|
+
tcp = Rbuv::Tcp.new
|
48
|
+
tcp.bind '127.0.0.1', 60000
|
49
|
+
tcp.listen(10) { Rbuv.stop_loop }
|
50
|
+
|
51
|
+
port_in_use?(60000).should be_true
|
52
|
+
ensure
|
53
|
+
tcp.close
|
54
|
+
end
|
55
|
+
|
56
|
+
port_in_use?(60000).should be_false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
it "when address already in use" do
|
61
|
+
port_in_use?(60000).should be_false
|
62
|
+
|
63
|
+
Rbuv.run do
|
64
|
+
begin
|
65
|
+
s = TCPServer.new '127.0.0.1', 60000
|
66
|
+
|
67
|
+
tcp = Rbuv::Tcp.new
|
68
|
+
tcp.bind '127.0.0.1', 60000
|
69
|
+
expect { tcp.listen(10) {} }.to raise_error
|
70
|
+
ensure
|
71
|
+
s.close
|
72
|
+
tcp.close
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should call the on_connection callback when connection coming" do
|
78
|
+
on_connection = mock
|
79
|
+
on_connection.should_receive(:call).once
|
80
|
+
|
81
|
+
Rbuv.run do
|
82
|
+
tcp = Rbuv::Tcp.new
|
83
|
+
tcp.bind '127.0.0.1', 60000
|
84
|
+
|
85
|
+
tcp.listen(10) do
|
86
|
+
on_connection.call
|
87
|
+
tcp.close
|
88
|
+
end
|
89
|
+
|
90
|
+
sock = TCPSocket.new '127.0.0.1', 60000
|
91
|
+
sock.close
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "#accept" do
|
97
|
+
port_in_use?(60000).should be_false
|
98
|
+
|
99
|
+
Rbuv.run do
|
100
|
+
tcp = Rbuv::Tcp.new
|
101
|
+
tcp.bind '127.0.0.1', 60000
|
102
|
+
|
103
|
+
sock = nil
|
104
|
+
|
105
|
+
tcp.listen(10) do |s|
|
106
|
+
c = Rbuv::Tcp.new
|
107
|
+
expect { s.accept(c) }.not_to raise_error
|
108
|
+
sock.close
|
109
|
+
tcp.close
|
110
|
+
end
|
111
|
+
|
112
|
+
sock = TCPSocket.new '127.0.0.1', 60000
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "#close" do
|
117
|
+
it "affect #closing?" do
|
118
|
+
Rbuv.run do
|
119
|
+
tcp = Rbuv::Tcp.new
|
120
|
+
tcp.close do
|
121
|
+
tcp.closing?.should be_true
|
122
|
+
end
|
123
|
+
tcp.closing?.should be_true
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it "call once" do
|
128
|
+
on_close = mock
|
129
|
+
on_close.should_receive(:call).once
|
130
|
+
|
131
|
+
Rbuv.run do
|
132
|
+
tcp = Rbuv::Tcp.new
|
133
|
+
|
134
|
+
tcp.close do
|
135
|
+
on_close.call
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "call multi-times" do
|
141
|
+
on_close = mock
|
142
|
+
on_close.should_receive(:call).once
|
143
|
+
|
144
|
+
no_on_close = mock
|
145
|
+
no_on_close.should_not_receive(:call)
|
146
|
+
|
147
|
+
Rbuv.run do
|
148
|
+
tcp = Rbuv::Tcp.new
|
149
|
+
|
150
|
+
tcp.close do
|
151
|
+
on_close.call
|
152
|
+
end
|
153
|
+
|
154
|
+
tcp.close do
|
155
|
+
no_on_close.call
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|