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,211 +1,78 @@
1
- /*
2
- Copyright: Boaz segev, 2016-2017
3
- License: MIT
1
+ #ifndef H_HTTP_RESPONSE_H
2
+ #define H_HTTP_RESPONSE_H
4
3
 
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
- #ifndef HTTP_RESPONSE
8
- /**
9
- The HttpResponse library
10
- ========================
11
-
12
- This library helps us to write HTTP valid responses, even when we do not know
13
- the internals of the HTTP protocol.
14
-
15
- The response object allows us to easily update the response status (all
16
- responses start with the default 200 "OK" status code), write headers and cookie
17
- data to the header buffer and send the response's body.
18
-
19
- The response object also allows us to easily update the body size and send body
20
- data or open files (which will be automatically closed once sending is done).
21
-
22
- As example flow for the response could be:
23
-
24
- ; // get an initialized HttpRequest object
25
- struct HttpRequest * response = HttpResponse.create(request);
26
- ; // ... write headers and body, i.e.
27
- HttpResponse.write_header_cstr(response, "X-Data", "my data");
28
- HttpResponse.write_body(response, "Hello World!\r\n", 14);
29
- ; // release the object
30
- HttpResponse.destroy(response);
31
-
32
-
33
- --
34
- Thread-safety:
35
-
36
- The response object and it's API are NOT thread-safe (it is assumed that no two
37
- threads handle the same response at the same time).
38
-
39
- Also, the response object will link itself to a libsock buffer packet, so it
40
- should be created and dispatched during the same event - `sock_packet_s` objects
41
- shouldn't be held across events or for a period of time... In other words:
42
-
43
- **Create the response object only when you are ready to send a response**.
44
-
45
- ---
46
- Misc notes:
47
- The response header's buffer size is limited and too many headers will fail the
48
- response.
49
-
50
- The response object allows us to easily update the response status (all
51
- responses start with the default 200 "OK" status code), write headers and write
52
- cookie data to the header buffer.
53
-
54
- The response object also allows us to easily update the body size and send body
55
- data or open files (which will be automatically closed once sending is done).
56
-
57
- The response does NOT support chuncked encoding.
58
-
59
- The following is the response API container, use:
60
-
61
- struct HttpRequest * response = HttpResponse.create(request);
62
-
63
-
64
- ---
65
- Performance:
66
-
67
- A note about using this library with the HTTP/1 protocol family (if this library
68
- supports HTTP/2, in the future, the use of the response object will be required,
69
- as it might not be possible to handle the response manually):
70
-
71
- Since this library safeguards against certain mistakes and manages an
72
- internal header buffer, it comes at a performance cost (it adds a layer of data
73
- copying to the headers).
74
-
75
- This cost is mitigated by the optional use of a response object pool, so that it
76
- actually saves us from using `malloc` for the headers - for some cases this is
77
- faster.
78
-
79
- In my performance tests, the greatest issue is this: spliting the headers from
80
- the body means that the socket's buffer is under-utilized on the first call to
81
- `send`, while sending the headers. While other operations incure minor costs,
82
- this is the actual reason for degraded performance when using this library.
83
-
84
- The order of performance should be considered as follows:
85
-
86
- 1. Destructive: Overwriting the request's header buffer with both the response
87
- headers and the response data (small responses). Sending the data through the
88
- socket using the `Server.write` function.
89
-
90
- 2. Using malloc to allocate enough memory for both the response's headers AND
91
- it's body. Sending the data through the socket using the `Server.write_move`
92
- function.
93
-
94
- 3. Using the HttpResponse object to send the response.
95
-
96
- Network issues and response properties might influence the order of performant
97
- solutions.
98
- */
99
- #define HTTP_RESPONSE
100
- #include "http.h"
101
4
  #include "http_request.h"
5
+ #include <stdio.h>
6
+ #include <time.h>
102
7
 
