iodine 0.2.17 → 0.3.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/README.md +36 -3
  4. data/bin/config.ru +23 -2
  5. data/bin/http-hello +1 -1
  6. data/bin/ws-shootout +5 -0
  7. data/ext/iodine/defer.c +468 -0
  8. data/ext/iodine/defer.h +105 -0
  9. data/ext/iodine/evio.c +263 -0
  10. data/ext/iodine/evio.h +133 -0
  11. data/ext/iodine/extconf.rb +2 -1
  12. data/ext/iodine/facil.c +958 -0
  13. data/ext/iodine/facil.h +423 -0
  14. data/ext/iodine/http.c +90 -0
  15. data/ext/iodine/http.h +50 -12
  16. data/ext/iodine/http1.c +200 -267
  17. data/ext/iodine/http1.h +17 -26
  18. data/ext/iodine/http1_request.c +81 -0
  19. data/ext/iodine/http1_request.h +58 -0
  20. data/ext/iodine/http1_response.c +403 -0
  21. data/ext/iodine/http1_response.h +90 -0
  22. data/ext/iodine/http1_simple_parser.c +124 -108
  23. data/ext/iodine/http1_simple_parser.h +8 -3
  24. data/ext/iodine/http_request.c +104 -0
  25. data/ext/iodine/http_request.h +58 -102
  26. data/ext/iodine/http_response.c +212 -208
  27. data/ext/iodine/http_response.h +89 -252
  28. data/ext/iodine/iodine_core.c +57 -46
  29. data/ext/iodine/iodine_core.h +3 -1
  30. data/ext/iodine/iodine_http.c +105 -81
  31. data/ext/iodine/iodine_websocket.c +17 -13
  32. data/ext/iodine/iodine_websocket.h +1 -0
  33. data/ext/iodine/rb-call.c +9 -7
  34. data/ext/iodine/{rb-libasync.h → rb-defer.c} +57 -49
  35. data/ext/iodine/rb-rack-io.c +12 -6
  36. data/ext/iodine/rb-rack-io.h +1 -1
  37. data/ext/iodine/rb-registry.c +5 -2
  38. data/ext/iodine/sock.c +1159 -0
  39. data/ext/iodine/{libsock.h → sock.h} +138 -142
  40. data/ext/iodine/spnlock.inc +77 -0
  41. data/ext/iodine/websockets.c +101 -112
  42. data/ext/iodine/websockets.h +38 -19
  43. data/iodine.gemspec +3 -3
  44. data/lib/iodine/version.rb +1 -1
  45. data/lib/rack/handler/iodine.rb +6 -6
  46. metadata +23 -19
  47. data/ext/iodine/http_response_http1.h +0 -382
  48. data/ext/iodine/libasync.c +0 -570
  49. data/ext/iodine/libasync.h +0 -122
  50. data/ext/iodine/libreact.c +0 -350
  51. data/ext/iodine/libreact.h +0 -244
  52. data/ext/iodine/libserver.c +0 -957
  53. data/ext/iodine/libserver.h +0 -481
  54. data/ext/iodine/libsock.c +0 -1025
  55. data/ext/iodine/spnlock.h +0 -243
