cool.io 1.0.0 → 1.9.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.
- checksums.yaml +7 -0
- data/.github/workflows/test.yaml +54 -0
- data/.gitignore +30 -0
- data/.rspec +3 -0
- data/{CHANGES → CHANGES.md} +175 -79
- data/{README.markdown → README.md} +43 -49
- data/Rakefile +44 -69
- data/appveyor.yml +18 -0
- data/cool.io.gemspec +18 -131
- data/examples/callbacked_echo_server.rb +24 -0
- data/ext/cool.io/buffer.c +781 -0
- data/ext/cool.io/cool.io.h +13 -0
- data/ext/cool.io/cool.io_ext.c +1 -0
- data/ext/cool.io/ev_wrap.h +4 -2
- data/ext/cool.io/extconf.rb +27 -16
- data/ext/cool.io/iowatcher.c +17 -8
- data/ext/cool.io/loop.c +36 -84
- data/ext/cool.io/stat_watcher.c +103 -25
- data/ext/cool.io/timer_watcher.c +3 -3
- data/ext/cool.io/utils.c +5 -0
- data/ext/cool.io/watcher.h +1 -1
- data/ext/libev/Changes +152 -3
- data/ext/libev/LICENSE +2 -1
- data/ext/libev/README +8 -8
- data/ext/libev/ev.c +1719 -348
- data/ext/libev/ev.h +146 -118
- data/ext/libev/ev_epoll.c +71 -20
- data/ext/libev/ev_kqueue.c +36 -16
- data/ext/libev/ev_poll.c +14 -11
- data/ext/libev/ev_port.c +43 -18
- data/ext/libev/ev_select.c +82 -25
- data/ext/libev/ev_vars.h +28 -21
- data/ext/libev/ev_win32.c +19 -10
- data/ext/libev/ev_wrap.h +166 -152
- data/ext/libev/test_libev_win32.c +1 -1
- data/gems.rb +9 -0
- data/lib/cool.io/async_watcher.rb +1 -1
- data/lib/cool.io/custom_require.rb +9 -0
- data/lib/cool.io/dns_resolver.rb +30 -22
- data/lib/cool.io/dsl.rb +32 -28
- data/lib/cool.io/io.rb +55 -35
- data/lib/cool.io/iowatcher.rb +1 -1
- data/lib/cool.io/listener.rb +35 -17
- data/lib/cool.io/loop.rb +17 -25
- data/lib/cool.io/meta.rb +6 -5
- data/lib/cool.io/server.rb +5 -4
- data/lib/cool.io/socket.rb +41 -30
- data/lib/cool.io/timer_watcher.rb +1 -1
- data/lib/cool.io/version.rb +7 -0
- data/lib/cool.io.rb +11 -10
- data/lib/coolio.rb +1 -1
- data/libev_ruby_gil.diff +175 -0
- data/libev_win_select.diff +130 -0
- data/spec/async_watcher_spec.rb +5 -5
- data/spec/dns_spec.rb +27 -8
- data/spec/iobuffer_spec.rb +147 -0
- data/spec/spec_helper.rb +15 -1
- data/spec/stat_watcher_spec.rb +81 -0
- data/spec/tcp_server_spec.rb +225 -0
- data/spec/tcp_socket_spec.rb +185 -0
- data/spec/timer_watcher_spec.rb +23 -19
- data/spec/udp_socket_spec.rb +58 -0
- data/spec/unix_listener_spec.rb +8 -8
- data/spec/unix_server_spec.rb +10 -8
- metadata +109 -112
- data/VERSION +0 -1
- data/examples/httpclient.rb +0 -38
- data/ext/http11_client/.gitignore +0 -5
- data/ext/http11_client/LICENSE +0 -31
- data/ext/http11_client/ext_help.h +0 -14
- data/ext/http11_client/extconf.rb +0 -6
- data/ext/http11_client/http11_client.c +0 -300
- data/ext/http11_client/http11_parser.c +0 -403
- data/ext/http11_client/http11_parser.h +0 -48
- data/ext/http11_client/http11_parser.rl +0 -173
- data/lib/cool.io/eventmachine.rb +0 -234
- data/lib/cool.io/http_client.rb +0 -419
- data/lib/rev.rb +0 -4
- data/spec/possible_tests/schedules_other_threads.rb +0 -48
- data/spec/possible_tests/test_on_resolve_failed.rb +0 -9
- data/spec/possible_tests/test_resolves.rb +0 -27
- data/spec/possible_tests/test_write_during_resolve.rb +0 -27
- data/spec/possible_tests/works_straight.rb +0 -71
data/ext/cool.io/cool.io.h
CHANGED
|
@@ -8,7 +8,11 @@
|
|
|
8
8
|
#define COOLIO_H
|
|
9
9
|
|
|
10
10
|
#include "ruby.h"
|
|
11
|
+
#if defined(HAVE_RUBY_IO_H)
|
|
12
|
+
#include "ruby/io.h"
|
|
13
|
+
#else
|
|
11
14
|
#include "rubyio.h"
|
|
15
|
+
#endif
|
|
12
16
|
|
|
13
17
|
#ifdef GetReadFile
|
|
14
18
|
#define FPTR_TO_FD(fptr) (fileno(GetReadFile(fptr)))
|
|
@@ -32,6 +36,7 @@ struct Coolio_Event
|
|
|
32
36
|
struct Coolio_Loop
|
|
33
37
|
{
|
|
34
38
|
struct ev_loop *ev_loop;
|
|
39
|
+
struct ev_timer timer; /* for timeouts */
|
|
35
40
|
|
|
36
41
|
int running;
|
|
37
42
|
int events_received;
|
|
@@ -55,4 +60,12 @@ struct Coolio_Watcher
|
|
|
55
60
|
|
|
56
61
|
void Coolio_Loop_process_event(VALUE watcher, int revents);
|
|
57
62
|
|
|
63
|
+
void Init_coolio_buffer();
|
|
64
|
+
void Init_coolio_loop();
|
|
65
|
+
void Init_coolio_watcher();
|
|
66
|
+
void Init_coolio_iowatcher();
|
|
67
|
+
void Init_coolio_timer_watcher();
|
|
68
|
+
void Init_coolio_stat_watcher();
|
|
69
|
+
void Init_coolio_utils();
|
|
70
|
+
|
|
58
71
|
#endif
|
data/ext/cool.io/cool.io_ext.c
CHANGED
data/ext/cool.io/ev_wrap.h
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#define EV_STANDALONE /* keeps ev from requiring config.h */
|
|
2
|
+
|
|
2
3
|
#ifdef _WIN32
|
|
3
|
-
#
|
|
4
|
-
#
|
|
4
|
+
#define EV_SELECT_IS_WINSOCKET 1 /* configure libev for windows select */
|
|
5
|
+
#define EV_USE_MONOTONIC 0
|
|
6
|
+
#define EV_USE_REALTIME 0
|
|
5
7
|
#endif
|
|
6
8
|
|
|
7
9
|
#include "../libev/ev.h"
|
data/ext/cool.io/extconf.rb
CHANGED
|
@@ -4,20 +4,25 @@ libs = []
|
|
|
4
4
|
|
|
5
5
|
$defs << "-DRUBY_VERSION_CODE=#{RUBY_VERSION.gsub(/\D/, '')}"
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
have_func('rb_io_descriptor')
|
|
8
|
+
have_func('rb_thread_blocking_region')
|
|
9
|
+
have_func('rb_thread_call_without_gvl')
|
|
10
|
+
have_func('rb_thread_alone')
|
|
11
|
+
have_func('rb_str_set_len')
|
|
12
|
+
have_library('rt', 'clock_gettime')
|
|
13
|
+
|
|
14
|
+
have_func("rb_io_descriptor")
|
|
15
|
+
have_library("c", "main")
|
|
16
|
+
if have_macro("HAVE_RB_IO_T", "ruby/io.h")
|
|
17
|
+
have_struct_member("rb_io_t", "fd", "ruby/io.h")
|
|
9
18
|
end
|
|
10
19
|
|
|
11
|
-
if
|
|
12
|
-
$defs << '-
|
|
20
|
+
if have_header('ruby/io.h')
|
|
21
|
+
$defs << '-DHAVE_RUBY_IO_H'
|
|
13
22
|
end
|
|
14
23
|
|
|
15
|
-
if
|
|
16
|
-
$defs << '-
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
if have_library('rt', 'clock_gettime')
|
|
20
|
-
libs << "-lrt"
|
|
24
|
+
if have_header('ruby/thread.h')
|
|
25
|
+
$defs << '-DHAVE_RUBY_THREAD_H'
|
|
21
26
|
end
|
|
22
27
|
|
|
23
28
|
if have_header('sys/select.h')
|
|
@@ -40,9 +45,7 @@ if have_header('port.h')
|
|
|
40
45
|
$defs << '-DEV_USE_PORT'
|
|
41
46
|
end
|
|
42
47
|
|
|
43
|
-
|
|
44
|
-
$defs << '-DHAVE_SYS_RESOURCE_H'
|
|
45
|
-
end
|
|
48
|
+
have_header('sys/resource.h')
|
|
46
49
|
|
|
47
50
|
# ncpu detection specifics
|
|
48
51
|
case RUBY_PLATFORM
|
|
@@ -54,16 +57,24 @@ else
|
|
|
54
57
|
end
|
|
55
58
|
end
|
|
56
59
|
|
|
60
|
+
if RUBY_PLATFORM =~ /solaris/
|
|
61
|
+
# libev/ev.c requires NSIG which is undefined if _XOPEN_SOURCE is defined
|
|
62
|
+
$defs << '-D__EXTENSIONS__'
|
|
63
|
+
end
|
|
64
|
+
|
|
57
65
|
$LIBS << ' ' << libs.join(' ')
|
|
58
66
|
|
|
59
67
|
dir_config('cool.io_ext')
|
|
60
68
|
create_makefile('cool.io_ext')
|
|
61
69
|
|
|
62
70
|
# win32 needs to link in "just the right order" for some reason or ioctlsocket will be mapped to an [inverted] ruby specific version. See libev mailing list for (not so helpful discussion--true cause I'm not sure, but this overcomes the symptom)
|
|
63
|
-
if RUBY_PLATFORM =~ /mingw|
|
|
71
|
+
if RUBY_PLATFORM =~ /mingw|mswin/
|
|
64
72
|
makefile_contents = File.read 'Makefile'
|
|
65
73
|
|
|
66
|
-
|
|
74
|
+
# "Init_cool could not be found" when loading cool.io.so.
|
|
75
|
+
# I'm not sure why this is needed. But this line causes "1114 A dynamic link library (DLL) initialization routine failed." So I commented out this line.
|
|
76
|
+
#makefile_contents.gsub! 'DLDFLAGS = ', 'DLDFLAGS = -export-all '
|
|
77
|
+
|
|
78
|
+
makefile_contents.gsub! /LIBS = (.*) (\S*ws2_32\S*)/i, 'LIBS = \\2 \\1'
|
|
67
79
|
File.open('Makefile', 'w') { |f| f.write makefile_contents }
|
|
68
80
|
end
|
|
69
|
-
|
data/ext/cool.io/iowatcher.c
CHANGED
|
@@ -5,7 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
#include "ruby.h"
|
|
8
|
+
#if defined(HAVE_RUBY_IO_H)
|
|
9
|
+
#include "ruby/io.h"
|
|
10
|
+
#else
|
|
8
11
|
#include "rubyio.h"
|
|
12
|
+
#endif
|
|
9
13
|
|
|
10
14
|
#include "ev_wrap.h"
|
|
11
15
|
|
|
@@ -61,11 +65,6 @@ static VALUE Coolio_IOWatcher_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
61
65
|
char *flags_str;
|
|
62
66
|
int events;
|
|
63
67
|
struct Coolio_Watcher *watcher_data;
|
|
64
|
-
#if HAVE_RB_IO_T
|
|
65
|
-
rb_io_t *fptr;
|
|
66
|
-
#else
|
|
67
|
-
OpenFile *fptr;
|
|
68
|
-
#endif
|
|
69
68
|
|
|
70
69
|
rb_scan_args(argc, argv, "11", &io, &flags);
|
|
71
70
|
|
|
@@ -84,10 +83,20 @@ static VALUE Coolio_IOWatcher_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
84
83
|
rb_raise(rb_eArgError, "invalid event type: '%s' (must be 'r', 'w', or 'rw')", flags_str);
|
|
85
84
|
|
|
86
85
|
Data_Get_Struct(self, struct Coolio_Watcher, watcher_data);
|
|
87
|
-
|
|
86
|
+
io = rb_convert_type(io, T_FILE, "IO", "to_io");
|
|
88
87
|
|
|
89
88
|
watcher_data->dispatch_callback = Coolio_IOWatcher_dispatch_callback;
|
|
89
|
+
#ifdef HAVE_RB_IO_DESCRIPTOR
|
|
90
|
+
ev_io_init(&watcher_data->event_types.ev_io, Coolio_IOWatcher_libev_callback, rb_io_descriptor(io), events);
|
|
91
|
+
#else
|
|
92
|
+
#if defined(HAVE_RB_IO_T)
|
|
93
|
+
rb_io_t *fptr;
|
|
94
|
+
#else
|
|
95
|
+
OpenFile *fptr;
|
|
96
|
+
#endif
|
|
97
|
+
GetOpenFile(io, fptr);
|
|
90
98
|
ev_io_init(&watcher_data->event_types.ev_io, Coolio_IOWatcher_libev_callback, FPTR_TO_FD(fptr), events);
|
|
99
|
+
#endif
|
|
91
100
|
watcher_data->event_types.ev_io.data = (void *)self;
|
|
92
101
|
|
|
93
102
|
return Qnil;
|
|
@@ -181,9 +190,9 @@ static void Coolio_IOWatcher_libev_callback(struct ev_loop *ev_loop, struct ev_i
|
|
|
181
190
|
static void Coolio_IOWatcher_dispatch_callback(VALUE self, int revents)
|
|
182
191
|
{
|
|
183
192
|
if(revents & EV_READ)
|
|
184
|
-
rb_funcall(self, rb_intern("on_readable"), 0
|
|
193
|
+
rb_funcall(self, rb_intern("on_readable"), 0);
|
|
185
194
|
else if(revents & EV_WRITE)
|
|
186
|
-
rb_funcall(self, rb_intern("on_writable"), 0
|
|
195
|
+
rb_funcall(self, rb_intern("on_writable"), 0);
|
|
187
196
|
else
|
|
188
197
|
rb_raise(rb_eRuntimeError, "unknown revents value for ev_io: %d", revents);
|
|
189
198
|
}
|
data/ext/cool.io/loop.c
CHANGED
|
@@ -6,19 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
#include <assert.h>
|
|
8
8
|
#include "ruby.h"
|
|
9
|
-
#include "rubysig.h"
|
|
10
9
|
#include "ev_wrap.h"
|
|
11
10
|
|
|
12
11
|
#include "cool.io.h"
|
|
13
12
|
|
|
14
|
-
#if defined(HAVE_RB_THREAD_BLOCKING_REGION)
|
|
15
|
-
# define Coolio_Loop_may_block_safely() (1)
|
|
16
|
-
#elif defined(HAVE_RB_THREAD_ALONE)
|
|
17
|
-
# define Coolio_Loop_may_block_safely() (rb_thread_alone())
|
|
18
|
-
#else /* just in case Ruby changes: */
|
|
19
|
-
# define Coolio_Loop_may_block_safely() (0)
|
|
20
|
-
#endif
|
|
21
|
-
|
|
22
13
|
static VALUE mCoolio = Qnil;
|
|
23
14
|
static VALUE cCoolio_Loop = Qnil;
|
|
24
15
|
|
|
@@ -26,12 +17,11 @@ static VALUE Coolio_Loop_allocate(VALUE klass);
|
|
|
26
17
|
static void Coolio_Loop_mark(struct Coolio_Loop *loop);
|
|
27
18
|
static void Coolio_Loop_free(struct Coolio_Loop *loop);
|
|
28
19
|
|
|
29
|
-
static VALUE Coolio_Loop_initialize(VALUE self);
|
|
30
20
|
static VALUE Coolio_Loop_ev_loop_new(VALUE self, VALUE flags);
|
|
31
|
-
static VALUE Coolio_Loop_run_once(VALUE self);
|
|
21
|
+
static VALUE Coolio_Loop_run_once(int argc, VALUE *argv, VALUE self);
|
|
32
22
|
static VALUE Coolio_Loop_run_nonblock(VALUE self);
|
|
33
23
|
|
|
34
|
-
static void
|
|
24
|
+
static void Coolio_Loop_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents);
|
|
35
25
|
static void Coolio_Loop_dispatch_events(struct Coolio_Loop *loop_data);
|
|
36
26
|
|
|
37
27
|
#define DEFAULT_EVENTBUF_SIZE 32
|
|
@@ -51,10 +41,9 @@ void Init_coolio_loop()
|
|
|
51
41
|
mCoolio = rb_define_module("Coolio");
|
|
52
42
|
cCoolio_Loop = rb_define_class_under(mCoolio, "Loop", rb_cObject);
|
|
53
43
|
rb_define_alloc_func(cCoolio_Loop, Coolio_Loop_allocate);
|
|
54
|
-
|
|
55
|
-
rb_define_method(cCoolio_Loop, "initialize", Coolio_Loop_initialize, 0);
|
|
44
|
+
|
|
56
45
|
rb_define_private_method(cCoolio_Loop, "ev_loop_new", Coolio_Loop_ev_loop_new, 1);
|
|
57
|
-
rb_define_method(cCoolio_Loop, "run_once", Coolio_Loop_run_once,
|
|
46
|
+
rb_define_method(cCoolio_Loop, "run_once", Coolio_Loop_run_once, -1);
|
|
58
47
|
rb_define_method(cCoolio_Loop, "run_nonblock", Coolio_Loop_run_nonblock, 0);
|
|
59
48
|
}
|
|
60
49
|
|
|
@@ -63,6 +52,7 @@ static VALUE Coolio_Loop_allocate(VALUE klass)
|
|
|
63
52
|
struct Coolio_Loop *loop = (struct Coolio_Loop *)xmalloc(sizeof(struct Coolio_Loop));
|
|
64
53
|
|
|
65
54
|
loop->ev_loop = 0;
|
|
55
|
+
ev_init(&loop->timer, Coolio_Loop_timeout_callback);
|
|
66
56
|
loop->running = 0;
|
|
67
57
|
loop->events_received = 0;
|
|
68
58
|
loop->eventbuf_size = DEFAULT_EVENTBUF_SIZE;
|
|
@@ -86,11 +76,6 @@ static void Coolio_Loop_free(struct Coolio_Loop *loop)
|
|
|
86
76
|
xfree(loop);
|
|
87
77
|
}
|
|
88
78
|
|
|
89
|
-
static VALUE Coolio_Loop_initialize(VALUE self)
|
|
90
|
-
{
|
|
91
|
-
Coolio_Loop_ev_loop_new(self, INT2NUM(0));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
79
|
/* Wrapper for populating a Coolio_Loop struct with a new event loop */
|
|
95
80
|
static VALUE Coolio_Loop_ev_loop_new(VALUE self, VALUE flags)
|
|
96
81
|
{
|
|
@@ -174,90 +159,57 @@ void Coolio_Loop_process_event(VALUE watcher, int revents)
|
|
|
174
159
|
loop_data->events_received++;
|
|
175
160
|
}
|
|
176
161
|
|
|
162
|
+
/* Called whenever a timeout fires on the event loop */
|
|
163
|
+
static void Coolio_Loop_timeout_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents)
|
|
164
|
+
{
|
|
165
|
+
/* We don't actually need to do anything here, the mere firing of the
|
|
166
|
+
timer is sufficient to interrupt the selector. However, libev still wants a callback */
|
|
167
|
+
}
|
|
168
|
+
|
|
177
169
|
/**
|
|
178
170
|
* call-seq:
|
|
179
171
|
* Coolio::Loop.run_once -> nil
|
|
180
172
|
*
|
|
181
173
|
* Run the Coolio::Loop once, blocking until events are received.
|
|
182
174
|
*/
|
|
183
|
-
static VALUE Coolio_Loop_run_once(VALUE self)
|
|
175
|
+
static VALUE Coolio_Loop_run_once(int argc, VALUE *argv, VALUE self)
|
|
184
176
|
{
|
|
177
|
+
VALUE timeout;
|
|
185
178
|
VALUE nevents;
|
|
179
|
+
struct Coolio_Loop *loop_data;
|
|
186
180
|
|
|
187
|
-
|
|
188
|
-
struct Coolio_Loop *loop_data;
|
|
189
|
-
|
|
190
|
-
Data_Get_Struct(self, struct Coolio_Loop, loop_data);
|
|
181
|
+
rb_scan_args(argc, argv, "01", &timeout);
|
|
191
182
|
|
|
192
|
-
|
|
183
|
+
if (timeout != Qnil && NUM2DBL(timeout) < 0) {
|
|
184
|
+
rb_raise(rb_eArgError, "time interval must be positive");
|
|
185
|
+
}
|
|
193
186
|
|
|
194
|
-
|
|
195
|
-
Coolio_Loop_dispatch_events(loop_data);
|
|
187
|
+
Data_Get_Struct(self, struct Coolio_Loop, loop_data);
|
|
196
188
|
|
|
197
|
-
|
|
198
|
-
loop_data->events_received = 0;
|
|
189
|
+
assert(loop_data->ev_loop && !loop_data->events_received);
|
|
199
190
|
|
|
191
|
+
/* Implement the optional timeout (if any) as a ev_timer */
|
|
192
|
+
/* Using the technique written at
|
|
193
|
+
http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_timer_code_relative_and_opti,
|
|
194
|
+
the timer is not stopped/started everytime when timeout is specified, instead,
|
|
195
|
+
the timer is stopped when timeout is not specified. */
|
|
196
|
+
if (timeout != Qnil) {
|
|
197
|
+
/* It seems libev is not a fan of timers being zero, so fudge a little */
|
|
198
|
+
loop_data->timer.repeat = NUM2DBL(timeout) + 0.0001;
|
|
199
|
+
ev_timer_again(loop_data->ev_loop, &loop_data->timer);
|
|
200
200
|
} else {
|
|
201
|
-
|
|
202
|
-
rb_thread_schedule();
|
|
201
|
+
ev_timer_stop(loop_data->ev_loop, &loop_data->timer);
|
|
203
202
|
}
|
|
204
203
|
|
|
205
|
-
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/* Ruby 1.9 supports blocking system calls through rb_thread_blocking_region() */
|
|
209
|
-
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
|
210
|
-
#define HAVE_EV_LOOP_ONESHOT
|
|
211
|
-
static VALUE Coolio_Loop_ev_loop_oneshot_blocking(void *ptr)
|
|
212
|
-
{
|
|
213
|
-
/* The libev loop has now escaped through the Global VM Lock unscathed! */
|
|
214
|
-
struct Coolio_Loop *loop_data = (struct Coolio_Loop *)ptr;
|
|
215
|
-
|
|
204
|
+
/* libev is patched to release the GIL when it makes its system call */
|
|
216
205
|
RUN_LOOP(loop_data, EVLOOP_ONESHOT);
|
|
217
|
-
|
|
218
|
-
return Qnil;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
static void Coolio_Loop_ev_loop_oneshot(struct Coolio_Loop *loop_data)
|
|
222
|
-
{
|
|
223
|
-
/* Use Ruby 1.9's rb_thread_blocking_region call to make a blocking system call */
|
|
224
|
-
rb_thread_blocking_region(Coolio_Loop_ev_loop_oneshot_blocking, loop_data, RUBY_UBF_IO, 0);
|
|
225
|
-
}
|
|
226
|
-
#endif
|
|
227
|
-
|
|
228
|
-
/* Ruby 1.8 requires us to periodically run the event loop then defer back to
|
|
229
|
-
* the green threads scheduler */
|
|
230
|
-
#ifndef HAVE_EV_LOOP_ONESHOT
|
|
231
|
-
#define BLOCKING_INTERVAL 0.01 /* Block for 10ms at a time */
|
|
232
|
-
|
|
233
|
-
/* Stub for scheduler's ev_timer callback */
|
|
234
|
-
static void timer_callback(struct ev_loop *ev_loop, struct ev_timer *timer, int revents)
|
|
235
|
-
{
|
|
236
|
-
ev_timer_again (ev_loop, timer);
|
|
237
|
-
}
|
|
238
206
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
struct ev_timer timer;
|
|
243
|
-
struct timeval tv;
|
|
244
|
-
|
|
245
|
-
/* Set up an ev_timer to unblock the loop every 10ms */
|
|
246
|
-
ev_timer_init(&timer, timer_callback, BLOCKING_INTERVAL, BLOCKING_INTERVAL);
|
|
247
|
-
ev_timer_start(loop_data->ev_loop, &timer);
|
|
248
|
-
|
|
249
|
-
/* Loop until we receive events */
|
|
250
|
-
while(!loop_data->events_received) {
|
|
251
|
-
TRAP_BEG;
|
|
252
|
-
RUN_LOOP(loop_data, EVLOOP_ONESHOT);
|
|
253
|
-
TRAP_END;
|
|
254
|
-
|
|
255
|
-
rb_thread_schedule();
|
|
256
|
-
}
|
|
207
|
+
Coolio_Loop_dispatch_events(loop_data);
|
|
208
|
+
nevents = INT2NUM(loop_data->events_received);
|
|
209
|
+
loop_data->events_received = 0;
|
|
257
210
|
|
|
258
|
-
|
|
211
|
+
return nevents;
|
|
259
212
|
}
|
|
260
|
-
#endif
|
|
261
213
|
|
|
262
214
|
/**
|
|
263
215
|
* call-seq:
|
data/ext/cool.io/stat_watcher.c
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
static VALUE mCoolio = Qnil;
|
|
14
14
|
static VALUE cCoolio_Watcher = Qnil;
|
|
15
15
|
static VALUE cCoolio_StatWatcher = Qnil;
|
|
16
|
+
static VALUE cCoolio_StatInfo = Qnil;
|
|
16
17
|
static VALUE cCoolio_Loop = Qnil;
|
|
17
18
|
|
|
18
19
|
static VALUE Coolio_StatWatcher_initialize(int argc, VALUE *argv, VALUE self);
|
|
@@ -20,9 +21,11 @@ static VALUE Coolio_StatWatcher_attach(VALUE self, VALUE loop);
|
|
|
20
21
|
static VALUE Coolio_StatWatcher_detach(VALUE self);
|
|
21
22
|
static VALUE Coolio_StatWatcher_enable(VALUE self);
|
|
22
23
|
static VALUE Coolio_StatWatcher_disable(VALUE self);
|
|
23
|
-
static VALUE Coolio_StatWatcher_on_change(VALUE self);
|
|
24
|
+
static VALUE Coolio_StatWatcher_on_change(VALUE self, VALUE previous, VALUE current);
|
|
24
25
|
static VALUE Coolio_StatWatcher_path(VALUE self);
|
|
25
26
|
|
|
27
|
+
static VALUE Coolio_StatInfo_build(ev_statdata *statdata_struct);
|
|
28
|
+
|
|
26
29
|
static void Coolio_StatWatcher_libev_callback(struct ev_loop *ev_loop, struct ev_stat *stat, int revents);
|
|
27
30
|
static void Coolio_StatWatcher_dispatch_callback(VALUE self, int revents);
|
|
28
31
|
|
|
@@ -30,12 +33,27 @@ static void Coolio_StatWatcher_dispatch_callback(VALUE self, int revents);
|
|
|
30
33
|
* Coolio::StatWatcher lets you create either one-shot or periodic stats which
|
|
31
34
|
* run within Coolio's event loop. It's useful for creating timeouts or
|
|
32
35
|
* events which fire periodically.
|
|
33
|
-
|
|
36
|
+
**/
|
|
34
37
|
void Init_coolio_stat_watcher()
|
|
35
|
-
{
|
|
38
|
+
{
|
|
36
39
|
mCoolio = rb_define_module("Coolio");
|
|
37
40
|
cCoolio_Watcher = rb_define_class_under(mCoolio, "Watcher", rb_cObject);
|
|
38
41
|
cCoolio_StatWatcher = rb_define_class_under(mCoolio, "StatWatcher", cCoolio_Watcher);
|
|
42
|
+
cCoolio_StatInfo = rb_struct_define("StatInfo",
|
|
43
|
+
"mtime",
|
|
44
|
+
"ctime",
|
|
45
|
+
"atime",
|
|
46
|
+
"dev",
|
|
47
|
+
"ino",
|
|
48
|
+
"mode",
|
|
49
|
+
"nlink",
|
|
50
|
+
"uid",
|
|
51
|
+
"guid",
|
|
52
|
+
"rdev",
|
|
53
|
+
"size",
|
|
54
|
+
"blksize",
|
|
55
|
+
"blocks",
|
|
56
|
+
NULL);
|
|
39
57
|
cCoolio_Loop = rb_define_class_under(mCoolio, "Loop", rb_cObject);
|
|
40
58
|
|
|
41
59
|
rb_define_method(cCoolio_StatWatcher, "initialize", Coolio_StatWatcher_initialize, -1);
|
|
@@ -43,14 +61,14 @@ void Init_coolio_stat_watcher()
|
|
|
43
61
|
rb_define_method(cCoolio_StatWatcher, "detach", Coolio_StatWatcher_detach, 0);
|
|
44
62
|
rb_define_method(cCoolio_StatWatcher, "enable", Coolio_StatWatcher_enable, 0);
|
|
45
63
|
rb_define_method(cCoolio_StatWatcher, "disable", Coolio_StatWatcher_disable, 0);
|
|
46
|
-
rb_define_method(cCoolio_StatWatcher, "on_change", Coolio_StatWatcher_on_change,
|
|
64
|
+
rb_define_method(cCoolio_StatWatcher, "on_change", Coolio_StatWatcher_on_change, 2);
|
|
47
65
|
rb_define_method(cCoolio_StatWatcher, "path", Coolio_StatWatcher_path, 0);
|
|
48
66
|
}
|
|
49
67
|
|
|
50
68
|
/**
|
|
51
69
|
* call-seq:
|
|
52
70
|
* Coolio::StatWatcher.initialize(path, interval = 0) -> Coolio::StatWatcher
|
|
53
|
-
*
|
|
71
|
+
*
|
|
54
72
|
* Create a new Coolio::StatWatcher for the given path. This will monitor the
|
|
55
73
|
* given path for changes at the filesystem level. The interval argument
|
|
56
74
|
* specified how often in seconds the path should be polled for changes.
|
|
@@ -75,11 +93,11 @@ static VALUE Coolio_StatWatcher_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
75
93
|
|
|
76
94
|
watcher_data->dispatch_callback = Coolio_StatWatcher_dispatch_callback;
|
|
77
95
|
ev_stat_init(
|
|
78
|
-
&watcher_data->event_types.ev_stat,
|
|
79
|
-
Coolio_StatWatcher_libev_callback,
|
|
80
|
-
RSTRING_PTR(path),
|
|
96
|
+
&watcher_data->event_types.ev_stat,
|
|
97
|
+
Coolio_StatWatcher_libev_callback,
|
|
98
|
+
RSTRING_PTR(path),
|
|
81
99
|
interval == Qnil ? 0 : NUM2DBL(interval)
|
|
82
|
-
);
|
|
100
|
+
);
|
|
83
101
|
watcher_data->event_types.ev_stat.data = (void *)self;
|
|
84
102
|
|
|
85
103
|
return Qnil;
|
|
@@ -88,7 +106,7 @@ static VALUE Coolio_StatWatcher_initialize(int argc, VALUE *argv, VALUE self)
|
|
|
88
106
|
/**
|
|
89
107
|
* call-seq:
|
|
90
108
|
* Coolio::StatWatcher.attach(loop) -> Coolio::StatWatcher
|
|
91
|
-
*
|
|
109
|
+
*
|
|
92
110
|
* Attach the stat watcher to the given Coolio::Loop. If the watcher is already
|
|
93
111
|
* attached to a loop, detach it from the old one and attach it to the new one.
|
|
94
112
|
*/
|
|
@@ -97,9 +115,9 @@ static VALUE Coolio_StatWatcher_attach(VALUE self, VALUE loop)
|
|
|
97
115
|
ev_tstamp interval, timeout;
|
|
98
116
|
struct Coolio_Loop *loop_data;
|
|
99
117
|
struct Coolio_Watcher *watcher_data;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
118
|
+
|
|
119
|
+
if(!rb_obj_is_kind_of(loop, cCoolio_Loop))
|
|
120
|
+
rb_raise(rb_eArgError, "expected loop to be an instance of Coolio::Loop, not %s", RSTRING_PTR(rb_inspect(loop)));
|
|
103
121
|
|
|
104
122
|
Data_Get_Struct(loop, struct Coolio_Loop, loop_data);
|
|
105
123
|
Data_Get_Struct(self, struct Coolio_Watcher, watcher_data);
|
|
@@ -112,13 +130,13 @@ static VALUE Coolio_StatWatcher_attach(VALUE self, VALUE loop)
|
|
|
112
130
|
ev_stat_start(loop_data->ev_loop, &watcher_data->event_types.ev_stat);
|
|
113
131
|
rb_call_super(1, &loop);
|
|
114
132
|
|
|
115
|
-
return self;
|
|
133
|
+
return self;
|
|
116
134
|
}
|
|
117
135
|
|
|
118
136
|
/**
|
|
119
137
|
* call-seq:
|
|
120
138
|
* Coolio::StatWatcher.detach -> Coolio::StatWatcher
|
|
121
|
-
*
|
|
139
|
+
*
|
|
122
140
|
* Detach the stat watcher from its current Coolio::Loop.
|
|
123
141
|
*/
|
|
124
142
|
static VALUE Coolio_StatWatcher_detach(VALUE self)
|
|
@@ -131,7 +149,7 @@ static VALUE Coolio_StatWatcher_detach(VALUE self)
|
|
|
131
149
|
/**
|
|
132
150
|
* call-seq:
|
|
133
151
|
* Coolio::StatWatcher.enable -> Coolio::StatWatcher
|
|
134
|
-
*
|
|
152
|
+
*
|
|
135
153
|
* Re-enable a stat watcher which has been temporarily disabled. See the
|
|
136
154
|
* disable method for a more thorough explanation.
|
|
137
155
|
*/
|
|
@@ -139,15 +157,15 @@ static VALUE Coolio_StatWatcher_enable(VALUE self)
|
|
|
139
157
|
{
|
|
140
158
|
Watcher_Enable(stat, self);
|
|
141
159
|
|
|
142
|
-
return self;
|
|
160
|
+
return self;
|
|
143
161
|
}
|
|
144
162
|
|
|
145
163
|
/**
|
|
146
164
|
* call-seq:
|
|
147
165
|
* Coolio::StatWatcher.disable -> Coolio::StatWatcher
|
|
148
|
-
*
|
|
149
|
-
* Temporarily disable a stat watcher which is attached to a loop.
|
|
150
|
-
* This is useful if you wish to toggle event monitoring on and off.
|
|
166
|
+
*
|
|
167
|
+
* Temporarily disable a stat watcher which is attached to a loop.
|
|
168
|
+
* This is useful if you wish to toggle event monitoring on and off.
|
|
151
169
|
*/
|
|
152
170
|
static VALUE Coolio_StatWatcher_disable(VALUE self)
|
|
153
171
|
{
|
|
@@ -159,10 +177,10 @@ static VALUE Coolio_StatWatcher_disable(VALUE self)
|
|
|
159
177
|
/**
|
|
160
178
|
* call-seq:
|
|
161
179
|
* Coolio::StatWatcher#on_change -> nil
|
|
162
|
-
*
|
|
180
|
+
*
|
|
163
181
|
* Called whenever the status of the given path changes
|
|
164
182
|
*/
|
|
165
|
-
static VALUE Coolio_StatWatcher_on_change(VALUE self)
|
|
183
|
+
static VALUE Coolio_StatWatcher_on_change(VALUE self, VALUE previous, VALUE current)
|
|
166
184
|
{
|
|
167
185
|
return Qnil;
|
|
168
186
|
}
|
|
@@ -170,7 +188,7 @@ static VALUE Coolio_StatWatcher_on_change(VALUE self)
|
|
|
170
188
|
/**
|
|
171
189
|
* call-seq:
|
|
172
190
|
* Coolio::StatWatcher#path -> String
|
|
173
|
-
*
|
|
191
|
+
*
|
|
174
192
|
* Retrieve the path associated with this StatWatcher
|
|
175
193
|
*/
|
|
176
194
|
static VALUE Coolio_StatWatcher_path(VALUE self)
|
|
@@ -186,6 +204,66 @@ static void Coolio_StatWatcher_libev_callback(struct ev_loop *ev_loop, struct ev
|
|
|
186
204
|
|
|
187
205
|
/* Coolio::Loop dispatch callback */
|
|
188
206
|
static void Coolio_StatWatcher_dispatch_callback(VALUE self, int revents)
|
|
189
|
-
{
|
|
190
|
-
|
|
207
|
+
{
|
|
208
|
+
struct Coolio_Watcher *watcher_data;
|
|
209
|
+
Data_Get_Struct(self, struct Coolio_Watcher, watcher_data);
|
|
210
|
+
|
|
211
|
+
VALUE previous_statdata = Coolio_StatInfo_build(&watcher_data->event_types.ev_stat.prev);
|
|
212
|
+
VALUE current_statdata = Coolio_StatInfo_build(&watcher_data->event_types.ev_stat.attr);
|
|
213
|
+
rb_funcall(self, rb_intern("on_change"), 2, previous_statdata, current_statdata);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Convience method to build StatInfo structs given an ev_statdata
|
|
218
|
+
* */
|
|
219
|
+
static VALUE Coolio_StatInfo_build(ev_statdata *statdata_struct)
|
|
220
|
+
{
|
|
221
|
+
VALUE at_method = rb_intern("at");
|
|
222
|
+
VALUE cTime = rb_const_get(rb_cObject, rb_intern("Time"));
|
|
223
|
+
|
|
224
|
+
VALUE mtime = Qnil;
|
|
225
|
+
VALUE ctime = Qnil;
|
|
226
|
+
VALUE atime = Qnil;
|
|
227
|
+
VALUE dev = Qnil;
|
|
228
|
+
VALUE ino = Qnil;
|
|
229
|
+
VALUE mode = Qnil;
|
|
230
|
+
VALUE nlink = Qnil;
|
|
231
|
+
VALUE uid = Qnil;
|
|
232
|
+
VALUE gid = Qnil;
|
|
233
|
+
VALUE rdev = Qnil;
|
|
234
|
+
VALUE size = Qnil;
|
|
235
|
+
VALUE blksize = Qnil;
|
|
236
|
+
VALUE blocks = Qnil;
|
|
237
|
+
|
|
238
|
+
mtime = rb_funcall(cTime, at_method, 1, INT2NUM(statdata_struct->st_mtime));
|
|
239
|
+
ctime = rb_funcall(cTime, at_method, 1, INT2NUM(statdata_struct->st_ctime));
|
|
240
|
+
atime = rb_funcall(cTime, at_method, 1, INT2NUM(statdata_struct->st_atime));
|
|
241
|
+
dev = INT2NUM(statdata_struct->st_dev);
|
|
242
|
+
ino = INT2NUM(statdata_struct->st_ino);
|
|
243
|
+
mode = INT2NUM(statdata_struct->st_mode);
|
|
244
|
+
nlink = INT2NUM(statdata_struct->st_nlink);
|
|
245
|
+
uid = INT2NUM(statdata_struct->st_uid);
|
|
246
|
+
gid = INT2NUM(statdata_struct->st_gid);
|
|
247
|
+
rdev = INT2NUM(statdata_struct->st_rdev);
|
|
248
|
+
size = INT2NUM(statdata_struct->st_size);
|
|
249
|
+
#ifdef HAVE_ST_BLKSIZE
|
|
250
|
+
blksize = INT2NUM(statdata_struct->st_blksize);
|
|
251
|
+
blocks = INT2NUM(statdata_struct->st_blocks);
|
|
252
|
+
#endif
|
|
253
|
+
|
|
254
|
+
return rb_struct_new(cCoolio_StatInfo,
|
|
255
|
+
mtime,
|
|
256
|
+
ctime,
|
|
257
|
+
atime,
|
|
258
|
+
dev,
|
|
259
|
+
ino,
|
|
260
|
+
mode,
|
|
261
|
+
nlink,
|
|
262
|
+
uid,
|
|
263
|
+
gid,
|
|
264
|
+
rdev,
|
|
265
|
+
size,
|
|
266
|
+
blksize,
|
|
267
|
+
blocks,
|
|
268
|
+
NULL);
|
|
191
269
|
}
|
data/ext/cool.io/timer_watcher.c
CHANGED
|
@@ -95,8 +95,8 @@ static VALUE Coolio_TimerWatcher_attach(VALUE self, VALUE loop)
|
|
|
95
95
|
struct Coolio_Loop *loop_data;
|
|
96
96
|
struct Coolio_Watcher *watcher_data;
|
|
97
97
|
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
if(!rb_obj_is_kind_of(loop, cCoolio_Loop))
|
|
99
|
+
rb_raise(rb_eArgError, "expected loop to be an instance of Coolio::Loop, not %s", RSTRING_PTR(rb_inspect(loop)));
|
|
100
100
|
|
|
101
101
|
Data_Get_Struct(loop, struct Coolio_Loop, loop_data);
|
|
102
102
|
Data_Get_Struct(self, struct Coolio_Watcher, watcher_data);
|
|
@@ -213,7 +213,7 @@ static void Coolio_TimerWatcher_libev_callback(struct ev_loop *ev_loop, struct e
|
|
|
213
213
|
static void Coolio_TimerWatcher_dispatch_callback(VALUE self, int revents)
|
|
214
214
|
{
|
|
215
215
|
if(revents & EV_TIMEOUT)
|
|
216
|
-
rb_funcall(self, rb_intern("on_timer"), 0
|
|
216
|
+
rb_funcall(self, rb_intern("on_timer"), 0);
|
|
217
217
|
else
|
|
218
218
|
rb_raise(rb_eRuntimeError, "unknown revents value for ev_timer: %d", revents);
|
|
219
219
|
}
|
data/ext/cool.io/utils.c
CHANGED
data/ext/cool.io/watcher.h
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
struct Coolio_Loop *loop_data; \
|
|
13
13
|
\
|
|
14
14
|
if(!rb_obj_is_kind_of(loop, cCoolio_Loop)) \
|
|
15
|
-
rb_raise(rb_eArgError, "expected loop to be an instance of Coolio::Loop"); \
|
|
15
|
+
rb_raise(rb_eArgError, "expected loop to be an instance of Coolio::Loop, not %s", RSTRING_PTR(rb_inspect(loop))); \
|
|
16
16
|
\
|
|
17
17
|
Data_Get_Struct(watcher, struct Coolio_Watcher, watcher_data); \
|
|
18
18
|
Data_Get_Struct(loop, struct Coolio_Loop, loop_data); \
|