103
8
  typedef struct {
104
- /**
105
- The body's response length.
106
-
107
- If this isn't set manually, the first call to
108
- `HttpResponse.write_body` (and friends) will set the length to the length
109
- being written (which might be less then the total data sent, if the sending is
110
- fragmented).
111
-
112
- Set the value to -1 to force the HttpResponse not to write the
113
- `Content-Length` header.
114
- */
9
+ /** The protocol version family (HTTP/1.1 / HTTP/2 etc'). */
10
+ enum HTTP_VERSION http_version;
11
+ /** Will be set to TRUE (1) once the headers were sent. */
12
+ unsigned headers_sent : 1;
13
+ /** Set to true when the "Date" header is written to the buffer. */
14
+ unsigned date_written : 1;
15
+ /** Set to true when the "Connection" header is written to the buffer. */
16
+ unsigned connection_written : 1;
17
+ /** Set to true when the "Content-Length" header is written to the buffer. */
18
+ unsigned content_length_written : 1;
19
+ /** Set to true in order to close the connection once the response was sent.
20
+ */
21
+ unsigned should_close : 1;
22
+ /** Internally used by the logging API. */
23
+ unsigned logged : 1;
24
+ /** Set this value to TRUE to indicate the request pointer should be freed. */
25
+ unsigned request_dupped : 1;
26
+ /** The response status */
27
+ uint16_t status;
28
+ /** The socket UUID for the response. */
29
+ intptr_t fd;
30
+ /** The originating request. */
31
+ http_request_s *request;
32
+ /** The body's response length.
33
+ *
34
+ * If this isn't set manually, the first call to `http_response_write_body`
35
+ * (and friends) will set the length to the length being written (which might
36
+ * be less then the total data sent, if the sending is fragmented).
37
+ *
38
+ * The value to -1 to prevents `http_response_s` from sending the
39
+ * `Content-Length` header.
40
+ */
115
41
  ssize_t content_length;
116
- /**
117
- The HTTP date for the response (in seconds since epoche).
118
-
119
- Defaults to now (approximately, not exactly, uses cached data).
120
-
121
- The date will be automatically formatted to match the HTTP protocol
122
- specifications. It is better to avoid setting the "Date" header manualy.
123
- */
42
+ /** The HTTP Date for the response (in seconds since epoche).
43
+ *
44
+ * Defaults to now (approximately, not exactly, uses cached time data).
45
+ *
46
+ * The date will be automatically formatted to match the HTTP protocol
47
+ * specifications.
48
+ *
49
+ * It is better to avoid setting the "Date" header manualy.
50
+ */
124
51
  time_t date;
125
- /**
126
- The HTTP date for the response (in seconds since epoche).
127
-
128
- Defaults to now (approximately, not exactly, uses cached data).
129
-
130
- The date will be automatically formatted to match the HTTP protocol
131
- specifications. It is better to avoid setting the "Date" header manualy.
132
- */
52
+ /** The HTTP Last-Modified date for the response (in seconds since epoche).
53
+ *
54
+ * Defaults to now (approximately, not exactly, uses cached time data).
55
+ *
56
+ * The date will be automatically formatted to match the HTTP protocol
57
+ * specifications.
58
+ *
59
+ * It is better to avoid setting the "Last-Modified" header manualy.
60
+ */
133
61
  time_t last_modified;
134
62
  /**
135
- The response status
63
+ Internally used by the logging API.
136
64
  */
137
- uint16_t status;
138
- /**
139
- Metadata about the response's state - don't edit this data (except the opaque
140
- data, if needed).
141
- */
142
- struct {
143
- /**
144
- The request object to which this response is "responding".
145
- */
146
- http_request_s *request;
147
- /**
148
- The libsock fd UUID.
149
- */
150
- intptr_t fd;
151
- /**
152
- A `libsock` buffer packet used for header data (to avoid double copy).
153
- */
154
- sock_packet_s *packet;
155
- /**
156
- A pointer to the header's writing position.
157
- */
158
- char *headers_pos;
159
- /**
160
- Internally used by the logging API.
161
- */
162
- clock_t clock_start;
163
- /**
164
- HTTP protocol version identifier.
165
- */
166
- uint8_t version;
167
- /**
168
- Set to true once the headers were sent.
169
- */
170
- unsigned headers_sent : 1;
171
- /**
172
- Set to true when the "Date" header is written to the buffer.
173
- */
174
- unsigned date_written : 1;
175
- /**
176
- Set to true when the "Connection" header is written to the buffer.
177
- */
178
- unsigned connection_written : 1;
179
- /**
180
- Set to true when the "Content-Length" header is written to the buffer.
181
- */
182
- unsigned content_length_written : 1;
183
- /**
184
- Set to true in order to close the connection once the response was sent.
185
- */
186
- unsigned should_close : 1;
187
- /**
188
- Internally used by the logging API.
189
- */
190
- unsigned logged : 1;
191
- /**
192
- Reserved for future use.
193
- */
194
- unsigned rsrv : 2;
195
-
196
- } metadata;
197
-
65
+ clock_t clock_start;
198
66
  } http_response_s;
