rbuv 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9d6903efbe33b48ef3d2deb2cee18173a708ab2
4
- data.tar.gz: dcb456920a095dfc229137299eaa597bf19b2948
3
+ metadata.gz: 308a6259f4457d5dd3ccd17dfd092940a75359ca
4
+ data.tar.gz: b8f8ef7b0a3aca6e69539fe09d047fc865f46614
5
5
  SHA512:
6
- metadata.gz: 561fc7896938cee33ceff8d502d8ca96ed53f12c0109f9f9b454d806de3b379d7784912b93ce410f2b8479c06dd9c3d5341e9a7516d63adf5057ef5cfb37254d
7
- data.tar.gz: 573137d980ae1f9a77d3d251f424c1f2c12d6e188d4b2586a02b8d33e143dd240430ed279d4b9f5279ea3e413547ac3340fba2effafae662c55808e5b912340d
6
+ metadata.gz: d9d906a50927d5e8c81439cce4f73a800e2e86812050dcfb91dda274a4ba4ef78bb69e06fc301f3fdfb66dbb63580d41d4b86a1e2be25cd1e09295e815132fde
7
+ data.tar.gz: 1b784c9a54821db879f02335f17067d59d90176c5618bb0e571c8cd2591f51043fbc05f0184db052e0f1c323b65be16783ee50acbf580c8931b8ceaa01d172da
data/.gitignore CHANGED
@@ -20,3 +20,5 @@ rbuv.bundle
20
20
  coverage/
21
21
  xcode/
22
22
  .rbx/
23
+ .ruby-gemset
24
+ .ruby-version
data/ext/rbuv/extconf.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'mkmf'
2
2
  require 'rbconfig'
3
3
 
4
+ have_header('ruby/thread.h')
5
+ have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
6
+
4
7
  case RbConfig::CONFIG["host_os"]
5
8
  when /darwin/
6
9
  have_framework("CoreFoundation")
data/ext/rbuv/rbuv.c CHANGED
@@ -12,4 +12,7 @@ void Init_rbuv() {
12
12
  Init_rbuv_handle();
13
13
  Init_rbuv_loop();
14
14
  Init_rbuv_timer();
15
+ Init_rbuv_stream();
16
+ Init_rbuv_tcp();
17
+ Init_rbuv_signal();
15
18
  }
data/ext/rbuv/rbuv.h CHANGED
@@ -4,14 +4,20 @@
4
4
  #include <assert.h>
5
5
 
6
6
  #include <ruby.h>
7
+ #ifdef HAVE_RUBY_THREAD_H
8
+ # include <ruby/thread.h>
9
+ #endif
7
10
  #include <uv.h>
8
11
 
9
- #include "debug.h"
12
+ #include "rbuv_debug.h"
10
13
 
11
- #include "error.h"
12
- #include "handle.h"
13
- #include "loop.h"
14
- #include "timer.h"
14
+ #include "rbuv_error.h"
15
+ #include "rbuv_handle.h"
16
+ #include "rbuv_loop.h"
17
+ #include "rbuv_timer.h"
18
+ #include "rbuv_stream.h"
19
+ #include "rbuv_tcp.h"
20
+ #include "rbuv_signal.h"
15
21
 
16
22
  extern ID id_call;
17
23
 
@@ -24,4 +30,11 @@ extern VALUE mRbuv;
24
30
  } \
25
31
  } while(0)
26
32
 
27
- #endif /* RBUV_H_ */
33
+ #define RBUV_OFFSETOF(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
34
+ #define RBUV_CONTAINTER_OF(ptr, type, member) ({ \
35
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
36
+ (type *)( (char *)__mptr - RBUV_OFFSETOF(type, member) );})
37
+
38
+ typedef void *(*rbuv_rb_blocking_function_t)(void *);
39
+
40
+ #endif /* RBUV_H_ */
@@ -24,4 +24,4 @@
24
24
 
25
25
  # endif
26
26
 
27
- #endif /* RBUV_DEBUG_H_ */
27
+ #endif /* RBUV_DEBUG_H_ */
@@ -1,7 +1,7 @@
1
- #include "error.h"
1
+ #include "rbuv_error.h"
2
2
 
