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 +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
|
+
}
|