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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 308a6259f4457d5dd3ccd17dfd092940a75359ca
|
4
|
+
data.tar.gz: b8f8ef7b0a3aca6e69539fe09d047fc865f46614
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9d906a50927d5e8c81439cce4f73a800e2e86812050dcfb91dda274a4ba4ef78bb69e06fc301f3fdfb66dbb63580d41d4b86a1e2be25cd1e09295e815132fde
|
7
|
+
data.tar.gz: 1b784c9a54821db879f02335f17067d59d90176c5618bb0e571c8cd2591f51043fbc05f0184db052e0f1c323b65be16783ee50acbf580c8931b8ceaa01d172da
|
data/.gitignore
CHANGED
data/ext/rbuv/extconf.rb
CHANGED
data/ext/rbuv/rbuv.c
CHANGED
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 "
|
12
|
+
#include "rbuv_debug.h"
|
10
13
|
|
11
|
-
#include "
|
12
|
-
#include "
|
13
|
-
#include "
|
14
|
-
#include "
|
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
|
-
#
|
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_ */
|
@@ -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 "
|
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
|
-
|
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
|
}
|
@@ -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, ®);
|
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,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
|
+
}
|