rev 0.1.4 → 0.2.0
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.
- data/CHANGES +102 -0
- data/README +5 -5
- data/Rakefile +70 -0
- data/examples/echo_server.rb +24 -0
- data/ext/http11_client/http11_parser.rl +173 -0
- data/ext/libev/Changes +40 -0
- data/ext/libev/LICENSE +25 -0
- data/ext/libev/README +130 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/update_ev_wrap +19 -0
- data/ext/rev/extconf.rb +24 -11
- data/ext/rev/rev.h +7 -0
- data/ext/rev/rev_buffer.c +17 -8
- data/ext/rev/rev_ext.c +5 -4
- data/ext/rev/rev_io_watcher.c +7 -6
- data/ext/rev/rev_loop.c +48 -6
- data/ext/rev/rev_ssl.c +255 -0
- data/ext/rev/rev_timer_watcher.c +3 -6
- data/ext/rev/rev_utils.c +108 -0
- data/ext/rev/rev_watcher.c +0 -3
- data/lib/rev.rb +2 -1
- data/lib/rev/async_watcher.rb +38 -0
- data/lib/rev/dns_resolver.rb +6 -8
- data/lib/rev/http_client.rb +35 -32
- data/lib/rev/io.rb +47 -43
- data/lib/rev/io_watcher.rb +0 -2
- data/lib/rev/listener.rb +0 -1
- data/lib/rev/loop.rb +11 -4
- data/lib/rev/server.rb +2 -4
- data/lib/rev/socket.rb +1 -2
- data/lib/rev/ssl.rb +184 -0
- data/lib/rev/timer_watcher.rb +0 -2
- data/lib/rev/watcher.rb +0 -2
- data/rev.gemspec +27 -0
- metadata +69 -61
- data/lib/http11_client.bundle +0 -0
- data/lib/rev_ext.bundle +0 -0
- data/spec/rev_spec.rb +0 -26
data/ext/rev/rev_ssl.c
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2008 Tony Arcieri
|
3
|
+
* Includes portions from the 'OpenSSL for Ruby' project
|
4
|
+
* Copyright (C) 2000-2002 GOTOU Yuuzou <gotoyuzo@notwork.org>
|
5
|
+
* Copyright (C) 2001-2002 Michal Rokos <m.rokos@sh.cvut.cz>
|
6
|
+
* Copyright (C) 2001-2007 Technorama Ltd. <oss-ruby@technorama.net>
|
7
|
+
* You may redistribute this under the terms of the Ruby license.
|
8
|
+
* See LICENSE for details
|
9
|
+
*/
|
10
|
+
|
11
|
+
#ifdef HAVE_OPENSSL_SSL_H
|
12
|
+
|
13
|
+
#include "ruby.h"
|
14
|
+
#include "rubyio.h"
|
15
|
+
|
16
|
+
#include <openssl/ssl.h>
|
17
|
+
|
18
|
+
static VALUE mOSSL = Qnil;
|
19
|
+
static VALUE eOSSLError = Qnil;
|
20
|
+
|
21
|
+
static VALUE mSSL = Qnil;
|
22
|
+
static VALUE cSSLSocket = Qnil;
|
23
|
+
static VALUE eSSLError = Qnil;
|
24
|
+
|
25
|
+
static VALUE mRev = Qnil;
|
26
|
+
static VALUE mRev_SSL = Qnil;
|
27
|
+
static VALUE cRev_SSL_IO = Qnil;
|
28
|
+
|
29
|
+
static VALUE eRev_SSL_IO_ReadAgain = Qnil;
|
30
|
+
static VALUE eRev_SSL_IO_WriteAgain = Qnil;
|
31
|
+
|
32
|
+
static VALUE Rev_SSL_IO_connect_nonblock(VALUE self);
|
33
|
+
static VALUE Rev_SSL_IO_accept_nonblock(VALUE self);
|
34
|
+
static VALUE Rev_SSL_IO_ssl_setup(VALUE self);
|
35
|
+
static VALUE Rev_SSL_IO_ssl_setup_check(VALUE dummy, VALUE error_info);
|
36
|
+
static VALUE Rev_SSL_IO_start_ssl(VALUE self, int (*func)(), const char *funcname);
|
37
|
+
|
38
|
+
static VALUE Rev_SSL_IO_read_nonblock(int argc, VALUE *argv, VALUE self);
|
39
|
+
static VALUE Rev_SSL_IO_write_nonblock(VALUE self, VALUE str);
|
40
|
+
|
41
|
+
void Init_rev_ssl()
|
42
|
+
{
|
43
|
+
rb_require("openssl");
|
44
|
+
|
45
|
+
mOSSL = rb_define_module("OpenSSL");
|
46
|
+
eOSSLError = rb_define_class_under(mOSSL, "OpenSSLError", rb_eStandardError);
|
47
|
+
|
48
|
+
mSSL = rb_define_module_under(mOSSL, "SSL");
|
49
|
+
cSSLSocket = rb_define_class_under(mSSL, "SSLSocket", rb_cObject);
|
50
|
+
eSSLError = rb_define_class_under(mSSL, "SSLError", eOSSLError);
|
51
|
+
|
52
|
+
mRev = rb_define_module("Rev");
|
53
|
+
mRev_SSL = rb_define_module_under(mRev, "SSL");
|
54
|
+
cRev_SSL_IO = rb_define_class_under(mRev_SSL, "IO", cSSLSocket);
|
55
|
+
|
56
|
+
eRev_SSL_IO_ReadAgain = rb_define_class_under(cRev_SSL_IO, "ReadAgain", rb_eStandardError);
|
57
|
+
eRev_SSL_IO_WriteAgain = rb_define_class_under(cRev_SSL_IO, "WriteAgain", rb_eStandardError);
|
58
|
+
|
59
|
+
rb_define_method(cRev_SSL_IO, "connect_nonblock", Rev_SSL_IO_connect_nonblock, 0);
|
60
|
+
rb_define_method(cRev_SSL_IO, "accept_nonblock", Rev_SSL_IO_accept_nonblock, 0);
|
61
|
+
|
62
|
+
rb_define_method(cRev_SSL_IO, "read_nonblock", Rev_SSL_IO_read_nonblock, -1);
|
63
|
+
rb_define_method(cRev_SSL_IO, "write_nonblock", Rev_SSL_IO_write_nonblock, 1);
|
64
|
+
}
|
65
|
+
|
66
|
+
static VALUE
|
67
|
+
Rev_SSL_IO_ssl_setup(VALUE self)
|
68
|
+
{
|
69
|
+
/*
|
70
|
+
* DANGER WILL ROBINSON! CRAZY HACKS AHEAD!
|
71
|
+
*
|
72
|
+
* Before we connect or accept we need to call the ossl_ssl_setup() function
|
73
|
+
* in ossl_ssl.c. For whatever reason this isn't called in
|
74
|
+
* SSLSocket#initialize but is instead called directly from #connect and
|
75
|
+
* #accept.
|
76
|
+
*
|
77
|
+
* To make things even more awesome, it's a static function, so we can't
|
78
|
+
* call it directly. However, we can call it indirectly...
|
79
|
+
*
|
80
|
+
* There's one other method within ossl_ssl.c which calls ossl_ssl_setup(),
|
81
|
+
* and that's #session=. I'm not sure why this calls it, but its author
|
82
|
+
* left this comment to help us figure out:
|
83
|
+
*
|
84
|
+
* "why is ossl_ssl_setup delayed?"
|
85
|
+
*
|
86
|
+
* Why indeed, guy... why indeed. Well, his function calls ossl_ssl_setup(),
|
87
|
+
* then typechecks its arguments, which means if we pass a bogus one it will
|
88
|
+
* happily setup SSL for us, then raise an exception. So we can catch
|
89
|
+
* that exception and be on our merry way.
|
90
|
+
*
|
91
|
+
* I don't even know what this method is supposed to do. It appears related
|
92
|
+
* to OpenSSL::SSL::Session, which is linked into the OpenSSL library but
|
93
|
+
* never initialized, probably because it's buggy. Nevertheless, the
|
94
|
+
* #session= method is still available to use for this hack. Awesome!
|
95
|
+
*/
|
96
|
+
rb_funcall(self, rb_intern("session="), 1, Qnil);
|
97
|
+
}
|
98
|
+
|
99
|
+
/* Ensure the error raised by calling #session= with a dummy argument is
|
100
|
+
* the one we were expecting */
|
101
|
+
static VALUE
|
102
|
+
Rev_SSL_IO_ssl_setup_check(VALUE dummy, VALUE err)
|
103
|
+
{
|
104
|
+
if(!rb_obj_is_kind_of(err, rb_eTypeError))
|
105
|
+
rb_raise(rb_eRuntimeError, "Rev::SSL not supported in this Ruby version, sorry");
|
106
|
+
|
107
|
+
return Qnil;
|
108
|
+
}
|
109
|
+
|
110
|
+
/*
|
111
|
+
* call-seq:
|
112
|
+
* ssl.connect => self
|
113
|
+
*/
|
114
|
+
static VALUE
|
115
|
+
Rev_SSL_IO_connect_nonblock(VALUE self)
|
116
|
+
{
|
117
|
+
rb_rescue(Rev_SSL_IO_ssl_setup, self, Rev_SSL_IO_ssl_setup_check, Qnil);
|
118
|
+
return Rev_SSL_IO_start_ssl(self, SSL_connect, "SSL_connect");
|
119
|
+
}
|
120
|
+
|
121
|
+
/*
|
122
|
+
* call-seq:
|
123
|
+
* ssl.accept => self
|
124
|
+
*/
|
125
|
+
static VALUE
|
126
|
+
Rev_SSL_IO_accept_nonblock(VALUE self)
|
127
|
+
{
|
128
|
+
rb_rescue(Rev_SSL_IO_ssl_setup, self, 0, 0);
|
129
|
+
return Rev_SSL_IO_start_ssl(self, SSL_accept, "SSL_accept");
|
130
|
+
}
|
131
|
+
|
132
|
+
static VALUE
|
133
|
+
Rev_SSL_IO_start_ssl(VALUE self, int (*func)(), const char *funcname)
|
134
|
+
{
|
135
|
+
SSL *ssl;
|
136
|
+
int ret, ret2;
|
137
|
+
|
138
|
+
Data_Get_Struct(self, SSL, ssl);
|
139
|
+
if(!ssl)
|
140
|
+
rb_raise(rb_eRuntimeError, "SSL never initialized");
|
141
|
+
|
142
|
+
if((ret = func(ssl)) <= 0) {
|
143
|
+
switch((ret2 = SSL_get_error(ssl, ret))) {
|
144
|
+
case SSL_ERROR_WANT_WRITE:
|
145
|
+
rb_raise(eRev_SSL_IO_WriteAgain, "write again");
|
146
|
+
case SSL_ERROR_WANT_READ:
|
147
|
+
rb_raise(eRev_SSL_IO_ReadAgain, "read again");
|
148
|
+
case SSL_ERROR_SYSCALL:
|
149
|
+
if (errno) rb_sys_fail(funcname);
|
150
|
+
rb_raise(eSSLError, "%s SYSCALL returned=%d errno=%d state=%s",
|
151
|
+
funcname, ret2, errno, SSL_state_string_long(ssl)
|
152
|
+
);
|
153
|
+
default:
|
154
|
+
rb_raise(eSSLError, "%s returned=%d errno=%d state=%s",
|
155
|
+
funcname, ret2, errno, SSL_state_string_long(ssl)
|
156
|
+
);
|
157
|
+
}
|
158
|
+
}
|
159
|
+
|
160
|
+
return self;
|
161
|
+
}
|
162
|
+
|
163
|
+
/*
|
164
|
+
* call-seq:
|
165
|
+
* ssl.read_nonblock(length) => string
|
166
|
+
* ssl.read_nonblock(length, buffer) => buffer
|
167
|
+
*
|
168
|
+
* === Parameters
|
169
|
+
* * +length+ is a positive integer.
|
170
|
+
* * +buffer+ is a string used to store the result.
|
171
|
+
*/
|
172
|
+
static VALUE
|
173
|
+
Rev_SSL_IO_read_nonblock(int argc, VALUE *argv, VALUE self)
|
174
|
+
{
|
175
|
+
SSL *ssl;
|
176
|
+
int ilen, nread = 0;
|
177
|
+
VALUE len, str;
|
178
|
+
|
179
|
+
rb_scan_args(argc, argv, "11", &len, &str);
|
180
|
+
ilen = NUM2INT(len);
|
181
|
+
|
182
|
+
if(NIL_P(str))
|
183
|
+
str = rb_str_new(0, ilen);
|
184
|
+
else {
|
185
|
+
StringValue(str);
|
186
|
+
rb_str_modify(str);
|
187
|
+
rb_str_resize(str, ilen);
|
188
|
+
}
|
189
|
+
|
190
|
+
if(ilen == 0) return str;
|
191
|
+
|
192
|
+
Data_Get_Struct(self, SSL, ssl);
|
193
|
+
|
194
|
+
if (ssl) {
|
195
|
+
nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
|
196
|
+
switch(SSL_get_error(ssl, nread)){
|
197
|
+
case SSL_ERROR_NONE:
|
198
|
+
goto end;
|
199
|
+
case SSL_ERROR_ZERO_RETURN:
|
200
|
+
rb_eof_error();
|
201
|
+
case SSL_ERROR_WANT_WRITE:
|
202
|
+
rb_raise(eRev_SSL_IO_WriteAgain, "write again");
|
203
|
+
case SSL_ERROR_WANT_READ:
|
204
|
+
rb_raise(eRev_SSL_IO_ReadAgain, "read again");
|
205
|
+
case SSL_ERROR_SYSCALL:
|
206
|
+
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
|
207
|
+
rb_sys_fail(0);
|
208
|
+
default:
|
209
|
+
rb_raise(eSSLError, "SSL_read:");
|
210
|
+
}
|
211
|
+
} else
|
212
|
+
rb_raise(rb_eRuntimeError, "SSL session is not started yet.");
|
213
|
+
|
214
|
+
end:
|
215
|
+
rb_str_set_len(str, nread);
|
216
|
+
OBJ_TAINT(str);
|
217
|
+
|
218
|
+
return str;
|
219
|
+
}
|
220
|
+
|
221
|
+
/*
|
222
|
+
* call-seq:
|
223
|
+
* ssl.write_nonblock(string) => integer
|
224
|
+
*/
|
225
|
+
static VALUE
|
226
|
+
Rev_SSL_IO_write_nonblock(VALUE self, VALUE str)
|
227
|
+
{
|
228
|
+
SSL *ssl;
|
229
|
+
int nwrite = 0;
|
230
|
+
|
231
|
+
StringValue(str);
|
232
|
+
Data_Get_Struct(self, SSL, ssl);
|
233
|
+
|
234
|
+
if (ssl) {
|
235
|
+
nwrite = SSL_write(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
|
236
|
+
switch(SSL_get_error(ssl, nwrite)){
|
237
|
+
case SSL_ERROR_NONE:
|
238
|
+
goto end;
|
239
|
+
case SSL_ERROR_WANT_WRITE:
|
240
|
+
rb_raise(eRev_SSL_IO_WriteAgain, "write again");
|
241
|
+
case SSL_ERROR_WANT_READ:
|
242
|
+
rb_raise(eRev_SSL_IO_ReadAgain, "read again");
|
243
|
+
case SSL_ERROR_SYSCALL:
|
244
|
+
if (errno) rb_sys_fail(0);
|
245
|
+
default:
|
246
|
+
rb_raise(eSSLError, "SSL_write:");
|
247
|
+
}
|
248
|
+
} else
|
249
|
+
rb_raise(rb_eRuntimeError, "SSL session is not started yet.");
|
250
|
+
|
251
|
+
end:
|
252
|
+
return INT2NUM(nwrite);
|
253
|
+
}
|
254
|
+
|
255
|
+
#endif
|
data/ext/rev/rev_timer_watcher.c
CHANGED
@@ -12,13 +12,11 @@
|
|
12
12
|
#include "rev.h"
|
13
13
|
#include "rev_watcher.h"
|
14
14
|
|
15
|
-
/* Module and object handles */
|
16
15
|
static VALUE mRev = Qnil;
|
17
16
|
static VALUE cRev_Watcher = Qnil;
|
18
17
|
static VALUE cRev_TimerWatcher = Qnil;
|
19
18
|
static VALUE cRev_Loop = Qnil;
|
20
19
|
|
21
|
-
/* Method implementations */
|
22
20
|
static VALUE Rev_TimerWatcher_initialize(int argc, VALUE *argv, VALUE self);
|
23
21
|
static VALUE Rev_TimerWatcher_attach(VALUE self, VALUE loop);
|
24
22
|
static VALUE Rev_TimerWatcher_detach(VALUE self);
|
@@ -27,7 +25,6 @@ static VALUE Rev_TimerWatcher_disable(VALUE self);
|
|
27
25
|
static VALUE Rev_TimerWatcher_reset(VALUE self);
|
28
26
|
static VALUE Rev_TimerWatcher_on_timer(VALUE self);
|
29
27
|
|
30
|
-
/* Callbacks */
|
31
28
|
static void Rev_TimerWatcher_libev_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents);
|
32
29
|
static void Rev_TimerWatcher_dispatch_callback(VALUE self, int revents);
|
33
30
|
|
@@ -79,8 +76,8 @@ static VALUE Rev_TimerWatcher_initialize(int argc, VALUE *argv, VALUE self)
|
|
79
76
|
ev_timer_init(
|
80
77
|
&watcher_data->event_types.ev_timer,
|
81
78
|
Rev_TimerWatcher_libev_callback,
|
82
|
-
|
83
|
-
repeating == Qtrue ?
|
79
|
+
NUM2DBL(interval),
|
80
|
+
repeating == Qtrue ? NUM2DBL(interval) : 0
|
84
81
|
);
|
85
82
|
watcher_data->event_types.ev_timer.data = (void *)self;
|
86
83
|
|
@@ -112,7 +109,7 @@ static VALUE Rev_TimerWatcher_attach(VALUE self, VALUE loop)
|
|
112
109
|
watcher_data->loop = loop;
|
113
110
|
|
114
111
|
/* Calibrate timeout to account for potential drift */
|
115
|
-
interval =
|
112
|
+
interval = NUM2DBL(rb_iv_get(self, "@interval"));
|
116
113
|
timeout = interval + ev_time() - ev_now(loop_data->ev_loop);
|
117
114
|
|
118
115
|
ev_timer_set(
|
data/ext/rev/rev_utils.c
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (C) 2007 Tony Arcieri
|
3
|
+
* You may redistribute this under the terms of the Ruby license.
|
4
|
+
* See LICENSE for details
|
5
|
+
*/
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
|
9
|
+
#include <sys/resource.h>
|
10
|
+
|
11
|
+
#ifdef HAVE_SYS_SYSCTL_H
|
12
|
+
#include <sys/param.h>
|
13
|
+
#include <sys/sysctl.h>
|
14
|
+
#endif
|
15
|
+
|
16
|
+
static VALUE mRev = Qnil;
|
17
|
+
static VALUE cRev_Utils = Qnil;
|
18
|
+
|
19
|
+
static VALUE Rev_Utils_ncpus(VALUE self);
|
20
|
+
static VALUE Rev_Utils_maxfds(VALUE self);
|
21
|
+
static VALUE Rev_Utils_setmaxfds(VALUE self, VALUE max);
|
22
|
+
|
23
|
+
/*
|
24
|
+
* Assorted utility routines
|
25
|
+
*/
|
26
|
+
void Init_rev_utils()
|
27
|
+
{
|
28
|
+
mRev = rb_define_module("Rev");
|
29
|
+
cRev_Utils = rb_define_module_under(mRev, "Utils");
|
30
|
+
|
31
|
+
rb_define_singleton_method(cRev_Utils, "ncpus", Rev_Utils_ncpus, 0);
|
32
|
+
rb_define_singleton_method(cRev_Utils, "maxfds", Rev_Utils_maxfds, 0);
|
33
|
+
rb_define_singleton_method(cRev_Utils, "maxfds=", Rev_Utils_setmaxfds, 1);
|
34
|
+
}
|
35
|
+
|
36
|
+
/**
|
37
|
+
* call-seq:
|
38
|
+
* Rev::Utils.ncpus -> Integer
|
39
|
+
*
|
40
|
+
* Return the number of CPUs in the present system
|
41
|
+
*/
|
42
|
+
static VALUE Rev_Utils_ncpus(VALUE self)
|
43
|
+
{
|
44
|
+
int ncpus = 0;
|
45
|
+
|
46
|
+
#ifdef HAVE_LINUX_PROCFS
|
47
|
+
#define HAVE_REV_UTILS_NCPUS
|
48
|
+
char buf[512];
|
49
|
+
FILE *cpuinfo;
|
50
|
+
|
51
|
+
if(!(cpuinfo = fopen("/proc/cpuinfo", "r")))
|
52
|
+
rb_sys_fail("fopen");
|
53
|
+
|
54
|
+
while(fgets(buf, 512, cpuinfo)) {
|
55
|
+
if(!strncmp(buf, "processor", 9))
|
56
|
+
ncpus++;
|
57
|
+
}
|
58
|
+
#endif
|
59
|
+
|
60
|
+
#ifdef HAVE_SYSCTLBYNAME
|
61
|
+
#define HAVE_REV_UTILS_NCPUS
|
62
|
+
size_t size = sizeof(int);
|
63
|
+
|
64
|
+
if(sysctlbyname("hw.ncpu", &ncpus, &size, NULL, 0))
|
65
|
+
return INT2NUM(1);
|
66
|
+
#endif
|
67
|
+
|
68
|
+
#ifndef HAVE_REV_UTILS_NCPUS
|
69
|
+
rb_raise(rb_eRuntimeError, "operation not supported");
|
70
|
+
#endif
|
71
|
+
|
72
|
+
return INT2NUM(ncpus);
|
73
|
+
}
|
74
|
+
|
75
|
+
/**
|
76
|
+
* call-seq:
|
77
|
+
* Rev::Utils.maxfds -> Integer
|
78
|
+
*
|
79
|
+
* Return the maximum number of files descriptors available to the process
|
80
|
+
*/
|
81
|
+
static VALUE Rev_Utils_maxfds(VALUE self)
|
82
|
+
{
|
83
|
+
struct rlimit rlim;
|
84
|
+
|
85
|
+
if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
|
86
|
+
rb_sys_fail("getrlimit");
|
87
|
+
|
88
|
+
return INT2NUM(rlim.rlim_cur);
|
89
|
+
}
|
90
|
+
|
91
|
+
/**
|
92
|
+
* call-seq:
|
93
|
+
* Rev::Utils.maxfds=(count) -> Integer
|
94
|
+
*
|
95
|
+
* Set the number of file descriptors available to the process. May require
|
96
|
+
* superuser privileges.
|
97
|
+
*/
|
98
|
+
static VALUE Rev_Utils_setmaxfds(VALUE self, VALUE max)
|
99
|
+
{
|
100
|
+
struct rlimit rlim;
|
101
|
+
|
102
|
+
rlim.rlim_cur = NUM2INT(max);
|
103
|
+
|
104
|
+
if(setrlimit(RLIMIT_NOFILE, &rlim) < 0)
|
105
|
+
rb_sys_fail("setrlimit");
|
106
|
+
|
107
|
+
return max;
|
108
|
+
}
|
data/ext/rev/rev_watcher.c
CHANGED
@@ -11,16 +11,13 @@
|
|
11
11
|
|
12
12
|
#include "rev.h"
|
13
13
|
|
14
|
-
/* Module and object handles */
|
15
14
|
static VALUE mRev = Qnil;
|
16
15
|
static VALUE cRev_Watcher = Qnil;
|
17
16
|
|
18
|
-
/* Data allocators and deallocators */
|
19
17
|
static VALUE Rev_Watcher_allocate(VALUE klass);
|
20
18
|
static void Rev_Watcher_mark(struct Rev_Watcher *watcher);
|
21
19
|
static void Rev_Watcher_free(struct Rev_Watcher *watcher);
|
22
20
|
|
23
|
-
/* Method implementations */
|
24
21
|
static VALUE Rev_Watcher_initialize(VALUE self);
|
25
22
|
static VALUE Rev_Watcher_attach(VALUE self, VALUE loop);
|
26
23
|
static VALUE Rev_Watcher_detach(VALUE self);
|
data/lib/rev.rb
CHANGED
@@ -9,6 +9,7 @@ require File.dirname(__FILE__) + '/rev/loop'
|
|
9
9
|
require File.dirname(__FILE__) + '/rev/watcher'
|
10
10
|
require File.dirname(__FILE__) + '/rev/io_watcher'
|
11
11
|
require File.dirname(__FILE__) + '/rev/timer_watcher'
|
12
|
+
require File.dirname(__FILE__) + '/rev/async_watcher'
|
12
13
|
require File.dirname(__FILE__) + '/rev/listener'
|
13
14
|
require File.dirname(__FILE__) + '/rev/io'
|
14
15
|
require File.dirname(__FILE__) + '/rev/dns_resolver'
|
@@ -17,6 +18,6 @@ require File.dirname(__FILE__) + '/rev/server'
|
|
17
18
|
require File.dirname(__FILE__) + '/rev/http_client'
|
18
19
|
|
19
20
|
module Rev
|
20
|
-
Rev::VERSION = '0.
|
21
|
+
Rev::VERSION = '0.2.0' unless defined? Rev::VERSION
|
21
22
|
def self.version() VERSION end
|
22
23
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (C)2007 Tony Arcieri
|
3
|
+
# You can redistribute this under the terms of the Ruby license
|
4
|
+
# See file LICENSE for details
|
5
|
+
#++
|
6
|
+
|
7
|
+
module Rev
|
8
|
+
# The AsyncWatcher lets you signal another thread to wake up. Its
|
9
|
+
# intended use is notifying another thread of events.
|
10
|
+
class AsyncWatcher < IOWatcher
|
11
|
+
def initialize
|
12
|
+
@reader, @writer = ::IO.pipe
|
13
|
+
super(@reader)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Signal the async watcher. This call is thread safe.
|
17
|
+
def signal
|
18
|
+
# Write a byte to the pipe. What we write is meaningless, it
|
19
|
+
# merely signals an event has occurred for each byte written.
|
20
|
+
@writer.write "\0"
|
21
|
+
end
|
22
|
+
|
23
|
+
# Called whenever a signal is received
|
24
|
+
def on_signal; end
|
25
|
+
event_callback :on_signal
|
26
|
+
|
27
|
+
#########
|
28
|
+
protected
|
29
|
+
#########
|
30
|
+
|
31
|
+
def on_readable
|
32
|
+
# Read a byte from the pipe. This clears readability, unless
|
33
|
+
# another signal is pending
|
34
|
+
@reader.read 1
|
35
|
+
on_signal
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|