199
67
 
200
68
  /**
201
69
  The struct HttpCookie is a helper for seting cookie data.
202
70
 
203
- This struct is used together with the `HttpResponse.set_cookie`. i.e.:
71
+ This struct is used together with the `http_response_set_cookie`. i.e.:
204
72
 
205
- HttpResponse.set_cookie(response, (struct HttpCookie){
73
+ http_response_set_cookie(response,
206
74
  .name = "my_cookie",
207
- .value = "data"
208
- });
75
+ .value = "data" );
209
76
 
210
77
  */
211
78
  typedef struct {
@@ -233,28 +100,21 @@ typedef struct {
233
100
  unsigned http_only : 1;
234
101
  } http_cookie_s;
235
102
 
236
- /**
237
- Initializes a response object with the request object. This function assumes the
238
- response object memory is garbage and might have been stack-allocated.
103
+ /* *****************************************************************************
104
+ Initialization
105
+ ***************************************************************************** */
239
106
 
240
- Notice that the `http_request_s` pointer must point at a valid request object
241
- and that the request object must remain valid until the response had been
242
- completed.
107
+ /** Creates / allocates a protocol version's response object. */
108
+ http_response_s *http_response_create(http_request_s *request);
109
+ /** Destroys the response object. No data is sent.*/
110
+ void http_response_destroy(http_response_s *);
111
+ /** Sends the data and destroys the response object.*/
112
+ void http_response_finish(http_response_s *);
243
113
 
244
- Hangs on failuer (waits for available resources).
245
- */
246
- http_response_s http_response_init(http_request_s *request);
247
- /**
248
- Releases any resources held by the response object (doesn't release the response
249
- object itself, which might have been allocated on the stack).
114
+ /* *****************************************************************************
115
+ Writing data to the response object
116
+ ***************************************************************************** */
250
117
 
251
- This function assumes the response object might have been stack-allocated.
252
- */
253
- void http_response_destroy(http_response_s *response);
254
- /** Gets a response status, as a string. */
255
- const char *http_response_status_str(uint16_t status);
256
- /** Gets the mime-type string (C string) associated with the file extension. */
257
- const char *http_response_ext2mime(const char *ext);
258
118
  /**
259
119
  Writes a header to the response. This function writes only the requested
260
120
  number of bytes from the header name and the requested number of bytes from
@@ -267,9 +127,9 @@ cannot be sent), the function will return -1.
267
127
 
268
128
  On success, the function returns 0.
269
129
  */
270
- int http_response_write_header(http_response_s *, http_headers_s header);
130
+ int http_response_write_header_fn(http_response_s *, http_header_s header);
271
131
  #define http_response_write_header(response, ...) \
272
- http_response_write_header(response, (http_headers_s){__VA_ARGS__})
132
+ http_response_write_header_fn(response, (http_header_s){__VA_ARGS__})
273
133
 
274
134
  /**
275
135
  Set / Delete a cookie using this helper function.
@@ -303,18 +163,6 @@ int http_response_set_cookie(http_response_s *, http_cookie_s);
303
163
  #define http_response_set_cookie(response, ...) \
304
164
  http_response_set_cookie(response, (http_cookie_s){__VA_ARGS__})
305
165
 
306
- /**
307
- Indicates that any pending data (i.e. unsent headers) should be sent and that no
308
- more use of the response object will be made. This will also release any
309
- resources aquired when the response object was initialized, similar to the
310
- `http_response_destroy` function.
311
-
312
- If logging was initiated and hadn't been performed, it will be performed.
313
-
314
- If the connection was already closed, the function will return -1. On success,
315
- the function returns 0.
316
- */
317
- void http_response_finish(http_response_s *);
318
166
  /**
319
167
  Sends the headers (if they weren't previously sent) and writes the data to the
320
168
  underlying socket.
@@ -327,33 +175,19 @@ the function returns 0.
327
175
  int http_response_write_body(http_response_s *, const char *body,
328
176
  size_t length);
329
177
 
330
- // /**
331
- // REVIEW: IS THIS APPLICABLE FOR HTTP/2 AS WELL? this must be a unified API.
332
- //
333
- // Sends the headers (if they weren't previously sent) and writes the data to
334
- // the
335
- // underlying socket.
336
- //
337
- // The server's outgoing buffer will take ownership of the body and free it's
338
- // memory using `free` once the data was sent.
339
- //
340
- // If the connection was already closed, the function will return -1. On
341
- // success,
342
- // the function returns 0.
343
- // */
344
- // int http_response_write_body_move(http_response_s*,
345
- // const char* body,
346
- // size_t length);
347
-
348
178
  /**
349
179
  Sends the headers (if they weren't previously sent) and writes the data to the
350
180
  underlying socket.
351
181
 
352
182
  The server's outgoing buffer will take ownership of the file and close it
353
- using `fclose` once the data was sent.
183
+ using `close` once the data was sent.
354
184
 
355
185
  If the connection was already closed, the function will return -1. On success,
356
- the function returns 0.
186
+ the function returns 0. The file is alsways closed by the function.
187
+
188
+ If should be possible to destroy the response object and send an error response
189
+ if an error is detected. The function will avoid sending any data before it
190
+ knows the likelyhood of error is small enough.
357
191
  */
358
192
  int http_response_sendfile(http_response_s *, int source_fd, off_t offset,
359
193
  size_t length);
@@ -387,13 +221,16 @@ int http_response_sendfile2(http_response_s *response, http_request_s *request,
387
221
  const char *file_path_safe, size_t path_safe_len,
388
222
  const char *file_path_unsafe,
389
223
  size_t path_unsafe_len, uint8_t log);
390
- /**
391
- Starts counting miliseconds for log results.
392
- */
224
+ /* *****************************************************************************
225
+ Helpers and common tasks
226
+ ***************************************************************************** */
227
+
228
+ /** Gets a response status, as a string. */
229
+ const char *http_response_status_str(uint16_t status);
230
+ /** Gets the mime-type string (C string) associated with the file extension. */
231
+ const char *http_response_ext2mime(const char *ext);
232
+
233
+ /** Starts counting miliseconds for log results. */
393
234
  void http_response_log_start(http_response_s *);
394
- /**
395
- prints out the log to stderr.
396
- */
397
- void http_response_log_finish(http_response_s *);
398
235
 
399
236
  #endif
@@ -133,7 +133,7 @@ Returns `false` on error and `self` on success.
133
133
  */
134
134
  static VALUE dyn_write_urgent(VALUE self, VALUE data) {
135
135
  intptr_t fd = iodine_get_fd(self);
136
- if (sock_write2(.fduuid = fd, .buffer = RSTRING(data),
136
+ if (sock_write2(.uuid = fd, .buffer = RSTRING(data),
137
137
  .length = RSTRING_LEN(data), .urgent = 1))
138
138
  return Qfalse;
139
139
  return self;
@@ -149,7 +149,7 @@ static VALUE dyn_set_timeout(VALUE self, VALUE timeout) {
149
149
  unsigned int tout = FIX2UINT(timeout);
150
150
  if (tout > 255)
151
151
  tout = 255;
152
- server_set_timeout(fd, tout);
152
+ facil_set_timeout(fd, tout);
153
153
  return self;
154
154
  }
155
155
 
@@ -158,7 +158,7 @@ Returns the connection's timeout.
158
158
  */
159
159
  static VALUE dyn_get_timeout(VALUE self) {
160
160
  intptr_t fd = iodine_get_fd(self);
161
- uint8_t tout = server_get_timeout(fd);
161
+ uint8_t tout = facil_get_timeout(fd);
162
162
  unsigned int tout_int = tout;
163
163
  return UINT2NUM(tout_int);
164
164
  }
@@ -211,7 +211,8 @@ static VALUE dyn_defer(VALUE self) {
211
211
  return Qfalse;
212
212
  Registry.add(block);
213
213
  intptr_t fd = iodine_get_fd(self);
214
- server_task(fd, dyn_perform_defer, (void *)block, dyn_defer_fallback);
214
+ facil_defer(.uuid = fd, .task = dyn_perform_defer, .arg = (void *)block,
215
+ .fallback = dyn_defer_fallback);
215
216
  return self;
216
217
  }
217
218
 
@@ -221,16 +222,15 @@ static void dyn_perform_each_task(intptr_t fd, protocol_s *protocol,
221
222
  RubyCaller.call2((VALUE)data, call_proc_id, 1,
222
223
  &(dyn_prot(protocol)->handler));
223
224
  }
224
- static void dyn_finish_each_task(intptr_t fd, protocol_s *protocol,
225
- void *data) {
226
- (void)(protocol);
225
+ static void dyn_finish_each_task(intptr_t fd, void *data) {
227
226
  (void)(fd);
228
227
  Registry.remove((VALUE)data);
229
228
  }
230
229
 
231
230
  void iodine_run_each(intptr_t origin, const char *service, VALUE block) {
232
- server_each(origin, service, dyn_perform_each_task, (void *)block,
233
- dyn_finish_each_task);
231
+ facil_each(.origin = origin, .service = service,
232
+ .task = dyn_perform_each_task, .arg = (void *)block,
233
+ .on_complete = dyn_finish_each_task);
234
234
  }
235
235
 
236
236
  /**
@@ -252,8 +252,9 @@ static VALUE dyn_each(VALUE self) {
252
252
  return Qfalse;
253
253
  Registry.add(block);
254
254
  intptr_t fd = iodine_get_fd(self);
255
- server_each(fd, iodine_protocol_service, dyn_perform_each_task, (void *)block,
256
- dyn_finish_each_task);
255
+ facil_each(.origin = fd, .service = iodine_protocol_service,
256
+ .task = dyn_perform_each_task, .arg = (void *)block,
257
+ .on_complete = dyn_finish_each_task);
257
258
  return self;
258
259
  }
259
260
 
@@ -275,8 +276,9 @@ static VALUE dyn_class_each(VALUE self) {
275
276
  if (block == Qnil)
276
277
  return Qfalse;
277
278
  Registry.add(block);
278
- server_each(-1, iodine_protocol_service, dyn_perform_each_task, (void *)block,
279
- dyn_finish_each_task);
279
+ facil_each(.origin = -1, .service = iodine_protocol_service,
280
+ .task = dyn_perform_each_task, .arg = (void *)block,
281
+ .on_complete = dyn_finish_each_task);
280
282
  return self;
281
283
  }
282
284
 
@@ -367,7 +369,7 @@ static inline protocol_s *dyn_set_protocol(intptr_t fduuid, VALUE handler,
367
369
  Registry.remove(handler);
368
370
  return NULL;
369
371
  }
370
- server_set_timeout(fduuid, timeout);
372
+ facil_set_timeout(fduuid, timeout);
371
373
  *protocol = (dyn_protocol_s){
372
374
  .handler = handler,
373
375
  .protocol.on_data = dyn_protocol_on_data,
@@ -456,11 +458,12 @@ static VALUE iodine_listen_dyn_protocol(VALUE self, VALUE port, VALUE handler) {
456
458
  rb_raise(rb_eTypeError, "The port variable must be a Fixnum or a String.");
457
459
  if (TYPE(port) == T_FIXNUM)
458
460
  port = rb_funcall2(port, to_s_method_id, 0, NULL);
461
+ rb_ivar_set(self, rb_intern("_port"), port);
459
462
  // listen
460
- server_listen(.port = StringValueCStr(port), .udata = (void *)handler,
461
- .on_open = on_open_dyn_protocol,
462
- .on_start = on_server_start_for_handler,
463
- .on_finish = on_server_on_finish_for_handler);
463
+ facil_listen(.port = StringValueCStr(port), .udata = (void *)handler,
464
+ .on_open = on_open_dyn_protocol,
465
+ .on_start = on_server_start_for_handler,
466
+ .on_finish = on_server_on_finish_for_handler);
464
467
  return self;
465
468
  }
466
469
 
@@ -489,7 +492,7 @@ VALUE iodine_upgrade2basic(intptr_t fduuid, VALUE handler) {
489
492
  }
490
493
  protocol_s *protocol = dyn_set_protocol(fduuid, handler, timeout);
491
494
  if (protocol) {
492
- if (server_switch_protocol(fduuid, protocol))
495
+ if (facil_attach(fduuid, protocol))
493
496
  dyn_protocol_on_close(protocol);
494
497
  return handler;
495
498
  }
@@ -500,6 +503,11 @@ VALUE iodine_upgrade2basic(intptr_t fduuid, VALUE handler) {
500
503
  Iodine Task Management
501
504
  */
502
505
 
506
+ static void iodine_run_once2(void *block, void *ignr) {
507
+ (void)ignr;
508
+ RubyCaller.call((VALUE)block, call_proc_id);
509
+ Registry.remove((VALUE)block);
510
+ }
503
511
  static void iodine_run_once(void *block) {
504
512
  RubyCaller.call((VALUE)block, call_proc_id);
505
513
  Registry.remove((VALUE)block);
@@ -525,10 +533,8 @@ static VALUE iodine_run_async(VALUE self) {
525
533
  if (block == Qnil)
526
534
  return Qfalse;
527
535
  Registry.add(block);
528
- if (async_run(iodine_run_once, (void *)block)) {
529
- server_run_after(1, iodine_run_once, (void *)block);
530
- ;
531
- }
536
+ if (defer(iodine_run_once2, (void *)block, NULL))
537
+ perror("ERROR: dropped defered task");
532
538
  return block;
533
539
  }
534
540
 
@@ -551,7 +557,7 @@ static VALUE iodine_run_after(VALUE self, VALUE milliseconds) {
551
557
  if (block == Qnil)
552
558
  return Qfalse;
553
559
  Registry.add(block);
554
- server_run_after(milli, iodine_run_once, (void *)block);
560
+ facil_run_every(milli, 1, iodine_run_once, (void *)block, NULL);
555
561
  return block;
556
562
  }
557
563
  /**
@@ -591,19 +597,23 @@ static VALUE iodine_run_every(int argc, VALUE *argv, VALUE self) {
591
597
  // requires a block to be passed
592
598
  rb_need_block();
593
599
  Registry.add(block);
594
- server_run_every(milli, repeat, iodine_run_always, (void *)block,
595
- (void (*)(void *))Registry.remove);
600
+ facil_run_every(milli, repeat, iodine_run_always, (void *)block,
601
+ (void (*)(void *))Registry.remove);
596
602
  return block;
597
603
  }
598
604
 
599
605
  static VALUE iodine_count(VALUE self) {
600
606
  (void)(self);
601
- return ULONG2NUM(server_count(NULL));
607
+ return ULONG2NUM(facil_count(NULL));
602
608
  }
603
609
  /* *****************************************************************************
604
610
  Running the server
605
611
  */
606
- static int sock_io_thread = 0;
612
+ #include <pthread.h>
613
+
614
+ static volatile int sock_io_thread = 0;
615
+ static pthread_t sock_io_pthread;
616
+
607
617
  static void *iodine_io_thread(void *arg) {
608
618
  (void)arg;
609
619
  static const struct timespec tm = {.tv_nsec = 16777216UL};
@@ -613,10 +623,14 @@ static void *iodine_io_thread(void *arg) {
613
623
  }
614
624
  return NULL;
615
625
  }
616
-
617
- static void iodine_start_io_thread(void) {
618
- pthread_t io_thread;
619
- pthread_create(&io_thread, NULL, iodine_io_thread, NULL);
626
+ static void iodine_start_io_thread(void *a1, void *a2) {
627
+ (void)a1;
628
+ (void)a2;
629
+ pthread_create(&sock_io_pthread, NULL, iodine_io_thread, NULL);
630
+ }
631
+ static void iodine_join_io_thread(void) {
632
+ sock_io_thread = 0;
633
+ pthread_join(sock_io_pthread, NULL);
620
634
  }
621
635
 
622
636
  static void *srv_start_no_gvl(void *_) {
@@ -630,12 +644,13 @@ static void *srv_start_no_gvl(void *_) {
630
644
  #ifdef _SC_NPROCESSORS_ONLN
631
645
  size_t cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
632
646
  if (processes <= 0)
633
- processes = (cpu_count >> 1) ? (cpu_count >> 1) : 1;
647
+ processes = 0;
634
648
  if (threads <= 0)
635
- threads = (cpu_count >> 1) ? (cpu_count >> 1) : 1;
649
+ threads = 0;
636
650
 
637
- if (cpu_count > 0 && (((size_t)processes << 1) < cpu_count ||
638
- (size_t)processes > (cpu_count << 1)))
651
+ if (processes && threads && cpu_count > 0 &&
652
+ (((size_t)processes << 1) < cpu_count ||
653
+ (size_t)processes > (cpu_count << 1)))
639
654
  fprintf(
640
655
  stderr,
641
656
  "* Performance warnning:\n"
@@ -650,21 +665,17 @@ static void *srv_start_no_gvl(void *_) {
650
665
  cpu_count, cpu_count);
651
666
  #else
652
667
  if (processes <= 0)
653
- processes = 1;
668
+ processes = 0;
654
669
  if (threads <= 0)
655
- threads = 1;
670
+ threads = 0;
656
671
  #endif
657
672
  sock_io_thread = 1;
658
- server_run(.threads = threads, .processes = processes,
659
- .on_init = iodine_start_io_thread);
660
- sock_io_thread = 0;
673
+ defer(iodine_start_io_thread, NULL, NULL);
674
+ facil_run(.threads = threads, .processes = processes,
675
+ .on_finish = iodine_join_io_thread);
661
676
  return NULL;
662
677
  }
663
678
 
664
- static void unblck(void *_) {
665
- (void)(_);
666
- server_stop();
667
- }
668
679
  /**
669
680
  Starts the Iodine event loop. This will hang the thread until an interrupt
670
681
  (`^C`) signal is received.
@@ -676,7 +687,7 @@ static VALUE iodine_start(VALUE self) {
676
687
  perror("Iodine couldn't start HTTP service... port busy? ");
677
688
  return Qnil;
678
689
  }
679
- rb_thread_call_without_gvl2(srv_start_no_gvl, (void *)self, unblck, NULL);
690
+ rb_thread_call_without_gvl2(srv_start_no_gvl, (void *)self, NULL, NULL);
680
691
 
681
692
  return self;
682
693
  }