3
3
  VALUE eRbuvError;
4
4
 
5
5
  void Init_rbuv_error() {
6
6
  eRbuvError = rb_define_class_under(mRbuv, "Error", rb_eStandardError);
7
- }
7
+ }
@@ -7,4 +7,4 @@ extern VALUE eRbuvError;
7
7
 
8
8
  void Init_rbuv_error();
9
9
 
10
- #endif /* RBUV_ERROR_H_ */
10
+ #endif /* RBUV_ERROR_H_ */
@@ -0,0 +1,124 @@
1
+ #include "rbuv_handle.h"
2
+
3
+ struct rbuv_handle_s {
4
+ uv_handle_t *uv_handle;
5
+ VALUE cb_on_close;
6
+ };
7
+
8
+ typedef struct {
9
+ uv_handle_t *uv_handle;
10
+ } _uv_handle_on_close_arg_t;
11
+
12
+ VALUE cRbuvHandle;
13
+
14
+ /* Methods */
15
+ static VALUE rbuv_handle_close(VALUE self);
16
+ static VALUE rbuv_handle_is_active(VALUE self);
17
+ static VALUE rbuv_handle_is_closing(VALUE self);
18
+
19
+ /* Private methods */
20
+ static void _uv_handle_close(uv_handle_t *uv_handle);
21
+ static void _uv_handle_on_close(uv_handle_t *uv_handle);
22
+ static void _uv_handle_on_close_no_gvl(_uv_handle_on_close_arg_t *arg);
23
+
24
+ void Init_rbuv_handle() {
25
+ cRbuvHandle = rb_define_class_under(mRbuv, "Handle", rb_cObject);
26
+ rb_undef_alloc_func(cRbuvHandle);
27
+
28
+ rb_define_method(cRbuvHandle, "close", rbuv_handle_close, 0);
29
+ rb_define_method(cRbuvHandle, "active?", rbuv_handle_is_active, 0);
30
+ rb_define_method(cRbuvHandle, "closing?", rbuv_handle_is_closing, 0);
31
+ }
32
+
33
+ VALUE rbuv_handle_close(VALUE self) {
34
+ rbuv_handle_t *rbuv_handle;
35
+ VALUE block;
36
+
37
+ if (rb_block_given_p()) {
38
+ block = rb_block_proc();
39
+ } else {
40
+ block = Qnil;
41
+ }
42
+
43
+ Data_Get_Struct(self, rbuv_handle_t, rbuv_handle);
44
+
45
+ _rbuv_handle_close(rbuv_handle, block);
46
+
47
+ return Qnil;
48
+ }
49
+
50
+ VALUE rbuv_handle_is_active(VALUE self) {
51
+ rbuv_handle_t *rbuv_handle;
52
+
53
+ Data_Get_Struct(self, rbuv_handle_t, rbuv_handle);
54
+
55
+ return _rbuv_handle_is_active(rbuv_handle) ? Qtrue : Qfalse;
56
+ }
57
+
58
+ VALUE rbuv_handle_is_closing(VALUE self) {
59
+ rbuv_handle_t *rbuv_handle;
60
+
61
+ Data_Get_Struct(self, rbuv_handle_t, rbuv_handle);
62
+
63
+ return _rbuv_handle_is_closing(rbuv_handle) ? Qtrue : Qfalse;
64
+ }
65
+
66
+ int _rbuv_handle_is_active(rbuv_handle_t *rbuv_handle) {
67
+ assert(rbuv_handle);
68
+ return uv_is_active(rbuv_handle->uv_handle);
69
+ }
70
+
71
+ int _rbuv_handle_is_closing(rbuv_handle_t *rbuv_handle) {
72
+ assert(rbuv_handle);
73
+ return uv_is_closing(rbuv_handle->uv_handle);
74
+ }
75
+
76
+ void _rbuv_handle_close(rbuv_handle_t *rbuv_handle, VALUE block) {
77
+ assert(rbuv_handle);
78
+ RBUV_DEBUG_LOG_DETAIL("rbuv_handle: %p, uv_handle: %p, block: %s",
79
+ rbuv_handle, rbuv_handle->uv_handle,
80
+ RSTRING_PTR(rb_inspect(block)));
81
+ if (!_rbuv_handle_is_closing(rbuv_handle)) {
82
+ RBUV_DEBUG_LOG_DETAIL("closing rbuv_handle: %p, uv_handle: %p, block: %s",
83
+ rbuv_handle, rbuv_handle->uv_handle,
84
+ RSTRING_PTR(rb_inspect(block)));
85
+ rbuv_handle->cb_on_close = block;
86
+ _uv_handle_close(rbuv_handle->uv_handle);
87
+ }
88
+ }
89
+
90
+ void _uv_handle_close(uv_handle_t *uv_handle) {
91
+ assert(uv_handle);
92
+ uv_close(uv_handle, _uv_handle_on_close);
93
+ }
94
+
95
+ void _uv_handle_on_close(uv_handle_t *uv_handle) {
96
+ _uv_handle_on_close_arg_t arg = { .uv_handle = uv_handle };
97
+ rb_thread_call_with_gvl((rbuv_rb_blocking_function_t)_uv_handle_on_close_no_gvl, &arg);
98
+ }
99
+
100
+ void _uv_handle_on_close_no_gvl(_uv_handle_on_close_arg_t *arg) {
101
+ uv_handle_t *uv_handle = arg->uv_handle;
102
+
103
+ VALUE handle;
104
+ rbuv_handle_t *rbuv_handle;
105
+ VALUE on_close;
106
+
107
+ handle = (VALUE)uv_handle->data;
108
+
109
+ RBUV_DEBUG_LOG_DETAIL("uv_handle: %p, handle: %s",
110
+ uv_handle, RSTRING_PTR(rb_inspect(handle)));
111
+
112
+ Data_Get_Struct(handle, rbuv_handle_t, rbuv_handle);
113
+
114
+ on_close = rbuv_handle->cb_on_close;
115
+ rbuv_handle->cb_on_close = Qnil;
116
+
117
+ RBUV_DEBUG_LOG_DETAIL("handle: %s, on_close: %s",
118
+ RSTRING_PTR(rb_inspect(handle)),
119
+ RSTRING_PTR(rb_inspect(on_close)));
120
+
121
+ if (RTEST(on_close)) {
122
+ rb_funcall(on_close, id_call, 1, handle);
123
+ }
124
+ }
@@ -0,0 +1,16 @@
1
+ #ifndef RBUV_HANDLE_H_
2
+ #define RBUV_HANDLE_H_
3
+
4
+ #include "rbuv.h"
5
+
6
+ typedef struct rbuv_handle_s rbuv_handle_t;
7
+
8
+ extern VALUE cRbuvHandle;
9
+
10
+ void Init_rbuv_handle();
11
+
12
+ int _rbuv_handle_is_active(rbuv_handle_t *rbuv_handle);
13
+ int _rbuv_handle_is_closing(rbuv_handle_t *rbuv_handle);
14
+ void _rbuv_handle_close(rbuv_handle_t *rbuv_handle, VALUE block);
15
+
16
+ #endif /* RBUV_HANDLE_H_ */
@@ -1,9 +1,13 @@
1
- #include "loop.h"
1
+ #include "rbuv_loop.h"
2
2
 
