iodine 0.1.21 → 0.2.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.

Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -2
  3. data/.travis.yml +23 -2
  4. data/CHANGELOG.md +9 -2
  5. data/README.md +232 -179
  6. data/Rakefile +13 -1
  7. data/bin/config.ru +63 -0
  8. data/bin/console +6 -0
  9. data/bin/echo +42 -32
  10. data/bin/http-hello +62 -0
  11. data/bin/http-playground +124 -0
  12. data/bin/playground +62 -0
  13. data/bin/poc/Gemfile.lock +23 -0
  14. data/bin/poc/README.md +37 -0
  15. data/bin/poc/config.ru +66 -0
  16. data/bin/poc/gemfile +1 -0
  17. data/bin/poc/www/index.html +57 -0
  18. data/bin/raw-rbhttp +35 -0
  19. data/bin/raw_broadcast +66 -0
  20. data/bin/test_with_faye +40 -0
  21. data/bin/ws-broadcast +108 -0
  22. data/bin/ws-echo +108 -0
  23. data/exe/iodine +59 -0
  24. data/ext/iodine/base64.c +264 -0
  25. data/ext/iodine/base64.h +72 -0
  26. data/ext/iodine/bscrypt-common.h +109 -0
  27. data/ext/iodine/bscrypt.h +49 -0
  28. data/ext/iodine/extconf.rb +41 -0
  29. data/ext/iodine/hex.c +123 -0
  30. data/ext/iodine/hex.h +70 -0
  31. data/ext/iodine/http.c +200 -0
  32. data/ext/iodine/http.h +128 -0
  33. data/ext/iodine/http1.c +402 -0
  34. data/ext/iodine/http1.h +56 -0
  35. data/ext/iodine/http1_simple_parser.c +473 -0
  36. data/ext/iodine/http1_simple_parser.h +59 -0
  37. data/ext/iodine/http_request.h +128 -0
  38. data/ext/iodine/http_response.c +1606 -0
  39. data/ext/iodine/http_response.h +393 -0
  40. data/ext/iodine/http_response_http1.h +374 -0
  41. data/ext/iodine/iodine_core.c +641 -0
  42. data/ext/iodine/iodine_core.h +70 -0
  43. data/ext/iodine/iodine_http.c +615 -0
  44. data/ext/iodine/iodine_http.h +19 -0
  45. data/ext/iodine/iodine_websocket.c +430 -0
  46. data/ext/iodine/iodine_websocket.h +21 -0
  47. data/ext/iodine/libasync.c +552 -0
  48. data/ext/iodine/libasync.h +117 -0
  49. data/ext/iodine/libreact.c +347 -0
  50. data/ext/iodine/libreact.h +244 -0
  51. data/ext/iodine/libserver.c +912 -0
  52. data/ext/iodine/libserver.h +435 -0
  53. data/ext/iodine/libsock.c +950 -0
  54. data/ext/iodine/libsock.h +478 -0
  55. data/ext/iodine/misc.c +181 -0
  56. data/ext/iodine/misc.h +76 -0
  57. data/ext/iodine/random.c +193 -0
  58. data/ext/iodine/random.h +48 -0
  59. data/ext/iodine/rb-call.c +127 -0
  60. data/ext/iodine/rb-call.h +60 -0
  61. data/ext/iodine/rb-libasync.h +79 -0
  62. data/ext/iodine/rb-rack-io.c +389 -0
  63. data/ext/iodine/rb-rack-io.h +17 -0
  64. data/ext/iodine/rb-registry.c +213 -0
  65. data/ext/iodine/rb-registry.h +33 -0
  66. data/ext/iodine/sha1.c +359 -0
  67. data/ext/iodine/sha1.h +85 -0
  68. data/ext/iodine/sha2.c +825 -0
  69. data/ext/iodine/sha2.h +138 -0
  70. data/ext/iodine/siphash.c +136 -0
  71. data/ext/iodine/siphash.h +15 -0
  72. data/ext/iodine/spnlock.h +235 -0
  73. data/ext/iodine/websockets.c +696 -0
  74. data/ext/iodine/websockets.h +120 -0
  75. data/ext/iodine/xor-crypt.c +189 -0
  76. data/ext/iodine/xor-crypt.h +107 -0
  77. data/iodine.gemspec +25 -18
  78. data/lib/iodine.rb +57 -58
  79. data/lib/iodine/http.rb +0 -189
  80. data/lib/iodine/protocol.rb +36 -245
  81. data/lib/iodine/version.rb +1 -1
  82. data/lib/rack/handler/iodine.rb +145 -2
  83. metadata +115 -37
  84. data/bin/core_http_test +0 -51
  85. data/bin/em playground +0 -56
  86. data/bin/hello_world +0 -75
  87. data/bin/setup +0 -7
  88. data/lib/iodine/client.rb +0 -5
  89. data/lib/iodine/core.rb +0 -102
  90. data/lib/iodine/core_init.rb +0 -143
  91. data/lib/iodine/http/hpack.rb +0 -553
  92. data/lib/iodine/http/http1.rb +0 -251
  93. data/lib/iodine/http/http2.rb +0 -507
  94. data/lib/iodine/http/rack_support.rb +0 -108
  95. data/lib/iodine/http/request.rb +0 -462
  96. data/lib/iodine/http/response.rb +0 -474
  97. data/lib/iodine/http/session.rb +0 -143
  98. data/lib/iodine/http/websocket_client.rb +0 -335
  99. data/lib/iodine/http/websocket_handler.rb +0 -101
  100. data/lib/iodine/http/websockets.rb +0 -336
  101. data/lib/iodine/io.rb +0 -56
  102. data/lib/iodine/logging.rb +0 -46
  103. data/lib/iodine/settings.rb +0 -158
  104. data/lib/iodine/ssl_connector.rb +0 -48
  105. data/lib/iodine/timers.rb +0 -95
