ever 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/test.yml +29 -0
- data/.gitignore +57 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +25 -0
- data/LICENSE +21 -0
- data/README.md +167 -0
- data/Rakefile +18 -0
- data/ever.gemspec +26 -0
- data/examples/http_server.rb +124 -0
- data/ext/ever/ever.h +49 -0
- data/ext/ever/ever_ext.c +12 -0
- data/ext/ever/extconf.rb +22 -0
- data/ext/ever/libev.c +2 -0
- data/ext/ever/libev.h +11 -0
- data/ext/ever/loop.c +257 -0
- data/ext/ever/watcher.c +137 -0
- data/ext/libev/Changes +548 -0
- data/ext/libev/LICENSE +37 -0
- data/ext/libev/README +59 -0
- data/ext/libev/README.embed +3 -0
- data/ext/libev/ev.c +5279 -0
- data/ext/libev/ev.h +856 -0
- data/ext/libev/ev_epoll.c +296 -0
- data/ext/libev/ev_kqueue.c +224 -0
- data/ext/libev/ev_linuxaio.c +642 -0
- data/ext/libev/ev_poll.c +156 -0
- data/ext/libev/ev_port.c +192 -0
- data/ext/libev/ev_select.c +316 -0
- data/ext/libev/ev_vars.h +215 -0
- data/ext/libev/ev_win32.c +162 -0
- data/ext/libev/ev_wrap.h +216 -0
- data/ext/libev/test_libev_win32.c +123 -0
- data/lib/ever/version.rb +5 -0
- data/lib/ever.rb +3 -0
- data/test/helper.rb +13 -0
- data/test/run.rb +0 -0
- data/test/test_loop.rb +87 -0
- metadata +131 -0
data/ext/ever/ever.h
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#ifndef EVER_H
|
2
|
+
#define EVER_H
|
3
|
+
|
4
|
+
#include <execinfo.h>
|
5
|
+
#include "ruby.h"
|
6
|
+
#include "../libev/ev.h"
|
7
|
+
|
8
|
+
// debugging
|
9
|
+
#define OBJ_ID(obj) (NUM2LONG(rb_funcall(obj, rb_intern("object_id"), 0)))
|
10
|
+
#define INSPECT(str, obj) { printf(str); VALUE s = rb_funcall(obj, rb_intern("inspect"), 0); printf(": %s\n", StringValueCStr(s)); }
|
11
|
+
#define TRACE_CALLER() { VALUE c = rb_funcall(rb_mKernel, rb_intern("caller"), 0); INSPECT("caller: ", c); }
|
12
|
+
#define TRACE_C_STACK() { \
|
13
|
+
void *entries[10]; \
|
14
|
+
size_t size = backtrace(entries, 10); \
|
15
|
+
char **strings = backtrace_symbols(entries, size); \
|
16
|
+
for (unsigned long i = 0; i < size; i++) printf("%s\n", strings[i]); \
|
17
|
+
free(strings); \
|
18
|
+
}
|
19
|
+
|
20
|
+
// exceptions
|
21
|
+
#define TEST_EXCEPTION(ret) (rb_obj_is_kind_of(ret, rb_eException) == Qtrue)
|
22
|
+
#define RAISE_EXCEPTION(e) rb_funcall(e, ID_invoke, 0);
|
23
|
+
#define RAISE_IF_EXCEPTION(ret) if (rb_obj_is_kind_of(ret, rb_eException) == Qtrue) { RAISE_EXCEPTION(ret); }
|
24
|
+
#define RAISE_IF_NOT_NIL(ret) if (ret != Qnil) { RAISE_EXCEPTION(ret); }
|
25
|
+
|
26
|
+
extern VALUE mEver;
|
27
|
+
extern VALUE cLoop;
|
28
|
+
extern VALUE cWatcher;
|
29
|
+
|
30
|
+
typedef struct Loop_t {
|
31
|
+
struct ev_loop *ev_loop;
|
32
|
+
struct ev_async break_async;
|
33
|
+
|
34
|
+
VALUE active_watchers;
|
35
|
+
VALUE free_watchers;
|
36
|
+
VALUE queued_events;
|
37
|
+
|
38
|
+
int stop;
|
39
|
+
int in_ev_loop;
|
40
|
+
} Loop_t;
|
41
|
+
|
42
|
+
void loop_emit(Loop_t *loop, VALUE key);
|
43
|
+
void loop_release_watcher(Loop_t *loop, VALUE key);
|
44
|
+
|
45
|
+
void Watcher_setup_io(VALUE watcher, Loop_t *loop, VALUE key, int fd, int events, int oneshot);
|
46
|
+
void Watcher_setup_timer(VALUE watcher, Loop_t *loop, VALUE key, double timeout, double interval);
|
47
|
+
void Watcher_stop(VALUE watcher);
|
48
|
+
|
49
|
+
#endif /* EVER_H */
|
data/ext/ever/ever_ext.c
ADDED
data/ext/ever/extconf.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'mkmf'
|
5
|
+
|
6
|
+
$defs << '-DEV_USE_LINUXAIO' if have_header('linux/aio_abi.h')
|
7
|
+
$defs << '-DEV_USE_SELECT' if have_header('sys/select.h')
|
8
|
+
$defs << '-DEV_USE_POLL' if have_type('port_event_t', 'poll.h')
|
9
|
+
$defs << '-DEV_USE_EPOLL' if have_header('sys/epoll.h')
|
10
|
+
$defs << '-DEV_USE_KQUEUE' if have_header('sys/event.h') && have_header('sys/queue.h')
|
11
|
+
$defs << '-DEV_USE_PORT' if have_type('port_event_t', 'port.h')
|
12
|
+
$defs << '-DHAVE_SYS_RESOURCE_H' if have_header('sys/resource.h')
|
13
|
+
|
14
|
+
$CFLAGS << " -Wno-comment"
|
15
|
+
$CFLAGS << " -Wno-unused-result"
|
16
|
+
$CFLAGS << " -Wno-dangling-else"
|
17
|
+
$CFLAGS << " -Wno-parentheses"
|
18
|
+
|
19
|
+
CONFIG['optflags'] << ' -fno-strict-aliasing' unless RUBY_PLATFORM =~ /mswin/
|
20
|
+
|
21
|
+
dir_config 'ever_ext'
|
22
|
+
create_makefile 'ever_ext'
|
data/ext/ever/libev.c
ADDED
data/ext/ever/libev.h
ADDED
data/ext/ever/loop.c
ADDED
@@ -0,0 +1,257 @@
|
|
1
|
+
#include "ever.h"
|
2
|
+
#include "ruby/io.h"
|
3
|
+
|
4
|
+
VALUE cLoop;
|
5
|
+
VALUE SYM_stop;
|
6
|
+
ID ID_ivar_io;
|
7
|
+
|
8
|
+
////////////////////////////////////////////////////////////////////////////////
|
9
|
+
|
10
|
+
static inline void loop_run_ev_loop(Loop_t *loop) {
|
11
|
+
loop->in_ev_loop = 1;
|
12
|
+
ev_run(loop->ev_loop, EVRUN_ONCE);
|
13
|
+
loop->in_ev_loop = 0;
|
14
|
+
}
|
15
|
+
|
16
|
+
static inline void loop_yield_queued_events(Loop_t *loop) {
|
17
|
+
int len = RARRAY_LEN(loop->queued_events);
|
18
|
+
if (!len) return;
|
19
|
+
|
20
|
+
VALUE events = loop->queued_events;
|
21
|
+
loop->queued_events = rb_ary_new();
|
22
|
+
for (int i = 0; i < len; i++) {
|
23
|
+
rb_yield(RARRAY_AREF(events, i));
|
24
|
+
}
|
25
|
+
RB_GC_GUARD(events);
|
26
|
+
}
|
27
|
+
|
28
|
+
inline void loop_emit(Loop_t *loop, VALUE key) {
|
29
|
+
rb_ary_push(loop->queued_events, key);
|
30
|
+
}
|
31
|
+
|
32
|
+
static inline void loop_signal(Loop_t *loop) {
|
33
|
+
if (loop->in_ev_loop) {
|
34
|
+
// Since the loop will run until at least one event has occurred, we signal
|
35
|
+
// the selector's associated async watcher, which will cause the ev loop to
|
36
|
+
// return. In contrast to using `ev_break` to break out of the loop, which
|
37
|
+
// should be called from the same thread (from within the ev_loop), using an
|
38
|
+
// `ev_async` allows us to interrupt the event loop across threads.
|
39
|
+
ev_async_send(loop->ev_loop, &loop->break_async);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
static inline VALUE loop_get_free_watcher(Loop_t *loop) {
|
44
|
+
VALUE watcher = rb_ary_pop(loop->free_watchers);
|
45
|
+
if (watcher != Qnil) return watcher;
|
46
|
+
|
47
|
+
return rb_class_new_instance(0, 0, cWatcher);
|
48
|
+
}
|
49
|
+
|
50
|
+
static inline void loop_watch_fd(Loop_t *loop, VALUE key, int fd, int events, int oneshot) {
|
51
|
+
VALUE watcher = loop_get_free_watcher(loop);
|
52
|
+
Watcher_setup_io(watcher, loop, key, fd, events, oneshot);
|
53
|
+
rb_hash_aset(loop->active_watchers, key, watcher);
|
54
|
+
}
|
55
|
+
|
56
|
+
static inline void loop_watch_timer(Loop_t *loop, VALUE key, double timeout, double interval) {
|
57
|
+
VALUE watcher = loop_get_free_watcher(loop);
|
58
|
+
Watcher_setup_timer(watcher, loop, key, timeout, interval);
|
59
|
+
rb_hash_aset(loop->active_watchers, key, watcher);
|
60
|
+
}
|
61
|
+
|
62
|
+
static inline int sym_to_events(VALUE rw) {
|
63
|
+
return RTEST(rw) ? EV_WRITE : EV_READ;
|
64
|
+
}
|
65
|
+
|
66
|
+
static inline int fd_from_io(VALUE io) {
|
67
|
+
rb_io_t *fptr;
|
68
|
+
VALUE underlying_io = rb_ivar_get(io, ID_ivar_io);
|
69
|
+
if (underlying_io != Qnil) io = underlying_io;
|
70
|
+
GetOpenFile(io, fptr);
|
71
|
+
return fptr->fd;
|
72
|
+
}
|
73
|
+
|
74
|
+
inline void loop_release_watcher(Loop_t *loop, VALUE key) {
|
75
|
+
VALUE watcher = rb_hash_delete(loop->active_watchers, key);
|
76
|
+
if (watcher != Qnil)
|
77
|
+
rb_ary_push(loop->free_watchers, watcher);
|
78
|
+
}
|
79
|
+
|
80
|
+
////////////////////////////////////////////////////////////////////////////////
|
81
|
+
|
82
|
+
static void Loop_mark(void *ptr) {
|
83
|
+
Loop_t *loop = ptr;
|
84
|
+
rb_gc_mark(loop->active_watchers);
|
85
|
+
rb_gc_mark(loop->free_watchers);
|
86
|
+
rb_gc_mark(loop->queued_events);
|
87
|
+
}
|
88
|
+
|
89
|
+
static void Loop_free(void *ptr) {
|
90
|
+
Loop_t *loop = ptr;
|
91
|
+
|
92
|
+
ev_async_stop(loop->ev_loop, &loop->break_async);
|
93
|
+
ev_loop_destroy(loop->ev_loop);
|
94
|
+
}
|
95
|
+
|
96
|
+
static size_t Loop_size(const void *ptr) {
|
97
|
+
return sizeof(Loop_t);
|
98
|
+
}
|
99
|
+
|
100
|
+
static const rb_data_type_t Loop_type = {
|
101
|
+
"Ever::Loop",
|
102
|
+
{Loop_mark, Loop_free, Loop_size,},
|
103
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
104
|
+
};
|
105
|
+
|
106
|
+
static VALUE Loop_allocate(VALUE klass) {
|
107
|
+
Loop_t *loop = ALLOC(Loop_t);
|
108
|
+
return TypedData_Wrap_Struct(klass, &Loop_type, loop);
|
109
|
+
}
|
110
|
+
|
111
|
+
#define GetLoop(obj, loop) \
|
112
|
+
TypedData_Get_Struct((obj), Loop_t, &Loop_type, (loop))
|
113
|
+
|
114
|
+
void break_async_callback(struct ev_loop *ev_loop, struct ev_async *ev_async, int revents) {
|
115
|
+
// This callback does nothing, the break async is used solely for breaking out
|
116
|
+
// of a *blocking* event loop (waking it up) in a thread-safe, signal-safe manner
|
117
|
+
}
|
118
|
+
|
119
|
+
static VALUE Loop_initialize(VALUE self) {
|
120
|
+
Loop_t *loop;
|
121
|
+
GetLoop(self, loop);
|
122
|
+
|
123
|
+
loop->ev_loop = ev_loop_new(EVFLAG_NOSIGMASK);
|
124
|
+
// start async watcher used for breaking a poll op (from another thread)
|
125
|
+
ev_async_init(&loop->break_async, break_async_callback);
|
126
|
+
ev_async_start(loop->ev_loop, &loop->break_async);
|
127
|
+
// the break_async watcher is unreferenced, in order for Loop_poll to not
|
128
|
+
// block when no other watcher is active
|
129
|
+
ev_unref(loop->ev_loop);
|
130
|
+
|
131
|
+
loop->active_watchers = rb_hash_new();
|
132
|
+
loop->free_watchers = rb_ary_new();
|
133
|
+
loop->queued_events = rb_ary_new();
|
134
|
+
|
135
|
+
loop->stop = 0;
|
136
|
+
loop->in_ev_loop = 0;
|
137
|
+
|
138
|
+
return Qnil;
|
139
|
+
}
|
140
|
+
|
141
|
+
VALUE Loop_each(VALUE self) {
|
142
|
+
Loop_t *loop;
|
143
|
+
GetLoop(self, loop);
|
144
|
+
|
145
|
+
loop->stop = 0;
|
146
|
+
while (!loop->stop) {
|
147
|
+
if (RARRAY_LEN(loop->queued_events) == 0) loop_run_ev_loop(loop);
|
148
|
+
loop_yield_queued_events(loop);
|
149
|
+
}
|
150
|
+
return self;
|
151
|
+
}
|
152
|
+
|
153
|
+
VALUE Loop_next_event(VALUE self) {
|
154
|
+
Loop_t *loop;
|
155
|
+
GetLoop(self, loop);
|
156
|
+
|
157
|
+
if (RARRAY_LEN(loop->queued_events) == 0) loop_run_ev_loop(loop);
|
158
|
+
return rb_ary_shift(loop->queued_events);
|
159
|
+
}
|
160
|
+
|
161
|
+
VALUE Loop_emit(VALUE self, VALUE key) {
|
162
|
+
Loop_t *loop;
|
163
|
+
GetLoop(self, loop);
|
164
|
+
|
165
|
+
if (key == SYM_stop)
|
166
|
+
loop->stop = 1;
|
167
|
+
else
|
168
|
+
rb_ary_push(loop->queued_events, key);
|
169
|
+
|
170
|
+
loop_signal(loop);
|
171
|
+
return key;
|
172
|
+
}
|
173
|
+
|
174
|
+
VALUE Loop_signal(VALUE self) {
|
175
|
+
Loop_t *loop;
|
176
|
+
GetLoop(self, loop);
|
177
|
+
|
178
|
+
loop_signal(loop);
|
179
|
+
return self;
|
180
|
+
}
|
181
|
+
|
182
|
+
VALUE Loop_stop(VALUE self) {
|
183
|
+
Loop_t *loop;
|
184
|
+
GetLoop(self, loop);
|
185
|
+
|
186
|
+
loop->stop = 1;
|
187
|
+
loop_signal(loop);
|
188
|
+
return self;
|
189
|
+
}
|
190
|
+
|
191
|
+
VALUE Loop_watch_fd(VALUE self, VALUE key, VALUE fd, VALUE rw, VALUE oneshot) {
|
192
|
+
Loop_t *loop;
|
193
|
+
GetLoop(self, loop);
|
194
|
+
|
195
|
+
if (rb_hash_aref(loop->active_watchers, key) != Qnil)
|
196
|
+
rb_raise(rb_eRuntimeError, "Duplicate event key detected, event key must be unique");
|
197
|
+
|
198
|
+
loop_watch_fd(loop, key, NUM2INT(fd), sym_to_events(rw), RTEST(oneshot));
|
199
|
+
return self;
|
200
|
+
}
|
201
|
+
|
202
|
+
VALUE Loop_watch_io(VALUE self, VALUE key, VALUE io, VALUE rw, VALUE oneshot) {
|
203
|
+
Loop_t *loop;
|
204
|
+
GetLoop(self, loop);
|
205
|
+
|
206
|
+
if (rb_hash_aref(loop->active_watchers, key) != Qnil)
|
207
|
+
rb_raise(rb_eRuntimeError, "Duplicate event key detected, event key must be unique");
|
208
|
+
|
209
|
+
loop_watch_fd(loop, key, fd_from_io(io), sym_to_events(rw), RTEST(oneshot));
|
210
|
+
return self;
|
211
|
+
}
|
212
|
+
|
213
|
+
VALUE Loop_watch_timer(VALUE self, VALUE key, VALUE timeout, VALUE interval) {
|
214
|
+
Loop_t *loop;
|
215
|
+
GetLoop(self, loop);
|
216
|
+
|
217
|
+
if (rb_hash_aref(loop->active_watchers, key) != Qnil)
|
218
|
+
rb_raise(rb_eRuntimeError, "Duplicate event key detected, event key must be unique");
|
219
|
+
|
220
|
+
loop_watch_timer(loop, key, NUM2DBL(timeout), NUM2DBL(interval));
|
221
|
+
return self;
|
222
|
+
}
|
223
|
+
|
224
|
+
VALUE Loop_unwatch(VALUE self, VALUE key) {
|
225
|
+
Loop_t *loop;
|
226
|
+
GetLoop(self, loop);
|
227
|
+
|
228
|
+
VALUE watcher = rb_hash_delete(loop->active_watchers, key);
|
229
|
+
if (watcher == Qnil) return self;
|
230
|
+
|
231
|
+
Watcher_stop(watcher);
|
232
|
+
rb_ary_push(loop->free_watchers, watcher);
|
233
|
+
|
234
|
+
return self;
|
235
|
+
}
|
236
|
+
|
237
|
+
void Init_Loop() {
|
238
|
+
ev_set_allocator(xrealloc);
|
239
|
+
|
240
|
+
cLoop = rb_define_class_under(mEver, "Loop", rb_cObject);
|
241
|
+
rb_define_alloc_func(cLoop, Loop_allocate);
|
242
|
+
|
243
|
+
rb_define_method(cLoop, "initialize", Loop_initialize, 0);
|
244
|
+
|
245
|
+
rb_define_method(cLoop, "each", Loop_each, 0);
|
246
|
+
rb_define_method(cLoop, "next_event", Loop_next_event, 0);
|
247
|
+
rb_define_method(cLoop, "emit", Loop_emit, 1);
|
248
|
+
rb_define_method(cLoop, "signal", Loop_signal, 0);
|
249
|
+
rb_define_method(cLoop, "stop", Loop_stop, 0);
|
250
|
+
rb_define_method(cLoop, "watch_fd", Loop_watch_fd, 4);
|
251
|
+
rb_define_method(cLoop, "watch_io", Loop_watch_io, 4);
|
252
|
+
rb_define_method(cLoop, "watch_timer", Loop_watch_timer, 3);
|
253
|
+
rb_define_method(cLoop, "unwatch", Loop_unwatch, 1);
|
254
|
+
|
255
|
+
SYM_stop = ID2SYM(rb_intern("stop"));
|
256
|
+
ID_ivar_io = rb_intern("@io");
|
257
|
+
}
|
data/ext/ever/watcher.c
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
#include "ever.h"
|
2
|
+
#include "../libev/ev.h"
|
3
|
+
|
4
|
+
VALUE cWatcher;
|
5
|
+
|
6
|
+
enum watcher_type {
|
7
|
+
WATCHER_IO,
|
8
|
+
WATCHER_TIMER
|
9
|
+
};
|
10
|
+
|
11
|
+
|
12
|
+
typedef struct Watcher_t {
|
13
|
+
union {
|
14
|
+
struct ev_io io;
|
15
|
+
struct ev_timer timer;
|
16
|
+
};
|
17
|
+
|
18
|
+
Loop_t *loop;
|
19
|
+
enum watcher_type type;
|
20
|
+
VALUE key;
|
21
|
+
int oneshot;
|
22
|
+
} Watcher_t;
|
23
|
+
|
24
|
+
////////////////////////////////////////////////////////////////////////////////
|
25
|
+
|
26
|
+
static void Watcher_mark(void *ptr) {
|
27
|
+
Watcher_t *watcher = ptr;
|
28
|
+
rb_gc_mark(watcher->key);
|
29
|
+
}
|
30
|
+
|
31
|
+
static void Watcher_free(void *ptr) {
|
32
|
+
xfree(ptr);
|
33
|
+
}
|
34
|
+
|
35
|
+
static size_t Watcher_size(const void *ptr) {
|
36
|
+
return sizeof(Watcher_t);
|
37
|
+
}
|
38
|
+
|
39
|
+
static const rb_data_type_t Watcher_type = {
|
40
|
+
"Ever::Watcher",
|
41
|
+
{Watcher_mark, Watcher_free, Watcher_size,},
|
42
|
+
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
43
|
+
};
|
44
|
+
|
45
|
+
static VALUE Watcher_allocate(VALUE klass) {
|
46
|
+
Watcher_t *watcher = ALLOC(Watcher_t);
|
47
|
+
return TypedData_Wrap_Struct(klass, &Watcher_type, watcher);
|
48
|
+
}
|
49
|
+
|
50
|
+
#define GetWatcher(obj, watcher) \
|
51
|
+
TypedData_Get_Struct((obj), Watcher_t, &Watcher_type, (watcher))
|
52
|
+
|
53
|
+
VALUE Watcher_initialize(VALUE self) {
|
54
|
+
return self;
|
55
|
+
}
|
56
|
+
|
57
|
+
////////////////////////////////////////////////////////////////////////////////
|
58
|
+
|
59
|
+
inline void watcher_stop(Watcher_t *watcher) {
|
60
|
+
switch (watcher->type) {
|
61
|
+
case WATCHER_IO:
|
62
|
+
ev_io_stop(watcher->loop->ev_loop, &watcher->io);
|
63
|
+
return;
|
64
|
+
case WATCHER_TIMER:
|
65
|
+
ev_timer_stop(watcher->loop->ev_loop, &watcher->timer);
|
66
|
+
return;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
void watcher_io_callback(EV_P_ ev_io *w, int revents)
|
71
|
+
{
|
72
|
+
Watcher_t *watcher = (Watcher_t *)w;
|
73
|
+
loop_emit(watcher->loop, watcher->key);
|
74
|
+
if (watcher->oneshot) {
|
75
|
+
watcher_stop(watcher);
|
76
|
+
loop_release_watcher(watcher->loop, watcher->key);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
void watcher_timer_callback(EV_P_ ev_timer *w, int revents)
|
81
|
+
{
|
82
|
+
Watcher_t *watcher = (Watcher_t *)w;
|
83
|
+
loop_emit(watcher->loop, watcher->key);
|
84
|
+
if (watcher->oneshot) {
|
85
|
+
watcher_stop(watcher);
|
86
|
+
loop_release_watcher(watcher->loop, watcher->key);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
static inline void watcher_setup_io(Watcher_t *watcher, Loop_t *loop, VALUE key, int fd, int events, int oneshot) {
|
91
|
+
watcher->type = WATCHER_IO;
|
92
|
+
watcher->loop = loop;
|
93
|
+
watcher->key = key;
|
94
|
+
watcher->oneshot = oneshot;
|
95
|
+
|
96
|
+
ev_io_init(&watcher->io, watcher_io_callback, fd, events);
|
97
|
+
ev_io_start(loop->ev_loop, &watcher->io);
|
98
|
+
}
|
99
|
+
|
100
|
+
static inline void watcher_setup_timer(Watcher_t *watcher, Loop_t *loop, VALUE key, double timeout, double interval) {
|
101
|
+
watcher->type = WATCHER_TIMER;
|
102
|
+
watcher->loop = loop;
|
103
|
+
watcher->key = key;
|
104
|
+
watcher->oneshot = interval == 0.;
|
105
|
+
|
106
|
+
ev_timer_init(&watcher->timer, watcher_timer_callback, timeout, interval);
|
107
|
+
ev_timer_start(loop->ev_loop, &watcher->timer);
|
108
|
+
}
|
109
|
+
|
110
|
+
////////////////////////////////////////////////////////////////////////////////
|
111
|
+
|
112
|
+
inline void Watcher_setup_io(VALUE self, Loop_t *loop, VALUE key, int fd, int events, int oneshot) {
|
113
|
+
Watcher_t *watcher;
|
114
|
+
GetWatcher(self, watcher);
|
115
|
+
|
116
|
+
watcher_setup_io(watcher, loop, key, fd, events, oneshot);
|
117
|
+
}
|
118
|
+
|
119
|
+
inline void Watcher_setup_timer(VALUE self, Loop_t *loop, VALUE key, double timeout, double interval) {
|
120
|
+
Watcher_t *watcher;
|
121
|
+
GetWatcher(self, watcher);
|
122
|
+
|
123
|
+
watcher_setup_timer(watcher, loop, key, timeout, interval);
|
124
|
+
}
|
125
|
+
|
126
|
+
inline void Watcher_stop(VALUE self) {
|
127
|
+
Watcher_t *watcher;
|
128
|
+
GetWatcher(self, watcher);
|
129
|
+
|
130
|
+
watcher_stop(watcher);
|
131
|
+
}
|
132
|
+
|
133
|
+
void Init_Watcher() {
|
134
|
+
cWatcher = rb_define_class_under(mEver, "Watcher", rb_cObject);
|
135
|
+
rb_define_alloc_func(cWatcher, Watcher_allocate);
|
136
|
+
rb_define_method(cWatcher, "initialize", Watcher_initialize, 0);
|
137
|
+
}
|