iodine 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +63 -100
- data/bin/raw-rbhttp +12 -7
- data/examples/config.ru +8 -7
- data/examples/echo.ru +8 -7
- data/examples/info.md +41 -35
- data/examples/pubsub_engine.ru +12 -12
- data/examples/redis.ru +10 -12
- data/examples/shootout.ru +19 -42
- data/exe/iodine +116 -1
- data/ext/iodine/defer.c +1 -1
- data/ext/iodine/facil.c +12 -8
- data/ext/iodine/facil.h +2 -2
- data/ext/iodine/iodine.c +177 -343
- data/ext/iodine/iodine.h +18 -72
- data/ext/iodine/iodine_caller.c +132 -0
- data/ext/iodine/iodine_caller.h +21 -0
- data/ext/iodine/iodine_connection.c +841 -0
- data/ext/iodine/iodine_connection.h +55 -0
- data/ext/iodine/iodine_defer.c +391 -0
- data/ext/iodine/iodine_defer.h +7 -0
- data/ext/iodine/{rb-fiobj2rb.h → iodine_fiobj2rb.h} +6 -6
- data/ext/iodine/iodine_helpers.c +51 -5
- data/ext/iodine/iodine_helpers.h +2 -3
- data/ext/iodine/iodine_http.c +284 -141
- data/ext/iodine/iodine_http.h +2 -2
- data/ext/iodine/iodine_json.c +13 -13
- data/ext/iodine/iodine_json.h +1 -1
- data/ext/iodine/iodine_pubsub.c +573 -823
- data/ext/iodine/iodine_pubsub.h +15 -27
- data/ext/iodine/{rb-rack-io.c → iodine_rack_io.c} +30 -8
- data/ext/iodine/{rb-rack-io.h → iodine_rack_io.h} +1 -0
- data/ext/iodine/iodine_store.c +136 -0
- data/ext/iodine/iodine_store.h +20 -0
- data/ext/iodine/iodine_tcp.c +385 -0
- data/ext/iodine/iodine_tcp.h +9 -0
- data/lib/iodine.rb +73 -171
- data/lib/iodine/connection.rb +34 -0
- data/lib/iodine/pubsub.rb +5 -18
- data/lib/iodine/rack_utils.rb +43 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/rack/handler/iodine.rb +1 -182
- metadata +17 -18
- data/ext/iodine/iodine_protocol.c +0 -689
- data/ext/iodine/iodine_protocol.h +0 -13
- data/ext/iodine/iodine_websockets.c +0 -550
- data/ext/iodine/iodine_websockets.h +0 -17
- data/ext/iodine/rb-call.c +0 -156
- data/ext/iodine/rb-call.h +0 -70
- data/ext/iodine/rb-defer.c +0 -124
- data/ext/iodine/rb-registry.c +0 -150
- data/ext/iodine/rb-registry.h +0 -34
- data/lib/iodine/cli.rb +0 -89
- data/lib/iodine/monkeypatch.rb +0 -46
- data/lib/iodine/protocol.rb +0 -42
- data/lib/iodine/websocket.rb +0 -16
@@ -0,0 +1,55 @@
|
|
1
|
+
#ifndef H_IODINE_CONNECTION_H
|
2
|
+
#define H_IODINE_CONNECTION_H
|
3
|
+
|
4
|
+
#include "iodine.h"
|
5
|
+
|
6
|
+
typedef enum {
|
7
|
+
IODINE_CONNECTION_RAW,
|
8
|
+
IODINE_CONNECTION_WEBSOCKET,
|
9
|
+
IODINE_CONNECTION_SSE
|
10
|
+
} iodine_connection_type_e;
|
11
|
+
|
12
|
+
typedef struct {
|
13
|
+
iodine_connection_type_e type;
|
14
|
+
intptr_t uuid;
|
15
|
+
void *arg;
|
16
|
+
VALUE handler;
|
17
|
+
VALUE env;
|
18
|
+
} iodine_connection_s;
|
19
|
+
|
20
|
+
/**
|
21
|
+
* Creates a new connection object.
|
22
|
+
*/
|
23
|
+
VALUE iodine_connection_new(iodine_connection_s args);
|
24
|
+
#define iodine_connection_new(...) \
|
25
|
+
iodine_connection_new((iodine_connection_s){__VA_ARGS__})
|
26
|
+
|
27
|
+
typedef enum {
|
28
|
+
IODINE_CONNECTION_ON_OPEN,
|
29
|
+
IODINE_CONNECTION_ON_MESSAGE,
|
30
|
+
IODINE_CONNECTION_ON_DRAINED,
|
31
|
+
IODINE_CONNECTION_PING,
|
32
|
+
IODINE_CONNECTION_ON_SHUTDOWN,
|
33
|
+
IODINE_CONNECTION_ON_CLOSE
|
34
|
+
} iodine_connection_event_type_e;
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Fires a connection object's event. `data` is only for the on_message event.
|
38
|
+
*/
|
39
|
+
void iodine_connection_fire_event(VALUE connection,
|
40
|
+
iodine_connection_event_type_e ev,
|
41
|
+
VALUE data);
|
42
|
+
|
43
|
+
/** Initializes the Connection Ruby class. */
|
44
|
+
void iodine_connection_init(void);
|
45
|
+
|
46
|
+
extern const rb_data_type_t iodine_connection_data_type;
|
47
|
+
|
48
|
+
static inline iodine_connection_s *iodine_connection_CData(VALUE self) {
|
49
|
+
iodine_connection_s *c = NULL;
|
50
|
+
TypedData_Get_Struct(self, iodine_connection_s, &iodine_connection_data_type,
|
51
|
+
c);
|
52
|
+
return c;
|
53
|
+
}
|
54
|
+
|
55
|
+
#endif
|
@@ -0,0 +1,391 @@
|
|
1
|
+
#include "iodine.h"
|
2
|
+
|
3
|
+
#include <ruby/thread.h>
|
4
|
+
|
5
|
+
#include <stdint.h>
|
6
|
+
// clang-format on
|
7
|
+
|
8
|
+
#include "facil.h"
|
9
|
+
#include <spnlock.inc>
|
10
|
+
|
11
|
+
#include <pthread.h>
|
12
|
+
|
13
|
+
/* *****************************************************************************
|
14
|
+
IO flushing dedicated thread for protection against blocking code
|
15
|
+
***************************************************************************** */
|
16
|
+
|
17
|
+
static spn_lock_i sock_io_thread = 0;
|
18
|
+
static pthread_t sock_io_pthread;
|
19
|
+
typedef struct {
|
20
|
+
size_t threads;
|
21
|
+
size_t processes;
|
22
|
+
} iodine_start_settings_s;
|
23
|
+
|
24
|
+
static void *iodine_io_thread(void *arg) {
|
25
|
+
(void)arg;
|
26
|
+
struct timespec tm;
|
27
|
+
while (sock_io_thread) {
|
28
|
+
sock_flush_all();
|
29
|
+
tm = (struct timespec){.tv_nsec = 0, .tv_sec = 1};
|
30
|
+
nanosleep(&tm, NULL);
|
31
|
+
}
|
32
|
+
return NULL;
|
33
|
+
}
|
34
|
+
static void iodine_start_io_thread(void *a_, void *b_) {
|
35
|
+
if (!spn_trylock(&sock_io_thread)) {
|
36
|
+
pthread_create(&sock_io_pthread, NULL, iodine_io_thread, NULL);
|
37
|
+
}
|
38
|
+
(void)a_;
|
39
|
+
(void)b_;
|
40
|
+
}
|
41
|
+
static void iodine_join_io_thread(void) {
|
42
|
+
if (spn_unlock(&sock_io_thread)) {
|
43
|
+
sock_io_thread = 0;
|
44
|
+
pthread_join(sock_io_pthread, NULL);
|
45
|
+
sock_io_pthread = NULL;
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
/* *****************************************************************************
|
50
|
+
The Defer library overriding functions
|
51
|
+
***************************************************************************** */
|
52
|
+
|
53
|
+
/* used to create Ruby threads and pass them the information they need */
|
54
|
+
struct CreateThreadArgs {
|
55
|
+
void *(*thread_func)(void *);
|
56
|
+
void *arg;
|
57
|
+
spn_lock_i lock;
|
58
|
+
};
|
59
|
+
|
60
|
+
/* used for GVL signalling */
|
61
|
+
void call_async_signal(void *pool) { defer_pool_stop((pool_pt)pool); }
|
62
|
+
|
63
|
+
static void *defer_thread_start(void *args_) {
|
64
|
+
struct CreateThreadArgs *args = args_;
|
65
|
+
IodineCaller.set_GVL(0);
|
66
|
+
args->thread_func(args->arg);
|
67
|
+
return NULL;
|
68
|
+
}
|
69
|
+
|
70
|
+
/* the thread's GVL release */
|
71
|
+
static VALUE defer_thread_inGVL(void *args_) {
|
72
|
+
struct CreateThreadArgs *old_args = args_;
|
73
|
+
struct CreateThreadArgs args = *old_args;
|
74
|
+
IodineCaller.set_GVL(1);
|
75
|
+
spn_unlock(&old_args->lock);
|
76
|
+
rb_thread_call_without_gvl(defer_thread_start, &args,
|
77
|
+
(void (*)(void *))call_async_signal, args.arg);
|
78
|
+
return Qnil;
|
79
|
+
}
|
80
|
+
|
81
|
+
/* Within the GVL, creates a Ruby thread using an API call */
|
82
|
+
static void *create_ruby_thread_gvl(void *args) {
|
83
|
+
return (void *)IodineStore.add(rb_thread_create(defer_thread_inGVL, args));
|
84
|
+
}
|
85
|
+
|
86
|
+
/* Runs the before / after fork callbacks (if `before` is true, before runs) */
|
87
|
+
static void iodine_perform_fork_callbacks(uint8_t before);
|
88
|
+
|
89
|
+
static void *fork_using_ruby(void *ignr) {
|
90
|
+
// stop IO thread and call before_fork callbacks
|
91
|
+
if (sock_io_pthread) {
|
92
|
+
iodine_join_io_thread();
|
93
|
+
}
|
94
|
+
iodine_perform_fork_callbacks(1);
|
95
|
+
// fork
|
96
|
+
const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern2("Process", 7));
|
97
|
+
const VALUE rb_pid = IodineCaller.call(ProcessClass, rb_intern2("fork", 4));
|
98
|
+
intptr_t pid = 0;
|
99
|
+
if (rb_pid != Qnil) {
|
100
|
+
pid = NUM2INT(rb_pid);
|
101
|
+
} else {
|
102
|
+
pid = 0;
|
103
|
+
}
|
104
|
+
// manage post forking state
|
105
|
+
IodineCaller.set_GVL(1); /* enforce GVL state in thread storage */
|
106
|
+
if (!pid) {
|
107
|
+
IodineStore.after_fork();
|
108
|
+
}
|
109
|
+
iodine_perform_fork_callbacks(0);
|
110
|
+
// re-initiate IO thread
|
111
|
+
defer(iodine_start_io_thread, NULL, NULL);
|
112
|
+
return (void *)pid;
|
113
|
+
(void)ignr;
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
OVERRIDE THIS to replace the default pthread implementation.
|
118
|
+
*/
|
119
|
+
void *defer_new_thread(void *(*thread_func)(void *), void *arg) {
|
120
|
+
struct CreateThreadArgs data = (struct CreateThreadArgs){
|
121
|
+
.thread_func = thread_func, .arg = arg, .lock = SPN_LOCK_INIT,
|
122
|
+
};
|
123
|
+
spn_lock(&data.lock);
|
124
|
+
void *thr = IodineCaller.enterGVL(create_ruby_thread_gvl, &data);
|
125
|
+
if (!thr || thr == (void *)Qnil || thr == (void *)Qfalse) {
|
126
|
+
thr = NULL;
|
127
|
+
} else {
|
128
|
+
/* wait for thread to signal it's alive. */
|
129
|
+
spn_lock(&data.lock);
|
130
|
+
}
|
131
|
+
return thr;
|
132
|
+
}
|
133
|
+
|
134
|
+
/**
|
135
|
+
OVERRIDE THIS to replace the default pthread implementation.
|
136
|
+
*/
|
137
|
+
int defer_join_thread(void *thr) {
|
138
|
+
if (!thr || (VALUE)thr == Qfalse || (VALUE)thr == Qnil)
|
139
|
+
return -1;
|
140
|
+
IodineCaller.call((VALUE)thr, rb_intern("join"));
|
141
|
+
IodineStore.remove((VALUE)thr);
|
142
|
+
return 0;
|
143
|
+
}
|
144
|
+
|
145
|
+
// void defer_free_thread(void *thr) { (void)thr; }
|
146
|
+
void defer_free_thread(void *thr) { IodineStore.remove((VALUE)thr); }
|
147
|
+
|
148
|
+
/**
|
149
|
+
OVERRIDE THIS to replace the default `fork` implementation or to inject hooks
|
150
|
+
into the forking function.
|
151
|
+
|
152
|
+
Behaves like the system's `fork`.
|
153
|
+
*/
|
154
|
+
int facil_fork(void) {
|
155
|
+
intptr_t pid = (intptr_t)IodineCaller.enterGVL(fork_using_ruby, NULL);
|
156
|
+
return (int)pid;
|
157
|
+
}
|
158
|
+
|
159
|
+
/* *****************************************************************************
|
160
|
+
Task performance
|
161
|
+
***************************************************************************** */
|
162
|
+
|
163
|
+
static ID call_id;
|
164
|
+
|
165
|
+
static void iodine_defer_performe_once(void *block, void *ignr) {
|
166
|
+
IodineCaller.call((VALUE)block, call_id);
|
167
|
+
IodineStore.remove((VALUE)block);
|
168
|
+
(void)ignr;
|
169
|
+
}
|
170
|
+
|
171
|
+
static void iodine_defer_run_timer(void *block) {
|
172
|
+
IodineCaller.call((VALUE)block, call_id);
|
173
|
+
}
|
174
|
+
|
175
|
+
/* *****************************************************************************
|
176
|
+
Defer API
|
177
|
+
***************************************************************************** */
|
178
|
+
|
179
|
+
/**
|
180
|
+
* Runs a block of code asyncronously (adds the code to the event queue).
|
181
|
+
*
|
182
|
+
* Always returns the block of code to executed (Proc object).
|
183
|
+
*
|
184
|
+
* Code will be executed only while Iodine is running (after {Iodine.start}).
|
185
|
+
*
|
186
|
+
* Code blocks that where scheduled to run before Iodine enters cluster mode
|
187
|
+
* will run on all child processes.
|
188
|
+
*/
|
189
|
+
static VALUE iodine_defer_run(VALUE self) {
|
190
|
+
rb_need_block();
|
191
|
+
VALUE block = IodineStore.add(rb_block_proc());
|
192
|
+
defer(iodine_defer_performe_once, (void *)block, NULL);
|
193
|
+
return block;
|
194
|
+
(void)self;
|
195
|
+
}
|
196
|
+
|
197
|
+
/**
|
198
|
+
Runs the required block after the specified number of milliseconds have passed.
|
199
|
+
Time is counted only once Iodine started running (using {Iodine.start}).
|
200
|
+
|
201
|
+
Tasks scheduled before calling {Iodine.start} will run once for every process.
|
202
|
+
|
203
|
+
Always returns a copy of the block object.
|
204
|
+
*/
|
205
|
+
static VALUE iodine_defer_run_after(VALUE self, VALUE milliseconds) {
|
206
|
+
(void)(self);
|
207
|
+
if (milliseconds == Qnil) {
|
208
|
+
return iodine_defer_run(self);
|
209
|
+
}
|
210
|
+
if (TYPE(milliseconds) != T_FIXNUM) {
|
211
|
+
rb_raise(rb_eTypeError, "milliseconds must be a number");
|
212
|
+
return Qnil;
|
213
|
+
}
|
214
|
+
size_t milli = FIX2UINT(milliseconds);
|
215
|
+
if (milli == 0) {
|
216
|
+
return iodine_defer_run(self);
|
217
|
+
}
|
218
|
+
// requires a block to be passed
|
219
|
+
rb_need_block();
|
220
|
+
VALUE block = rb_block_proc();
|
221
|
+
if (block == Qnil)
|
222
|
+
return Qfalse;
|
223
|
+
IodineStore.add(block);
|
224
|
+
if (facil_run_every(milli, 1, iodine_defer_run_timer, (void *)block,
|
225
|
+
(void (*)(void *))IodineStore.remove) == -1) {
|
226
|
+
perror("ERROR: Iodine couldn't initialize timer");
|
227
|
+
return Qnil;
|
228
|
+
}
|
229
|
+
return block;
|
230
|
+
}
|
231
|
+
/**
|
232
|
+
Runs the required block after the specified number of milliseconds have passed.
|
233
|
+
Time is counted only once Iodine started running (using {Iodine.start}).
|
234
|
+
|
235
|
+
Accepts:
|
236
|
+
|
237
|
+
milliseconds:: the number of milliseconds between event repetitions.
|
238
|
+
|
239
|
+
repetitions:: the number of event repetitions. Defaults to 0 (never ending).
|
240
|
+
|
241
|
+
block:: (required) a block is required, as otherwise there is nothing to
|
242
|
+
perform.
|
243
|
+
|
244
|
+
The event will repeat itself until the number of repetitions had been delpeted.
|
245
|
+
|
246
|
+
Always returns a copy of the block object.
|
247
|
+
*/
|
248
|
+
static VALUE iodine_defer_run_every(int argc, VALUE *argv, VALUE self) {
|
249
|
+
(void)(self);
|
250
|
+
VALUE milliseconds, repetitions, block;
|
251
|
+
|
252
|
+
rb_scan_args(argc, argv, "11&", &milliseconds, &repetitions, &block);
|
253
|
+
|
254
|
+
if (TYPE(milliseconds) != T_FIXNUM) {
|
255
|
+
rb_raise(rb_eTypeError, "milliseconds must be a number.");
|
256
|
+
return Qnil;
|
257
|
+
}
|
258
|
+
if (repetitions != Qnil && TYPE(repetitions) != T_FIXNUM) {
|
259
|
+
rb_raise(rb_eTypeError, "repetitions must be a number or `nil`.");
|
260
|
+
return Qnil;
|
261
|
+
}
|
262
|
+
|
263
|
+
size_t milli = FIX2UINT(milliseconds);
|
264
|
+
size_t repeat = (repetitions == Qnil) ? 0 : FIX2UINT(repetitions);
|
265
|
+
// requires a block to be passed
|
266
|
+
rb_need_block();
|
267
|
+
IodineStore.add(block);
|
268
|
+
if (facil_run_every(milli, repeat, iodine_defer_run_timer, (void *)block,
|
269
|
+
(void (*)(void *))IodineStore.remove) == -1) {
|
270
|
+
perror("ERROR: Iodine couldn't initialize timer");
|
271
|
+
return Qnil;
|
272
|
+
}
|
273
|
+
return block;
|
274
|
+
}
|
275
|
+
|
276
|
+
/* *****************************************************************************
|
277
|
+
Pre/Post `fork`
|
278
|
+
***************************************************************************** */
|
279
|
+
#include "fio_llist.h"
|
280
|
+
#include "spnlock.inc"
|
281
|
+
|
282
|
+
static spn_lock_i iodine_before_fork_lock = SPN_LOCK_INIT;
|
283
|
+
static fio_ls_s iodine_before_fork_list = FIO_LS_INIT(iodine_before_fork_list);
|
284
|
+
static spn_lock_i iodine_after_fork_lock = SPN_LOCK_INIT;
|
285
|
+
static fio_ls_s iodine_after_fork_list = FIO_LS_INIT(iodine_after_fork_list);
|
286
|
+
static spn_lock_i iodine_on_shutdown_lock = SPN_LOCK_INIT;
|
287
|
+
static fio_ls_s iodine_on_shutdown_list = FIO_LS_INIT(iodine_on_shutdown_list);
|
288
|
+
|
289
|
+
/**
|
290
|
+
Sets a block of code to run before a new worker process is forked (cluster mode
|
291
|
+
only).
|
292
|
+
*/
|
293
|
+
VALUE iodine_before_fork_add(VALUE self) {
|
294
|
+
rb_need_block();
|
295
|
+
VALUE block = rb_block_proc();
|
296
|
+
IodineStore.add(block);
|
297
|
+
spn_lock(&iodine_before_fork_lock);
|
298
|
+
fio_ls_push(&iodine_before_fork_list, (void *)block);
|
299
|
+
spn_unlock(&iodine_before_fork_lock);
|
300
|
+
return block;
|
301
|
+
(void)self;
|
302
|
+
}
|
303
|
+
|
304
|
+
/**
|
305
|
+
Sets a block of code to run after a new worker process is forked (cluster mode
|
306
|
+
only).
|
307
|
+
*/
|
308
|
+
VALUE iodine_after_fork_add(VALUE self) {
|
309
|
+
rb_need_block();
|
310
|
+
VALUE block = rb_block_proc();
|
311
|
+
IodineStore.add(block);
|
312
|
+
spn_lock(&iodine_after_fork_lock);
|
313
|
+
fio_ls_push(&iodine_after_fork_list, (void *)block);
|
314
|
+
spn_unlock(&iodine_after_fork_lock);
|
315
|
+
return block;
|
316
|
+
(void)self;
|
317
|
+
}
|
318
|
+
|
319
|
+
// clang-format off
|
320
|
+
/**
|
321
|
+
Sets a block of code to run once a Worker process shuts down (both in single process mode and cluster mode).
|
322
|
+
*/
|
323
|
+
VALUE iodine_on_shutdown_add(VALUE self) {
|
324
|
+
// clang-format on
|
325
|
+
rb_need_block();
|
326
|
+
VALUE block = rb_block_proc();
|
327
|
+
IodineStore.add(block);
|
328
|
+
spn_lock(&iodine_on_shutdown_lock);
|
329
|
+
fio_ls_push(&iodine_on_shutdown_list, (void *)block);
|
330
|
+
spn_unlock(&iodine_on_shutdown_lock);
|
331
|
+
return block;
|
332
|
+
(void)self;
|
333
|
+
}
|
334
|
+
|
335
|
+
/* Runs the before / after fork callbacks (if `before` is true, before runs) */
|
336
|
+
static void iodine_perform_fork_callbacks(uint8_t before) {
|
337
|
+
fio_ls_s *ls = before ? &iodine_before_fork_list : &iodine_after_fork_list;
|
338
|
+
spn_lock_i *lock =
|
339
|
+
before ? &iodine_before_fork_lock : &iodine_after_fork_lock;
|
340
|
+
spn_lock(lock);
|
341
|
+
FIO_LS_FOR(ls, pos) { IodineCaller.call((VALUE)(pos->obj), call_id); }
|
342
|
+
spn_unlock(lock);
|
343
|
+
}
|
344
|
+
|
345
|
+
/* Performs any cleanup before worker dies */
|
346
|
+
void iodine_defer_on_finish(void) {
|
347
|
+
iodine_join_io_thread();
|
348
|
+
/* perform and clear away shutdown Procs */
|
349
|
+
spn_lock(&iodine_on_shutdown_lock);
|
350
|
+
while (fio_ls_any(&iodine_on_shutdown_list)) {
|
351
|
+
void *obj = fio_ls_shift(&iodine_on_shutdown_list);
|
352
|
+
IodineCaller.call((VALUE)(obj), call_id);
|
353
|
+
IodineStore.remove((VALUE)(obj));
|
354
|
+
}
|
355
|
+
spn_unlock(&iodine_on_shutdown_lock);
|
356
|
+
/* clear away forking Procs */
|
357
|
+
spn_lock(&iodine_before_fork_lock);
|
358
|
+
while (fio_ls_any(&iodine_before_fork_list)) {
|
359
|
+
IodineStore.remove((VALUE)fio_ls_shift(&iodine_before_fork_list));
|
360
|
+
}
|
361
|
+
spn_unlock(&iodine_before_fork_lock);
|
362
|
+
|
363
|
+
spn_lock(&iodine_after_fork_lock);
|
364
|
+
while (fio_ls_any(&iodine_after_fork_list)) {
|
365
|
+
IodineStore.remove((VALUE)fio_ls_shift(&iodine_after_fork_list));
|
366
|
+
void *obj = fio_ls_shift(&iodine_after_fork_list);
|
367
|
+
}
|
368
|
+
spn_unlock(&iodine_after_fork_lock);
|
369
|
+
}
|
370
|
+
|
371
|
+
/* *****************************************************************************
|
372
|
+
Add defer API to Iodine
|
373
|
+
***************************************************************************** */
|
374
|
+
|
375
|
+
void iodine_defer_initialize(void) {
|
376
|
+
call_id = rb_intern2("call", 4);
|
377
|
+
rb_define_module_function(IodineModule, "run", iodine_defer_run, 0);
|
378
|
+
rb_define_module_function(IodineModule, "defer", iodine_defer_run, 0);
|
379
|
+
|
380
|
+
rb_define_module_function(IodineModule, "run_after", iodine_defer_run_after,
|
381
|
+
1);
|
382
|
+
rb_define_module_function(IodineModule, "run_every", iodine_defer_run_every,
|
383
|
+
-1);
|
384
|
+
rb_define_module_function(IodineModule, "before_fork", iodine_before_fork_add,
|
385
|
+
0);
|
386
|
+
rb_define_module_function(IodineModule, "after_fork", iodine_after_fork_add,
|
387
|
+
0);
|
388
|
+
rb_define_module_function(IodineModule, "on_shutdown", iodine_on_shutdown_add,
|
389
|
+
0);
|
390
|
+
defer(iodine_start_io_thread, NULL, NULL);
|
391
|
+
}
|