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.
@@ -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
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef RBUV_TCP_H_
2
+ #define RBUV_TCP_H_
3
+
4
+ #include "rbuv.h"
5
+
6
+ typedef struct rbuv_tcp_s rbuv_tcp_t;
7
+
8
+ extern VALUE cRbuvTcp;
9
+
10
+ void Init_rbuv_tcp();
11
+
12
+ #endif /* RBUV_TCP_H_ */
@@ -1,12 +1,18 @@
1
- #include "timer.h"
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 cb;
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->cb = Qnil;
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->cb);
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
- rbuv_handle_close((rbuv_handle_t *)rbuv_timer);
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->cb = block;
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: %ld",
81
- rbuv_timer, rbuv_timer->uv_handle, _uv_timer_on_timeout, self);
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, &reg);
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->cb, id_call, 1, timer);
133
- }
153
+ rb_funcall(rbuv_timer->cb_on_timeout, id_call, 1, timer);
154
+ }
@@ -2,7 +2,6 @@
2
2
  #define RBUV_TIMER_H_
3
3
 
4
4
  #include "rbuv.h"
5
- #include "handle.h"
6
5
 
7
6
  typedef struct rbuv_timer_s rbuv_timer_t;
8
7
 
@@ -10,4 +9,4 @@ extern VALUE cRbuvTimer;
10
9
 
11
10
  void Init_rbuv_timer();
12
11
 
13
- #endif /* RBUV_TIMER_H_ */
12
+ #endif /* RBUV_TIMER_H_ */
@@ -0,0 +1,10 @@
1
+ module Rbuv
2
+ class Signal
3
+ ::Signal.list.each do |signame, signum|
4
+ const_set signame, signum
5
+ end
6
+ def self.start(*args)
7
+ self.new.start(*args) { |*block_args| yield(*block_args) }
8
+ end
9
+ end
10
+ end
data/lib/rbuv/timer.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Rbuv
2
2
  class Timer
3
3
  def self.start(*args)
4
- Timer.new.start(*args) { |timer| yield timer }
4
+ self.new.start(*args) { |*block_args| yield(*block_args) }
5
5
  end
6
6
  end
7
7
  end
data/lib/rbuv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rbuv
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
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
- def self.run_loop
7
- Loop.run
8
- end
7
+ class << self
9
8
 
10
- def self.stop_loop
11
- Loop.stop
12
- end
9
+ def run_loop
10
+ Loop.run
11
+ end
13
12
 
14
- def self.run
15
- Timer.start 0, 0 do
16
- yield
13
+ def stop_loop
14
+ Loop.stop
17
15
  end
18
- self.run_loop
19
- end
20
16
 
21
- def self.run_block
22
- Timer.start 0, 0 do
23
- yield
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
- Loop.run_once
28
+
26
29
  end
27
30
  end
@@ -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