3
3
  struct rbuv_handle_s {
4
4
  uv_handle_t *uv_handle;
5
5
  };
6
6
 
7
+ typedef struct {
8
+ int mode;
9
+ } _rbuv_loop_run_arg_t;
10
+
7
11
  VALUE cRbuvLoop;
8
12
 
9
13
  /* Methods */
@@ -14,6 +18,7 @@ static VALUE rbuv_loop_s_run_nowait(VALUE klass);
14
18
 
15
19
  /* Private methods */
16
20
  static void _rbuv_loop_run(uv_run_mode mode);
21
+ static void _rbuv_loop_run_no_gvl(_rbuv_loop_run_arg_t *arg);
17
22
 
18
23
  void Init_rbuv_loop() {
19
24
  cRbuvLoop = rb_define_class_under(mRbuv, "Loop", cRbuvHandle);
@@ -46,5 +51,16 @@ VALUE rbuv_loop_s_run_nowait(VALUE klass) {
46
51
  }
47
52
 
48
53
  void _rbuv_loop_run(uv_run_mode mode) {
49
- uv_run(uv_default_loop(), mode);
54
+ _rbuv_loop_run_arg_t arg = { .mode = mode };
55
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
56
+ rb_thread_call_without_gvl((rbuv_rb_blocking_function_t)_rbuv_loop_run_no_gvl,
57
+ &arg, RUBY_UBF_IO, 0);
58
+ #else
59
+ rb_thread_blocking_region((rb_blocking_function_t *)_rbuv_loop_run_no_gvl,
60
+ &arg, RUBY_UBF_IO, 0);
61
+ #endif
62
+ }
63
+
64
+ void _rbuv_loop_run_no_gvl(_rbuv_loop_run_arg_t *arg) {
65
+ uv_run(uv_default_loop(), arg->mode);
50
66
  }
@@ -2,7 +2,6 @@
2
2
  #define RBUV_LOOP_H_
3
3
 
4
4
  #include "rbuv.h"
5
- #include "handle.h"
6
5
 
7
6
  typedef struct rbuv_loop_s rbuv_loop_t;
8
7
 
@@ -10,4 +9,4 @@ extern VALUE cRbuvLoop;
10
9
 
11
10
  void Init_rbuv_loop();
12
11
 
13
- #endif /* RBUV_LOOP_H_ */
12
+ #endif /* RBUV_LOOP_H_ */
@@ -0,0 +1,119 @@
1
+ #include "rbuv_signal.h"
2
+
3
+ struct rbuv_signal_s {
4
+ uv_signal_t *uv_handle;
5
+ VALUE cb_on_signal;
6
+ };
7
+
8
+ typedef struct _uv_signal_on_signal_no_gvl_arg_s {
9
+ uv_signal_t *uv_signal;
10
+ int signum;
11
+ } _uv_signal_on_signal_no_gvl_arg_t;
12
+
13
+ VALUE cRbuvSignal;
14
+
15
+ /* Allocator/deallocator */
16
+ static VALUE rbuv_signal_alloc(VALUE klass);
17
+ static void rbuv_signal_mark(rbuv_signal_t *rbuv_signal);
18
+ static void rbuv_signal_free(rbuv_signal_t *rbuv_signal);
19
+
20
+ /* Methods */
21
+ static VALUE rbuv_signal_start(VALUE self, VALUE signum);
22
+ static VALUE rbuv_signal_stop(VALUE self);
23
+
24
+ /* Private methods */
25
+ static void _uv_signal_on_signal(uv_signal_t *uv_signal, int signum);
26
+ static void _uv_signal_on_signal_no_gvl(_uv_signal_on_signal_no_gvl_arg_t *arg);
27
+
28
+ void Init_rbuv_signal() {
29
+ cRbuvSignal = rb_define_class_under(mRbuv, "Signal", cRbuvHandle);
30
+ rb_define_alloc_func(cRbuvSignal, rbuv_signal_alloc);
31
+
32
+ rb_define_method(cRbuvSignal, "start", rbuv_signal_start, 1);
33
+ rb_define_method(cRbuvSignal, "stop", rbuv_signal_stop, 0);
34
+ }
35
+
36
+ VALUE rbuv_signal_alloc(VALUE klass) {
37
+ rbuv_signal_t *rbuv_signal;
38
+ VALUE signal;
39
+
40
+ rbuv_signal = malloc(sizeof(*rbuv_signal));
41
+ rbuv_signal->uv_handle = malloc(sizeof(*rbuv_signal->uv_handle));
42
+ uv_signal_init(uv_default_loop(), rbuv_signal->uv_handle);
43
+ rbuv_signal->cb_on_signal = Qnil;
44
+
45
+ signal = Data_Wrap_Struct(klass, rbuv_signal_mark, rbuv_signal_free, rbuv_signal);
46
+ rbuv_signal->uv_handle->data = (void *)signal;
47
+
48
+ RBUV_DEBUG_LOG_DETAIL("rbuv_signal: %p, uv_handle: %p, signal: %s",
49
+ rbuv_signal, rbuv_signal->uv_handle,
50
+ RSTRING_PTR(rb_inspect(signal)));
51
+
52
+ return signal;
53
+ }
54
+
55
+ void rbuv_signal_mark(rbuv_signal_t *rbuv_signal) {
56
+ assert(rbuv_signal);
57
+ RBUV_DEBUG_LOG_DETAIL("rbuv_signal: %p, uv_handle: %p, self: %lx",
58
+ rbuv_signal, rbuv_signal->uv_handle,
59
+ (VALUE)rbuv_signal->uv_handle->data);
60
+ rb_gc_mark(rbuv_signal->cb_on_signal);
61
+ }
62
+
63
+ void rbuv_signal_free(rbuv_signal_t *rbuv_signal) {
64
+ RBUV_DEBUG_LOG_DETAIL("rbuv_signal: %p, uv_handle: %p", rbuv_signal, rbuv_signal->uv_handle);
65
+
66
+ if (!_rbuv_handle_is_closing((rbuv_handle_t *)rbuv_signal)) {
67
+ uv_close((uv_handle_t *)rbuv_signal->uv_handle, NULL);
68
+ }
69
+
70
+ free(rbuv_signal);
71
+ }
72
+
73
+ VALUE rbuv_signal_start(VALUE self, VALUE signum) {
74
+ VALUE block;
75
+ int uv_signum;
76
+ rbuv_signal_t *rbuv_signal;
77
+
78
+ rb_need_block();
79
+ block = rb_block_proc();
80
+ uv_signum = NUM2INT(signum);
81
+
82
+ Data_Get_Struct(self, rbuv_signal_t, rbuv_signal);
83
+ rbuv_signal->cb_on_signal = block;
84
+
85
+ RBUV_DEBUG_LOG_DETAIL("rbuv_signal: %p, uv_handle: %p, _uv_signal_on_signal: %p, signal: %s",
86
+ rbuv_signal, rbuv_signal->uv_handle, _uv_signal_on_signal,
87
+ RSTRING_PTR(rb_inspect(self)));
88
+ uv_signal_start(rbuv_signal->uv_handle, _uv_signal_on_signal, uv_signum);
89
+
90
+ return self;
91
+ }
92
+
93
+ VALUE rbuv_signal_stop(VALUE self) {
94
+ rbuv_signal_t *rbuv_signal;
95
+
96
+ Data_Get_Struct(self, rbuv_signal_t, rbuv_signal);
97
+
98
+ uv_signal_stop(rbuv_signal->uv_handle);
99
+
100
+ return self;
101
+ }
102
+
103
+ void _uv_signal_on_signal(uv_signal_t *uv_signal, int signum) {
104
+ _uv_signal_on_signal_no_gvl_arg_t reg = { .uv_signal = uv_signal, .signum = signum };
105
+ rb_thread_call_with_gvl((rbuv_rb_blocking_function_t)_uv_signal_on_signal_no_gvl, &reg);
106
+ }
107
+
108
+ void _uv_signal_on_signal_no_gvl(_uv_signal_on_signal_no_gvl_arg_t *arg) {
109
+ uv_signal_t *uv_signal = arg->uv_signal;
110
+ int signum = arg->signum;
111
+
112
+ VALUE signal;
113
+ rbuv_signal_t *rbuv_signal;
114
+
115
+ signal = (VALUE)uv_signal->data;
116
+ Data_Get_Struct(signal, struct rbuv_signal_s, rbuv_signal);
117
+
118
+ rb_funcall(rbuv_signal->cb_on_signal, id_call, 2, signal, INT2FIX(signum));
119
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef RBUV_SIGNAL_H_
2
+ #define RBUV_SIGNAL_H_
3
+
4
+ #include "rbuv.h"
5
+
6
+ typedef struct rbuv_signal_s rbuv_signal_t;
7
+
8
+ extern VALUE cRbuvSignal;
9
+
10
+ void Init_rbuv_signal();
11
+
12
+ #endif /* RBUV_SIGNAL_H_ */
@@ -0,0 +1,253 @@
1
+ #include "rbuv_stream.h"
2
+
3
+ struct rbuv_stream_s {
4
+ uv_stream_t *uv_handle;
5
+ VALUE cb_on_close;
6
+ VALUE cb_on_connection;
7
+ VALUE cb_on_read;
8
+ };
9
+
10
+ typedef struct {
11
+ uv_write_t req;
12
+ uv_buf_t buf;
13
+ } rbuv_write_req_t;
14
+
15
+ typedef struct {
16
+ uv_stream_t *uv_stream;
17
+ int status;
18
+ } _uv_stream_on_connection_arg_t;
19
+
20
+ typedef struct {
21
+ uv_stream_t *uv_stream;
22
+ ssize_t nread;
23
+ uv_buf_t *buf;
24
+ } _uv_stream_on_read_arg_t;
25
+
26
+ VALUE cRbuvStream;
27
+
28
+ /* Methods */
29
+ static VALUE rbuv_stream_listen(VALUE self, VALUE backlog);
30
+ static VALUE rbuv_stream_accept(VALUE self, VALUE client);
31
+ static VALUE rbuv_stream_is_readable(VALUE self);
32
+ static VALUE rbuv_stream_is_writable(VALUE self);
33
+ static VALUE rbuv_stream_shutdown(VALUE self);
34
+ static VALUE rbuv_stream_read_start(VALUE self);
35
+ //static VALUE rbuv_stream_read2_start(VALUE self, VALUE client);
36
+ static VALUE rbuv_stream_read_stop(VALUE self);
37
+ static VALUE rbuv_stream_write(VALUE self, VALUE data);
38
+ //static VALUE rbuv_stream_write2(VALUE self);
39
+
40
+ /* Private methods */
41
+ static void _uv_stream_on_connection(uv_stream_t *server, int status);
42
+ static void _uv_stream_on_connection_no_gvl(_uv_stream_on_connection_arg_t *arg);
43
+ static uv_buf_t _uv_alloc_buffer(uv_handle_t *handle, size_t suggested_size);
44
+ static void _uv_stream_on_read(uv_stream_t *stream, ssize_t nread, uv_buf_t buf);
45
+ static void _uv_stream_on_read_no_gvl(_uv_stream_on_read_arg_t *arg);
46
+ static void _uv_stream_on_write(uv_write_t *req, int status);
47
+
48
+ void Init_rbuv_stream() {
49
+ cRbuvStream = rb_define_class_under(mRbuv, "Stream", cRbuvHandle);
50
+ rb_undef_alloc_func(cRbuvStream);
51
+
52
+ rb_define_method(cRbuvStream, "listen", rbuv_stream_listen, 1);
53
+ rb_define_method(cRbuvStream, "accept", rbuv_stream_accept, 1);
54
+ rb_define_method(cRbuvStream, "readable?", rbuv_stream_is_readable, 0);
55
+ rb_define_method(cRbuvStream, "writable?", rbuv_stream_is_writable, 0);
56
+ rb_define_method(cRbuvStream, "shutdown", rbuv_stream_shutdown, 0);
57
+ rb_define_method(cRbuvStream, "read_start", rbuv_stream_read_start, 0);
58
+ // rb_define_method(cRbuvStream, "read2_start", rbuv_stream_read2_start, 0);
59
+ rb_define_method(cRbuvStream, "read_stop", rbuv_stream_read_stop, 0);
60
+ rb_define_method(cRbuvStream, "write", rbuv_stream_write, 1);
61
+ // rb_define_method(cRbuvStream, "write2", rbuv_stream_write2, 1);
62
+ }
63
+
64
+ VALUE rbuv_stream_listen(VALUE self, VALUE backlog) {
65
+ rbuv_stream_t *rbuv_server;
66
+ VALUE block;
67
+ int uv_backlog;
68
+
69
+ rb_need_block();
70
+ block = rb_block_proc();
71
+
72
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_server);
73
+ rbuv_server->cb_on_connection = block;
74
+
75
+ uv_backlog = FIX2INT(backlog);
76
+
77
+ RBUV_DEBUG_LOG_DETAIL("self: %s, backlog: %d, block: %s, rbuv_server: %p, "
78
+ "uv_handle: %p, _uv_stream_on_connection: %p",
79
+ RSTRING_PTR(rb_inspect(self)),
80
+ uv_backlog,
81
+ RSTRING_PTR(rb_inspect(block)),
82
+ rbuv_server,
83
+ rbuv_server->uv_handle,
84
+ _uv_stream_on_connection);
85
+ RBUV_CHECK_UV_RETURN(uv_listen(rbuv_server->uv_handle, uv_backlog, _uv_stream_on_connection));
86
+
87
+ return self;
88
+ }
89
+
90
+ VALUE rbuv_stream_accept(VALUE self, VALUE client) {
91
+ rbuv_stream_t *rbuv_server;
92
+ rbuv_stream_t *rbuv_client;
93
+
94
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_server);
95
+ Data_Get_Struct(client, rbuv_stream_t, rbuv_client);
96
+
97
+ RBUV_CHECK_UV_RETURN(uv_accept(rbuv_server->uv_handle, rbuv_client->uv_handle));
98
+
99
+ return self;
100
+ }
101
+
102
+ VALUE rbuv_stream_is_readable(VALUE self) {
103
+ rbuv_stream_t *rbuv_stream;
104
+
105
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_stream);
106
+
107
+ return uv_is_readable(rbuv_stream->uv_handle) ? Qtrue : Qfalse;
108
+ }
109
+
110
+ VALUE rbuv_stream_is_writable(VALUE self) {
111
+ rbuv_stream_t *rbuv_stream;
112
+
113
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_stream);
114
+
115
+ return uv_is_writable(rbuv_stream->uv_handle) ? Qtrue : Qfalse;
116
+ }
117
+
118
+ VALUE rbuv_stream_shutdown(VALUE self) {
119
+ rbuv_stream_t *rbuv_stream;
120
+
121
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_stream);
122
+
123
+ rb_raise(rb_eNotImpError, __func__);
124
+
125
+ return self;
126
+ }
127
+
128
+ VALUE rbuv_stream_read_start(VALUE self) {
129
+ rbuv_stream_t *rbuv_stream;
130
+ VALUE block;
131
+
132
+ rb_need_block();
133
+ block = rb_block_proc();
134
+
135
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_stream);
136
+ rbuv_stream->cb_on_read = block;
137
+
138
+ uv_read_start(rbuv_stream->uv_handle, _uv_alloc_buffer, _uv_stream_on_read);
139
+
140
+ return self;
141
+ }
142
+
143
+ VALUE rbuv_stream_read_stop(VALUE self) {
144
+ rbuv_stream_t *rbuv_stream;
145
+
146
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_stream);
147
+
148
+ uv_read_stop(rbuv_stream->uv_handle);
149
+
150
+ return self;
151
+ }
152
+
153
+ VALUE rbuv_stream_write(VALUE self, VALUE data) {
154
+ rbuv_stream_t *rbuv_stream;
155
+ rbuv_write_req_t *req;
156
+
157
+ Data_Get_Struct(self, rbuv_stream_t, rbuv_stream);
158
+
159
+ req = malloc(sizeof(*req));
160
+
161
+ req->buf = uv_buf_init((char *)malloc(RSTRING_LEN(data)), (unsigned int)RSTRING_LEN(data));
162
+ memcpy(req->buf.base, RSTRING_PTR(data), RSTRING_LEN(data));
163
+
164
+ uv_write(&req->req, rbuv_stream->uv_handle, &req->buf, 1, _uv_stream_on_write);
165
+
166
+ return data;
167
+ }
168
+
169
+ void _uv_stream_on_connection(uv_stream_t *uv_server, int status) {
170
+ _uv_stream_on_connection_arg_t arg = { .uv_stream = uv_server, .status = status };
171
+ rb_thread_call_with_gvl((rbuv_rb_blocking_function_t)_uv_stream_on_connection_no_gvl, &arg);
172
+ }
173
+
174
+ void _uv_stream_on_connection_no_gvl(_uv_stream_on_connection_arg_t *arg) {
175
+ uv_stream_t *uv_server = arg->uv_stream;
176
+ int status = arg->status;
177
+
178
+ VALUE server;
179
+ rbuv_stream_t *rbuv_server;
180
+ VALUE on_connection;
181
+
182
+ RBUV_DEBUG_LOG("uv_server: %p, status: %d", uv_server, status);
183
+ if (status == -1) {
184
+ return;
185
+ }
186
+
187
+ server = (VALUE)uv_server->data;
188
+ Data_Get_Struct(server, rbuv_stream_t, rbuv_server);
189
+ on_connection = rbuv_server->cb_on_connection;
190
+
191
+ RBUV_DEBUG_LOG_DETAIL("server: %s, on_connection: %s",
192
+ RSTRING_PTR(rb_inspect(server)),
193
+ RSTRING_PTR(rb_inspect(on_connection)));
194
+
195
+ rb_funcall(on_connection, id_call, 1, server);
196
+ }
197
+
198
+ uv_buf_t _uv_alloc_buffer(uv_handle_t *handle, size_t suggested_size) {
199
+ return uv_buf_init((char *)malloc(suggested_size), (unsigned int)suggested_size);
200
+ }
201
+
202
+ void _uv_stream_on_read(uv_stream_t *uv_stream, ssize_t nread, uv_buf_t buf) {
203
+ _uv_stream_on_read_arg_t arg = { .uv_stream = uv_stream, .nread = nread, .buf = &buf };
204
+ rb_thread_call_with_gvl((rbuv_rb_blocking_function_t)_uv_stream_on_read_no_gvl, &arg);
205
+ }
206
+
207
+ void _uv_stream_on_read_no_gvl(_uv_stream_on_read_arg_t *arg) {
208
+ uv_stream_t *uv_stream = arg->uv_stream;
209
+ ssize_t nread = arg->nread;
210
+ uv_buf_t *buf = arg->buf;
211
+
212
+ VALUE stream;
213
+ rbuv_stream_t *rbuv_stream;
214
+ VALUE on_read;
215
+ uv_err_t uv_err;
216
+ VALUE error;
217
+
218
+ RBUV_DEBUG_LOG("uv_stream: %p, nread: %s", uv_stream, RSTRING_PTR(rb_inspect(nread)));
219
+
220
+ stream = (VALUE)uv_stream->data;
221
+ Data_Get_Struct(stream, rbuv_stream_t, rbuv_stream);
222
+ on_read = rbuv_stream->cb_on_read;
223
+ RBUV_DEBUG_LOG_DETAIL("stream: %s, on_read: %s",
224
+ RSTRING_PTR(rb_inspect(stream)),
225
+ RSTRING_PTR(rb_inspect(on_read)));
226
+
227
+ if (nread > 0) {
228
+ rb_funcall(on_read, id_call, 1, rb_str_new(buf->base, nread));
229
+ } else {
230
+ uv_err = uv_last_error(uv_default_loop());
231
+ if (uv_err.code == UV_EOF) {
232
+ error = rb_exc_new2(rb_eEOFError, "end of file reached");
233
+ } else {
234
+ error = rb_exc_new2(eRbuvError, uv_strerror(uv_err));
235
+ }
236
+ rb_funcall(on_read, id_call, 2, Qnil, error);
237
+ }
238
+
239
+ assert(buf->base);
240
+ free(buf->base);
241
+ }
242
+
243
+ void _uv_stream_on_write(uv_write_t *uv_req, int status) {
244
+ rbuv_write_req_t *rbuv_req;
245
+ RBUV_DEBUG_LOG("req: %p, status: %d", uv_req, status);
246
+
247
+ rbuv_req = RBUV_CONTAINTER_OF(uv_req, rbuv_write_req_t, req);
248
+
249
+ free(rbuv_req->buf.base);
250
+ free(rbuv_req);
251
+
252
+ RBUV_CHECK_UV_RETURN(status);
253
+ }
@@ -0,0 +1,12 @@
1
+ #ifndef RBUV_STREAM_H_
2
+ #define RBUV_STREAM_H_
3
+
4
+ #include "rbuv.h"
5
+
6
+ typedef struct rbuv_stream_s rbuv_stream_t;
7
+
8
+ extern VALUE cRbuvStream;
9
+
10
+ void Init_rbuv_stream();
11
+
12
+ #endif /* RBUV_STREAM_H_ */