@@ -1,122 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2016-2017
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 <stdio.h>
14
- #include <stdlib.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
- Returns TRUE (not 0) if there are any pending tasks.
62
- */
63
- int async_any(void);
64
-
65
- /**
66
- Waits for all the present tasks to complete and threads to exist.
67
-
68
- The function won't return unless `async_signal` is called to signal the threads
69
- to stop waiting for new tasks.
70
-
71
- After this function returns, the thread pool will remain active, waiting for new
72
- tasts.
73
-
74
- Unline finish (that uses `join`) this is an **active** wait where the waiting
75
- thread acts as a working thread and performs any pending tasks and then
76
- spinlocks until the active thread count drops to 0.
77
-
78
- Use:
79
-
80
- async_join();
81
-
82
- */
83
- void async_join();
84
-
85
- /**
86
- Signals all the threads to finish up and stop waiting for new tasks.
87
-
88
- Use:
89
-
90
- async_join();
91
-
92
- */
93
- void async_signal();
94
-
95
- /**
96
- Schedules a task to be performed by the thread pool.
97
-
98
- The Task should be a function such as `void task(void *arg)`.
99
-
100
- Use:
101
-
102
- void task(void * arg) { printf("%s", arg); }
103
-
104
- char arg[] = "Demo Task";
105
-
106
- async_run(task, arg);
107
-
108
- */
109
- int async_run(void (*task)(void *), void *arg);
110
-
111
- /**
112
- Same as:
113
-
114
- `async_signal(); async_wait();`
115
- */
116
- #define async_finish() \
117
- { \
118
- async_signal(); \
119
- async_join(); \
120
- }
121
-
122
- #endif /* LIB_ASYNC */
@@ -1,350 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2016-2017
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/epoll.h>
13
- #include <sys/timerfd.h>
14
- #endif
15
- #include <assert.h>
16
- #include <errno.h>
17
- #include <fcntl.h>
18
- #include <netdb.h>
19
- #include <stdio.h>
20
- #include <stdlib.h>
21
- #include <string.h>
22
- #include <sys/socket.h>
23
- #include <sys/types.h>
24
- #include <time.h>
25
- #include <unistd.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) { (void)(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) { (void)(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) {
55
- (void)(uuid);
56
- return 0;
57
- }
58
-
59
- #pragma weak sock_close
60
- void sock_close(intptr_t uuid) {
61
- shutdown(sock_uuid2fd(uuid), SHUT_RDWR);
62
- close(sock_uuid2fd(uuid));
63
- /* this is automatic on epoll... what about kqueue? */
64
- reactor_remove(uuid);
65
- /* call callback */
66
- reactor_on_close(uuid);
67
- }
68
-
69
- /* *****************************************************************************
70
- The main libreact API.
71
- */
72
-
73
- /**
74
- Closes a file descriptor, calling it's callback if it was registered with the
75
- reactor.
76
- */
77
- void reactor_close(intptr_t uuid) {
78
- sock_close(uuid);
79
- return;
80
- }
81
-
82
- /* *****************************************************************************
83
- KQueue implementation.
84
- */
85
- #ifdef EV_SET
86
-
87
- int reactor_add(intptr_t uuid) {
88
- struct kevent chevent[2];
89
- EV_SET(chevent, sock_uuid2fd(uuid), EVFILT_READ,
90
- EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, (void *)uuid);
91
- EV_SET(chevent + 1, sock_uuid2fd(uuid), EVFILT_WRITE,
92
- EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, (void *)uuid);
93
- return kevent(reactor_fd, chevent, 2, NULL, 0, NULL);
94
- }
95
- int reactor_add_timer(intptr_t uuid, long milliseconds) {
96
- struct kevent chevent;
97
- EV_SET(&chevent, sock_uuid2fd(uuid), EVFILT_TIMER, EV_ADD | EV_ENABLE, 0,
98
- milliseconds, (void *)uuid);
99
- return kevent(reactor_fd, &chevent, 1, NULL, 0, NULL);
100
- }
101
-
102
- int reactor_remove(intptr_t uuid) {
103
- struct kevent chevent[2];
104
- EV_SET(chevent, sock_uuid2fd(uuid), EVFILT_READ, EV_DELETE, 0, 0,
105
- (void *)uuid);
106
- EV_SET(chevent + 1, sock_uuid2fd(uuid), EVFILT_WRITE, EV_DELETE, 0, 0,
107
- (void *)uuid);
108
- return kevent(reactor_fd, chevent, 2, NULL, 0, NULL);
109
- }
110
- int reactor_remove_timer(intptr_t uuid) {
111
- struct kevent chevent;
112
- EV_SET(&chevent, sock_uuid2fd(uuid), EVFILT_TIMER, EV_DELETE, 0, 0,
113
- (void *)uuid);
114
- return kevent(reactor_fd, &chevent, 1, NULL, 0, NULL);
115
- }
116
-
117
- /**
118
- epoll requires the timer to be "reset" before repeating. Kqueue requires no such
119
- thing.
120
-
121
- This method promises that the timer will be repeated when running on epoll. This
122
- method is redundent on kqueue.
123
- */
124
- void reactor_reset_timer(intptr_t uuid) { (void)(uuid); } /* EPoll only */
125
-
126
- /**
127
- Creates a timer file descriptor, system dependent.
128
-
129
- Opens a new file decriptor for creating timer events. On BSD this will revert to
130
- an `fileno(tmpfile())` (with error handling) and on Linux it will call
131
- `timerfd_create(CLOCK_MONOTONIC, ...)`.
132
-
133
- Returns -1 on error, otherwise returns the file descriptor.
134
- */
135
- intptr_t reactor_make_timer() {
136
- #ifdef P_tmpdir
137
- char template[] = P_tmpdir "libreact_timer_XXXXXX";
138
- #else
139
- char template[] = "/tmp/libreact_timer_XXXXXX";
140
- #endif
141
- return mkstemp(template);
142
- }
143
-
144
- /* *****************************************************************************
145
- EPoll implementation.
146
- */
147
- #elif defined(EPOLLIN)
148
-
149
- int reactor_add(intptr_t uuid) {
150
- struct epoll_event chevent = {0};
151
- chevent.data.ptr = (void *)uuid;
152
- chevent.events =
153
- EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
154
- return epoll_ctl(reactor_fd, EPOLL_CTL_ADD, sock_uuid2fd(uuid), &chevent);
155
- }
156
- int reactor_add_timer(intptr_t uuid, long milliseconds) {
157
- struct epoll_event chevent;
158
- chevent.data.ptr = (void *)uuid;
159
- chevent.events =
160
- EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
161
- struct itimerspec new_t_data;
162
- new_t_data.it_value.tv_sec = new_t_data.it_interval.tv_sec =
163
- milliseconds / 1000;
164
- new_t_data.it_value.tv_nsec = new_t_data.it_interval.tv_nsec =
165
- (milliseconds % 1000) * 1000000;
166
- timerfd_settime(sock_uuid2fd(uuid), 0, &new_t_data, NULL);
167
- return epoll_ctl(reactor_fd, EPOLL_CTL_ADD, sock_uuid2fd(uuid), &chevent);
168
- }
169
-
170
- int reactor_remove(intptr_t uuid) {
171
- struct epoll_event chevent = {0};
172
- // chevent.data.ptr = (void *)uuid;
173
- // chevent.events =
174
- // EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
175
- return epoll_ctl(reactor_fd, EPOLL_CTL_DEL, sock_uuid2fd(uuid), &chevent);
176
- }
177
- int reactor_remove_timer(intptr_t uuid) {
178
- struct epoll_event chevent = {0};
179
- // chevent.data.ptr = (void *)uuid;
180
- // chevent.events =
181
- // EPOLLOUT | EPOLLIN | EPOLLET | EPOLLERR | EPOLLRDHUP | EPOLLHUP;
182
- return epoll_ctl(reactor_fd, EPOLL_CTL_DEL, sock_uuid2fd(uuid), &chevent);
183
- }
184
-
185
- /**
186
- epoll requires the timer to be "reset" before repeating. Kqueue requires no such
187
- thing.
188
-
189
- This method promises that the timer will be repeated when running on epoll. This
190
- method is redundent on kqueue.
191
- */
192
- void reactor_reset_timer(intptr_t uuid) {
193
- char data[8]; // void * is 8 byte long
194
- if (read(sock_uuid2fd(uuid), &data, 8) < 0)
195
- data[0] = 0;
196
- }
197
- /**
198
- Creates a timer file descriptor, system dependent.
199
-
200
- Opens a new file decriptor for creating timer events. On BSD this will revert to
201
- an `fileno(tmpfile())` (with error handling) and on Linux it will call
202
- `timerfd_create(CLOCK_MONOTONIC, ...)`.
203
-
204
- Returns -1 on error, otherwise returns the file descriptor.
205
- */
206
- intptr_t reactor_make_timer() {
207
- return timerfd_create(CLOCK_MONOTONIC, O_NONBLOCK);
208
- ;
209
- }
210
-
211
- /* *****************************************************************************
212
- This library requires either kqueue or epoll to be available.
213
- Please help us be implementing support for your OS.
214
- */
215
- #else
216
- int reactor_add(intptr_t uuid) { return -1; }
217
- int reactor_add_timer(intptr_t uuid, long milliseconds) { return -1; }
218
-
219
- int reactor_remove(intptr_t uuid) { return -1; }
220
- int reactor_remove_timer(intptr_t uuid) { return -1; }
221
- #error(This library requires either kqueue or epoll to be available. Please help us be implementing support for your OS.)
222
- #endif
223
-
224
- /* *****************************************************************************
225
- The Reactor loop.
226
- */
227
-
228
- /*
229
- define some macros to help us write a cleaner main function.
230
- */
231
-
232
- /* KQueue */
233
- #ifdef EV_SET
234
- /* global timout value for the reactors */
235
- static struct timespec _reactor_timeout = {
236
- .tv_sec = (REACTOR_TICK / 1000),
237
- .tv_nsec = ((REACTOR_TICK % 1000) * 1000000)};
238
- #define _CRAETE_QUEUE_ kqueue()
239
- #define _EVENT_TYPE_ struct kevent
240
- // #define _EVENTS_ ((_EVENT_TYPE_*)(reactor->internal_data.events))
241
- #define _WAIT_FOR_EVENTS_(events) \
242
- kevent(reactor_fd, NULL, 0, (events), REACTOR_MAX_EVENTS, &_reactor_timeout);
243
- #define _GET_FDUUID_(events, _ev_) ((intptr_t)((events)[(_ev_)].udata))
244
- #define _EVENTERROR_(events, _ev_) (events)[(_ev_)].flags &(EV_EOF | EV_ERROR)
245
- #define _EVENTREADY_(events, _ev_) (events)[(_ev_)].filter == EVFILT_WRITE
246
- #define _EVENTDATA_(events, _ev_) \
247
- (events)[(_ev_)].filter == EVFILT_READ || \
248
- (events)[(_ev_)].filter == EVFILT_TIMER
249
-
250
- /* EPoll */
251
- #elif defined(EPOLLIN)
252
- static int const _reactor_timeout = REACTOR_TICK;
253
- #define _CRAETE_QUEUE_ epoll_create1(0)
254
- #define _EVENT_TYPE_ struct epoll_event
255
- // #define _EVENTS_ ((_EVENT_TYPE_*)reactor->internal_data.events)
256
- #define _QUEUE_READY_FLAG_ EPOLLOUT
257
- #define _WAIT_FOR_EVENTS_(events) \
258
- epoll_wait(reactor_fd, (events), REACTOR_MAX_EVENTS, _reactor_timeout)
259
- #define _GET_FDUUID_(events, _ev_) ((intptr_t)((events)[(_ev_)].data.ptr))
260
- #define _EVENTERROR_(events, _ev_) \
261
- ((events)[(_ev_)].events & (~(EPOLLIN | EPOLLOUT)))
262
- #define _EVENTREADY_(_events, _ev_) (_events)[(_ev_)].events &EPOLLOUT
263
- #define _EVENTDATA_(_events, _ev_) (_events)[(_ev_)].events &EPOLLIN
264
-
265
- #else /* no epoll, no kqueue - this is where support ends */
266
- #error(This library requires either kqueue or epoll to be available. Please help us be implementing support for your OS.)
267
- #endif
268
-
269
- /**
270
- Initializes the reactor, making the reactor "live".
271
-
272
- Returns -1 on error, otherwise returns 0.
273
- */
274
- ssize_t reactor_init() {
275
- if (reactor_fd > 0)
276
- return -1;
277
- reactor_fd = _CRAETE_QUEUE_;
278
- return 0;
279
- }
280
-
281
- /**
282
- Closes the reactor, releasing it's resources (except the actual struct Reactor,
283
- which might have been allocated on the stack and should be handled by the
284
- caller).
285
- */
286
- void reactor_stop() {
287
- close(reactor_fd);
288
- reactor_fd = -1;
289
- }
290
-
291
- /* *****************************************************************************
292
- The main Reactor Review function
293
- */
294
-
295
- /**
296
- Reviews any pending events (up to REACTOR_MAX_EVENTS)
297
-
298
- Returns -1 on error, otherwise returns 0.
299
- */
300
- int reactor_review() {
301
- if (reactor_fd < 0)
302
- return -1;
303
- _EVENT_TYPE_ events[REACTOR_MAX_EVENTS];
304
-
305
- /* wait for events and handle them */
306
- int active_count = _WAIT_FOR_EVENTS_(events);
307
- if (active_count > 0) {
308
- for (int i = 0; i < active_count; i++) {
309
- if (_EVENTERROR_(events, i)) {
310
- // errors are hendled as disconnections (on_close)
311
- // printf("on_close for %lu\n", _GET_FDUUID_(events, i));
312
- sock_close(_GET_FDUUID_(events, i));
313
- } else {
314
- // no error, then it's an active event(s)
315
- if (_EVENTREADY_(events, i)) {
316
- // printf("on_ready for %lu\n", _GET_FDUUID_(events, i));
317
- if (sock_flush(_GET_FDUUID_(events, i)) < 0) {
318
- sock_close(_GET_FDUUID_(events, i));
319
- } else {
320
- // printf("on_ready callback for %lu fd(%d)\n",
321
- // _GET_FDUUID_(events, i),
322
- // sock_uuid2fd(_GET_FDUUID_(events, i)));
323
- reactor_on_ready(_GET_FDUUID_(events, i));
324
- }
325
- }
326
- if (_EVENTDATA_(events, i)) {
327
- // printf("on_data callback for %lu fd(%d)\n",
328
- // _GET_FDUUID_(events, i),
329
- // sock_uuid2fd(_GET_FDUUID_(events, i)));
330
- reactor_on_data(_GET_FDUUID_(events, i));
331
- }
332
- }
333
- } // end for loop
334
- } else if (active_count < 0) {
335
- // perror("Please close the reactor, it's dying...");
336
- return -1;
337
- }
338
- return active_count;
339
- }
340
-
341
- // we're done with these
342
- #undef _CRAETE_QUEUE_
343
- #undef _EVENT_TYPE_
344
- #undef _EVENTS
345
- #undef _INIT_TIMEOUT_
346
- #undef _WAIT_FOR_EVENTS_
347
- #undef _GET_FDUUID_
348
- #undef _EVENTERROR_
349
- #undef _EVENTREADY_
350
- #undef _EVENTDATA_