@@ -0,0 +1,117 @@
1
+ /*
2
+ copyright: Boaz segev, 2016
3
+ license: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #ifndef LIB_ASYNC
8
+ #define LIB_ASYNC "0.4.0"
9
+ #define LIB_ASYNC_VERSION_MAJOR 0
10
+ #define LIB_ASYNC_VERSION_MINOR 4
11
+ #define LIB_ASYNC_VERSION_PATCH 0
12
+
13
+ #include <stdlib.h>
14
+ #include <stdio.h>
15
+
16
+ #ifdef DEBUG
17
+ // prints out testing and benchmarking data
18
+ void async_test_library_speed(void);
19
+ #endif
20
+
21
+ /** \file
22
+ This is an easy to use **global** thread pool library. Once the thread pool was
23
+ initiated it makes running tasks very simple. i.e.:
24
+
25
+ async_start(4); // 4 worker threads
26
+ async_run(task, arg);
27
+ async_finish(); // waits for tasks and releases threads.
28
+
29
+ Please note, this library isn't fork-friendly - fork **before** you create the
30
+ thread pool. In general, mixing `fork` with multi-threading isn't safe nor
31
+ trivial - always fork before multi-threading.
32
+ */
33
+
34
+ /**
35
+ Starts running the global thread pool. Use:
36
+
37
+ async_start(8, 0);
38
+
39
+ The `use_sentinal` variable protects threads from crashing and produces error
40
+ reports. It isn't effective against all errors, but it should protect against
41
+ some.
42
+
43
+ */
44
+ ssize_t async_start(size_t threads);
45
+
46
+ /**
47
+ Use `async_join` instead.
48
+
49
+ Performs tasks until the task queue is empty. An empty task queue does NOT mean
50
+ all the tasks have completed, since some other threads might be running tasks
51
+ that have yet to complete (and these tasks might schedule new tasks as well).
52
+
53
+ Use:
54
+
55
+ async_perform();
56
+
57
+ */
58
+ void async_perform();
59
+
60
+ /**
61
+ Waits for all the present tasks to complete and threads to exist.
62
+
63
+ The function won't return unless `async_signal` is called to signal the threads
64
+ to stop waiting for new tasks.
65
+
66
+ After this function returns, the thread pool will remain active, waiting for new
67
+ tasts.
68
+
69
+ Unline finish (that uses `join`) this is an **active** wait where the waiting
70
+ thread acts as a working thread and performs any pending tasks and then
71
+ spinlocks until the active thread count drops to 0.
72
+
73
+ Use:
74
+
75
+ async_join();
76
+
77
+ */
78
+ void async_join();
79
+
80
+ /**
81
+ Signals all the threads to finish up and stop waiting for new tasks.
82
+
83
+ Use:
84
+
85
+ async_join();
86
+
87
+ */
88
+ void async_signal();
89
+
90
+ /**
91
+ Schedules a task to be performed by the thread pool.
92
+
93
+ The Task should be a function such as `void task(void *arg)`.
94
+
95
+ Use:
96
+
97
+ void task(void * arg) { printf("%s", arg); }
98
+
99
+ char arg[] = "Demo Task";
100
+
101
+ async_run(task, arg);
102
+
103
+ */
104
+ int async_run(void (*task)(void*), void* arg);
105
+
106
+ /**
107
+ Same as:
108
+
109
+ `async_signal(); async_wait();`
110
+ */
111
+ #define async_finish() \
112
+ { \
113
+ async_signal(); \
114
+ async_join(); \
115
+ }
116
+
117
+ #endif /* LIB_ASYNC */
@@ -0,0 +1,347 @@
1
+ /*
2
+ copyright: Boaz segev, 2016
3
+ license: MIT
4
+
5
+ Feel free to copy, use and enjoy according to the license provided.
6
+ */
7
+ #include "libreact.h"
8
+
9
+ #if !defined(__linux__) && !defined(__CYGWIN__)
10
+ #include <sys/event.h>
11
+ #else
12
+ #include <sys/timerfd.h>
13
+ #include <sys/epoll.h>
14
+ #endif
15
+ #include <time.h>
16
+ #include <assert.h>
17
+ #include <unistd.h>
18
+ #include <fcntl.h>
19
+ #include <errno.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+ #include <netdb.h>
24
+ #include <sys/types.h>
25
+ #include <sys/socket.h>
26
+
27
+ /* The (sadly, global) reactor fd */
28
+ static int reactor_fd = -1;
29
+
30
+ /* an inner helper function that removes and adds events */
31
+
32
+ /* *****************************************************************************
33
+ Callbacks
34
+ */
35
+
36
+ #pragma weak reactor_on_close
37
+ void reactor_on_close(intptr_t uuid) {}
38
+
39
+ #pragma weak reactor_on_data
40
+ void reactor_on_data(intptr_t uuid) {
41
+ char data[1024];
42
+ while (read(sock_uuid2fd(uuid), data, 1024) > 0)
43
+ ;
44
+ }
45
+
46
+ #pragma weak reactor_on_ready
47
+ void reactor_on_ready(intptr_t uuid) {}
48
+
49
+ /* *****************************************************************************
50
+ Integrate the `libsock` library if exists.
51
+ */
52
+
53
+ #pragma weak sock_flush
54
+ ssize_t sock_flush(intptr_t uuid) { return 0; }
55
+
56
+ #pragma weak sock_close
57
+ void sock_close(intptr_t uuid) {
58
+ shutdown(sock_uuid2fd(uuid), SHUT_RDWR);
59
+ close(sock_uuid2fd(uuid));
60
+ /* this is automatic on epoll... what about kqueue? */
61
+ reactor_remove(uuid);
62
+ /* call callback */
63
+ reactor_on_close(uuid);
64
+ }
65
+
66
+ /* *****************************************************************************
67
+ The main libreact API.
68
+ */
69
+
70
+ /**
71
+ Closes a file descriptor, calling it's callback if it was registered with the
72
+ reactor.
73
+ */
74
+ void reactor_close(intptr_t uuid) {
75
+ sock_close(uuid);
76
+ return;
77
+ }
78
+
79
+ /* *****************************************************************************
80
+ KQueue implementation.
81
+ */
82
+ #ifdef EV_SET
83
+
84
+ int reactor_add(intptr_t uuid) {
85
+ struct kevent chevent[2];
86
+ EV_SET(chevent, sock_uuid2fd(uuid), EVFILT_READ,
87
+ EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, (void *)uuid);
88
+ EV_SET(chevent + 1, sock_uuid2fd(uuid), EVFILT_WRITE,
89
+ EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, (void *)uuid);
90
+ return kevent(reactor_fd, chevent, 2, NULL, 0, NULL);
91
+ }
92
+ int reactor_add_timer(intptr_t uuid, long milliseconds) {
93
+ struct kevent chevent;
94
+ EV_SET(&chevent, sock_uuid2fd(uuid), EVFILT_TIMER, EV_ADD | EV_ENABLE, 0,
95
+ milliseconds, (void *)uuid);
96
+ return kevent(reactor_fd, &chevent, 1, NULL, 0, NULL);
97
+ }
98
+
99
+ int reactor_remove(intptr_t uuid) {
100
+ struct kevent chevent[2];
101
+ EV_SET(chevent, sock_uuid2fd(uuid), EVFILT_READ, EV_DELETE, 0, 0,
102
+ (void *)uuid);
103
+ EV_SET(chevent + 1, sock_uuid2fd(uuid), EVFILT_WRITE, EV_DELETE, 0, 0,
104
+ (void *)uuid);
105
+ return kevent(reactor_fd, chevent, 2, NULL, 0, NULL);
106
+ }
107
+ int reactor_remove_timer(intptr_t uuid) {
108
+ struct kevent chevent;
109
+ EV_SET(&chevent, sock_uuid2fd(uuid), EVFILT_TIMER, EV_DELETE, 0, 0,
110
+ (void *)uuid);
111
+ return kevent(reactor_fd, &chevent, 1, NULL, 0, NULL);
112
+ }
113
+
114
+ /**
115
+ epoll requires the timer to be "reset" before repeating. Kqueue requires no such
116
+ thing.
117
+
118
+ This method promises that the timer will be repeated when running on epoll. This
119
+ method is redundent on kqueue.
120
+ */
121
+ void reactor_reset_timer(intptr_t uuid) {} /* EPoll only */
122
+
123
+ /**
124
+ Creates a timer file descriptor, system dependent.
125
+
126
+ Opens a new file decriptor for creating timer events. On BSD this will revert to
127
+ an `fileno(tmpfile())` (with error handling) and on Linux it will call
128
+ `timerfd_create(CLOCK_MONOTONIC, ...)`.
129
+
130
+ Returns -1 on error, otherwise returns the file descriptor.
131
+ */
132
+ intptr_t reactor_make_timer() {
133
+ #ifdef P_tmpdir
134
+ char template[] = P_tmpdir "libreact_timer_XXXXXX";
135
+ #else
136
+ char template[] = "/tmp/libreact_timer_XXXXXX";
137
+ #endif
138
+ return mkstemp(template);
139
+ }
140
+
141
+ /* *****************************************************************************
142
+ EPoll implementation.
143
+ */
144
+ #elif defined(EPOLLIN)
145
+
146
+ int reactor_add(intptr_t uuid) {
147
+ struct epoll_event chevent = {0};
148
+ chevent.data.ptr = (void *)uuid;
149
+ chevent.events =
150
+ EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
151
+ return epoll_ctl(reactor_fd, EPOLL_CTL_ADD, sock_uuid2fd(uuid), &chevent);
152
+ }
153
+ int reactor_add_timer(intptr_t uuid, long milliseconds) {
154
+ struct epoll_event chevent;
155
+ chevent.data.ptr = (void *)uuid;
156
+ chevent.events =
157
+ EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
158
+ struct itimerspec new_t_data;
159
+ new_t_data.it_value.tv_sec = new_t_data.it_interval.tv_sec =
160
+ milliseconds / 1000;
161
+ new_t_data.it_value.tv_nsec = new_t_data.it_interval.tv_nsec =
162
+ (milliseconds % 1000) * 1000000;
163
+ timerfd_settime(sock_uuid2fd(uuid), 0, &new_t_data, NULL);
164
+ return epoll_ctl(reactor_fd, EPOLL_CTL_ADD, sock_uuid2fd(uuid), &chevent);
165
+ }
166
+
167
+ int reactor_remove(intptr_t uuid) {
168
+ struct epoll_event chevent = {0};
169
+ // chevent.data.ptr = (void *)uuid;
170
+ // chevent.events =
171
+ // EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
172
+ return epoll_ctl(reactor_fd, EPOLL_CTL_DEL, sock_uuid2fd(uuid), &chevent);
173
+ }
174
+ int reactor_remove_timer(intptr_t uuid) {
175
+ struct epoll_event chevent = {0};
176
+ // chevent.data.ptr = (void *)uuid;
177
+ // chevent.events =
178
+ // EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
179
+ return epoll_ctl(reactor_fd, EPOLL_CTL_DEL, sock_uuid2fd(uuid), &chevent);
180
+ }
181
+
182
+ /**
183
+ epoll requires the timer to be "reset" before repeating. Kqueue requires no such
184
+ thing.
185
+
186
+ This method promises that the timer will be repeated when running on epoll. This
187
+ method is redundent on kqueue.
188
+ */
189
+ void reactor_reset_timer(intptr_t uuid) {
190
+ char data[8]; // void * is 8 byte long
191
+ if (read(sock_uuid2fd(uuid), &data, 8) < 0)
192
+ data[0] = 0;
193
+ }
194
+ /**
195
+ Creates a timer file descriptor, system dependent.
196
+
197
+ Opens a new file decriptor for creating timer events. On BSD this will revert to
198
+ an `fileno(tmpfile())` (with error handling) and on Linux it will call
199
+ `timerfd_create(CLOCK_MONOTONIC, ...)`.
200
+
201
+ Returns -1 on error, otherwise returns the file descriptor.
202
+ */
203
+ intptr_t reactor_make_timer() {
204
+ return timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
205
+ ;
206
+ }
207
+
208
+ /* *****************************************************************************
209
+ This library requires either kqueue or epoll to be available.
210
+ Please help us be implementing support for your OS.
211
+ */
212
+ #else
213
+ int reactor_add(intptr_t uuid) { return -1; }
214
+ int reactor_add_timer(intptr_t uuid, long milliseconds) { return -1; }
215
+
216
+ int reactor_remove(intptr_t uuid) { return -1; }
217
+ int reactor_remove_timer(intptr_t uuid) { return -1; }
218
+ #error(This library requires either kqueue or epoll to be available. Please help us be implementing support for your OS.)
219
+ #endif
220
+
221
+ /* *****************************************************************************
222
+ The Reactor loop.
223
+ */
224
+
225
+ /*
226
+ define some macros to help us write a cleaner main function.
227
+ */
228
+
229
+ /* KQueue */
230
+ #ifdef EV_SET
231
+ /* global timout value for the reactors */
232
+ static struct timespec _reactor_timeout = {
233
+ .tv_sec = (REACTOR_TICK / 1000),
234
+ .tv_nsec = ((REACTOR_TICK % 1000) * 1000000)};
235
+ #define _CRAETE_QUEUE_ kqueue()
236
+ #define _EVENT_TYPE_ struct kevent
237
+ // #define _EVENTS_ ((_EVENT_TYPE_*)(reactor->internal_data.events))
238
+ #define _WAIT_FOR_EVENTS_(events) \
239
+ kevent(reactor_fd, NULL, 0, (events), REACTOR_MAX_EVENTS, &_reactor_timeout);
240
+ #define _GET_FDUUID_(events, _ev_) ((intptr_t)((events)[(_ev_)].udata))
241
+ #define _EVENTERROR_(events, _ev_) (events)[(_ev_)].flags &(EV_EOF | EV_ERROR)
242
+ #define _EVENTREADY_(events, _ev_) (events)[(_ev_)].filter == EVFILT_WRITE
243
+ #define _EVENTDATA_(events, _ev_) \
244
+ (events)[(_ev_)].filter == EVFILT_READ || \
245
+ (events)[(_ev_)].filter == EVFILT_TIMER
246
+
247
+ /* EPoll */
248
+ #elif defined(EPOLLIN)
249
+ static int const _reactor_timeout = REACTOR_TICK;
250
+ #define _CRAETE_QUEUE_ epoll_create1(0)
251
+ #define _EVENT_TYPE_ struct epoll_event
252
+ // #define _EVENTS_ ((_EVENT_TYPE_*)reactor->internal_data.events)
253
+ #define _QUEUE_READY_FLAG_ EPOLLOUT
254
+ #define _WAIT_FOR_EVENTS_(events) \
255
+ epoll_wait(reactor_fd, (events), REACTOR_MAX_EVENTS, _reactor_timeout)
256
+ #define _GET_FDUUID_(events, _ev_) ((intptr_t)((events)[(_ev_)].data.ptr))
257
+ #define _EVENTERROR_(events, _ev_) \
258
+ ((events)[(_ev_)].events & (~(EPOLLIN | EPOLLOUT)))
259
+ #define _EVENTREADY_(_events, _ev_) (_events)[(_ev_)].events &EPOLLOUT
260
+ #define _EVENTDATA_(_events, _ev_) (_events)[(_ev_)].events &EPOLLIN
261
+
262
+ #else /* no epoll, no kqueue - this is where support ends */
263
+ #error(This library requires either kqueue or epoll to be available. Please help us be implementing support for your OS.)
264
+ #endif
265
+
266
+ /**
267
+ Initializes the reactor, making the reactor "live".
268
+
269
+ Returns -1 on error, otherwise returns 0.
270
+ */
271
+ ssize_t reactor_init() {
272
+ if (reactor_fd > 0)
273
+ return -1;
274
+ reactor_fd = _CRAETE_QUEUE_;
275
+ return 0;
276
+ }
277
+
278
+ /**
279
+ Closes the reactor, releasing it's resources (except the actual struct Reactor,
280
+ which might have been allocated on the stack and should be handled by the
281
+ caller).
282
+ */
283
+ void reactor_stop() {
284
+ close(reactor_fd);
285
+ reactor_fd = -1;
286
+ }
287
+
288
+ /* *****************************************************************************
289
+ The main Reactor Review function
290
+ */
291
+
292
+ /**
293
+ Reviews any pending events (up to REACTOR_MAX_EVENTS)
294
+
295
+ Returns -1 on error, otherwise returns 0.
296
+ */
297
+ int reactor_review() {
298
+ if (reactor_fd < 0)
299
+ return -1;
300
+ _EVENT_TYPE_ events[REACTOR_MAX_EVENTS];
301
+
302
+ /* wait for events and handle them */
303
+ int active_count = _WAIT_FOR_EVENTS_(events);
304
+ if (active_count > 0) {
305
+ for (int i = 0; i < active_count; i++) {
306
+ if (_EVENTERROR_(events, i)) {
307
+ // errors are hendled as disconnections (on_close)
308
+ // printf("on_close for %lu\n", _GET_FDUUID_(events, i));
309
+ sock_close(_GET_FDUUID_(events, i));
310
+ } else {
311
+ // no error, then it's an active event(s)
312
+ if (_EVENTREADY_(events, i)) {
313
+ // printf("on_ready for %lu\n", _GET_FDUUID_(events, i));
314
+ if (sock_flush(_GET_FDUUID_(events, i)) < 0) {
315
+ sock_close(_GET_FDUUID_(events, i));
316
+ } else {
317
+ // printf("on_ready callback for %lu fd(%d)\n",
318
+ // _GET_FDUUID_(events, i),
319
+ // sock_uuid2fd(_GET_FDUUID_(events, i)));
320
+ reactor_on_ready(_GET_FDUUID_(events, i));
321
+ }
322
+ }
323
+ if (_EVENTDATA_(events, i)) {
324
+ // printf("on_data callback for %lu fd(%d)\n",
325
+ // _GET_FDUUID_(events, i),
326
+ // sock_uuid2fd(_GET_FDUUID_(events, i)));
327
+ reactor_on_data(_GET_FDUUID_(events, i));
328
+ }
329
+ }
330
+ } // end for loop
331
+ } else if (active_count < 0) {
332
+ // perror("Please close the reactor, it's dying...");
333
+ return -1;
334
+ }
335
+ return active_count;
336
+ }
337
+
338
+ // we're done with these
339
+ #undef _CRAETE_QUEUE_
340
+ #undef _EVENT_TYPE_
341
+ #undef _EVENTS
342
+ #undef _INIT_TIMEOUT_
343
+ #undef _WAIT_FOR_EVENTS_
344
+ #undef _GET_FDUUID_
345
+ #undef _EVENTERROR_
346
+ #undef _EVENTREADY_
347
+ #undef _EVENTDATA_