iodine 0.7.9 → 0.7.10

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.

@@ -109,7 +109,7 @@ Version and helper macros
109
109
  #define FIO_VERSION_MAJOR 0
110
110
  #define FIO_VERSION_MINOR 7
111
111
  #define FIO_VERSION_PATCH 0
112
- #define FIO_VERSION_BETA 2
112
+ #define FIO_VERSION_BETA 3
113
113
 
114
114
  /* Automatically convert version data to a string constant - ignore these two */
115
115
  #define FIO_MACRO2STR_STEP2(macro) #macro
@@ -167,7 +167,8 @@ Version and helper macros
167
167
 
168
168
  #ifndef FIO_PRINT_STATE
169
169
  /**
170
- * Prints some state massages to stderr (startup / shutdown / etc').
170
+ * Enables the FIO_LOG_STATE(msg,...) macro, which prints information level
171
+ * messages to stderr.
171
172
  */
172
173
  #define FIO_PRINT_STATE 1
173
174
  #endif
@@ -328,7 +329,7 @@ void *fio_mmap(size_t size);
328
329
  void fio_malloc_after_fork(void);
329
330
 
330
331
  #if FIO_FORCE_MALLOC
331
- #define FIO_MALLOC(size) malloc((size))
332
+ #define FIO_MALLOC(size) calloc((size), 1)
332
333
  #define FIO_CALLOC(size, units) calloc((size), (units))
333
334
  #define FIO_REALLOC(ptr, new_length, existing_data_length) \
334
335
  realloc((ptr), (new_length))
@@ -1713,8 +1714,6 @@ struct fio_msg_metadata_s {
1713
1714
  void (*on_finish)(fio_msg_s *msg, void *metadata);
1714
1715
  /** The pointer to be disclosed to the `fio_message_metadata` function. */
1715
1716
  void *metadata;
1716
- /** RESERVED for internal use (Metadata linked list). */
1717
- fio_msg_metadata_s *next;
1718
1717
  };
1719
1718
 
1720
1719
  /**
@@ -66,7 +66,7 @@ b = a.map {|s| s.length }
66
66
  puts "static char *html_escape_strs[] = {", a.to_s.slice(1..-2) ,"};",
67
67
  "static uint8_t html_escape_len[] = {", b.to_s.slice(1..-2),"};"
68
68
  */
69
- static char *html_escape_strs[] = {
69
+ static const char *html_escape_strs[] = {
70
70
  "�", "", "", "", "", "", "",
71
71
  "", "", "	", "
", "", "", "
",
72
72
  "", "", "", "", "", "", "",
@@ -53,12 +53,12 @@ static fio_str_info_s fio_i2str(const FIOBJ o) {
53
53
  }
54
54
  static fio_str_info_s fio_f2str(const FIOBJ o) {
55
55
  if (isnan(obj2float(o)->f))
56
- return (fio_str_info_s){.data = "NaN", .len = 3};
56
+ return (fio_str_info_s){.data = (char *)"NaN", .len = 3};
57
57
  else if (isinf(obj2float(o)->f)) {
58
58
  if (obj2float(o)->f > 0)
59
- return (fio_str_info_s){.data = "Infinity", .len = 8};
59
+ return (fio_str_info_s){.data = (char *)"Infinity", .len = 8};
60
60
  else
61
- return (fio_str_info_s){.data = "-Infinity", .len = 9};
61
+ return (fio_str_info_s){.data = (char *)"-Infinity", .len = 9};
62
62
  }
63
63
  return (fio_str_info_s){
64
64
  .data = num_buffer,
@@ -608,8 +608,8 @@ found_file:
608
608
  switch (s.len) {
609
609
  case 7:
610
610
  if (!strncasecmp("options", s.data, 7)) {
611
- http_set_header2(h, (fio_str_info_s){.data = "allow", .len = 5},
612
- (fio_str_info_s){.data = "GET, HEAD", .len = 9});
611
+ http_set_header2(h, (fio_str_info_s){.data = (char *)"allow", .len = 5},
612
+ (fio_str_info_s){.data = (char *)"GET, HEAD", .len = 9});
613
613
  h->status = 200;
614
614
  http_finish(h);
615
615
  return 0;
@@ -694,7 +694,8 @@ int http_send_error(http_s *r, size_t error) {
694
694
  if (http_sendfile2(r, http2protocol(r)->settings->public_folder,
695
695
  http2protocol(r)->settings->public_folder_length, buffer,
696
696
  pos)) {
697
- http_set_header(r, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("txt", 3));
697
+ http_set_header(r, HTTP_HEADER_CONTENT_TYPE,
698
+ http_mimetype_find((char *)"txt", 3));
698
699
  fio_str_info_s t = http_status2str(error);
699
700
  http_send_body(r, t.data, t.len);
700
701
  }
@@ -1148,15 +1149,15 @@ intptr_t http_connect(const char *address,
1148
1149
  } else {
1149
1150
  p++;
1150
1151
  if (!len) {
1151
- a = "localhost";
1152
+ a = (char *)"localhost";
1152
1153
  len = 9;
1153
1154
  }
1154
1155
  }
1155
1156
  } else {
1156
1157
  if (is_secure)
1157
- p = "443";
1158
+ p = (char *)"443";
1158
1159
  else
1159
- p = "80";
1160
+ p = (char *)"80";
1160
1161
  }
1161
1162
 
1162
1163
  /* set settings */
@@ -1179,7 +1180,7 @@ intptr_t http_connect(const char *address,
1179
1180
  h->status = 0;
1180
1181
  h->path = path;
1181
1182
  settings->udata = h;
1182
- http_set_header2(h, (fio_str_info_s){.data = "host", .len = 4},
1183
+ http_set_header2(h, (fio_str_info_s){.data = (char *)"host", .len = 4},
1183
1184
  (fio_str_info_s){.data = a, .len = len});
1184
1185
  intptr_t ret;
1185
1186
  if (is_websocket) {
@@ -1302,7 +1303,7 @@ static void http_sse_on_unsubscribe(void *sse_, void *args_) {
1302
1303
  struct http_sse_subscribe_args *args = args_;
1303
1304
  if (args->on_unsubscribe)
1304
1305
  args->on_unsubscribe(args->udata);
1305
- free(args);
1306
+ fio_free(args);
1306
1307
  http_sse_try_free(sse);
1307
1308
  }
1308
1309
 
@@ -1328,7 +1329,7 @@ uintptr_t http_sse_subscribe(http_sse_s *sse_,
1328
1329
  return 0;
1329
1330
  if (!args.on_message)
1330
1331
  args.on_message = http_sse_on_message__direct;
1331
- struct http_sse_subscribe_args *udata = malloc(sizeof(*udata));
1332
+ struct http_sse_subscribe_args *udata = fio_malloc(sizeof(*udata));
1332
1333
  FIO_ASSERT_ALLOC(udata);
1333
1334
  *udata = args;
1334
1335
 
@@ -1403,15 +1404,15 @@ int http_sse_write(http_sse_s *sse, struct http_sse_write_args args) {
1403
1404
  args.data.len + 2 + 7 + 10 + 4;
1404
1405
  buf = fiobj_str_buf(total);
1405
1406
  }
1406
- http_sse_copy2str(buf, "id: ", 4, args.id);
1407
- http_sse_copy2str(buf, "event: ", 7, args.event);
1407
+ http_sse_copy2str(buf, (char *)"id: ", 4, args.id);
1408
+ http_sse_copy2str(buf, (char *)"event: ", 7, args.event);
1408
1409
  if (args.retry) {
1409
1410
  FIOBJ i = fiobj_num_new(args.retry);
1410
- fiobj_str_write(buf, "retry: ", 7);
1411
+ fiobj_str_write(buf, (char *)"retry: ", 7);
1411
1412
  fiobj_str_join(buf, i);
1412
1413
  fiobj_free(i);
1413
1414
  }
1414
- http_sse_copy2str(buf, "data: ", 6, args.data);
1415
+ http_sse_copy2str(buf, (char *)"data: ", 6, args.data);
1415
1416
  fiobj_str_write(buf, "\r\n", 2);
1416
1417
  return FIO_LS_EMBD_OBJ(http_sse_internal_s, sse, sse)
1417
1418
  ->vtable->http_sse_write(sse, buf);
@@ -2819,7 +2820,7 @@ static char invalid_cookie_value_char[256] = {
2819
2820
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
2820
2821
 
2821
2822
  // clang-format off
2822
- #define HTTP_SET_STATUS_STR(status, str) [status-100] = { .data = (str), .len = (sizeof(str) - 1) }
2823
+ #define HTTP_SET_STATUS_STR(status, str) [status-100] = { .data = (char *)(str), .len = (sizeof(str) - 1) }
2823
2824
  // clang-format on
2824
2825
 
2825
2826
  /** Returns the status as a C string struct */
@@ -442,7 +442,7 @@ static uint8_t http1_sse_on_shutdown(intptr_t uuid, fio_protocol_s *p_) {
442
442
  static void http1_sse_on_close(intptr_t uuid, fio_protocol_s *p_) {
443
443
  http1_sse_fio_protocol_s *p = (http1_sse_fio_protocol_s *)p_;
444
444
  http_sse_destroy(p->sse);
445
- free(p);
445
+ fio_free(p);
446
446
  (void)uuid;
447
447
  }
448
448
  static void http1_sse_ping(intptr_t uuid, fio_protocol_s *p_) {
@@ -472,7 +472,7 @@ static int http1_upgrade2sse(http_s *h, http_sse_s *sse) {
472
472
  htt1p_finish(h); /* avoid the enforced content length in http_finish */
473
473
 
474
474
  /* switch protocol to SSE */
475
- http1_sse_fio_protocol_s *sse_pr = malloc(sizeof(*sse_pr));
475
+ http1_sse_fio_protocol_s *sse_pr = fio_malloc(sizeof(*sse_pr));
476
476
  if (!sse_pr)
477
477
  goto failed;
478
478
  *sse_pr = (http1_sse_fio_protocol_s){
@@ -483,7 +483,7 @@ static int http1_upgrade2sse(http_s *h, http_sse_s *sse) {
483
483
  .on_close = http1_sse_on_close,
484
484
  .ping = http1_sse_ping,
485
485
  },
486
- .sse = malloc(sizeof(*(sse_pr->sse))),
486
+ .sse = fio_malloc(sizeof(*(sse_pr->sse))),
487
487
  };
488
488
 
489
489
  if (!sse_pr->sse)
@@ -763,7 +763,7 @@ fio_protocol_s *http1_new(uintptr_t uuid, http_settings_s *settings,
763
763
  void *unread_data, size_t unread_length) {
764
764
  if (unread_data && unread_length > HTTP_MAX_HEADER_LENGTH)
765
765
  return NULL;
766
- http1pr_s *p = malloc(sizeof(*p) + HTTP_MAX_HEADER_LENGTH);
766
+ http1pr_s *p = fio_malloc(sizeof(*p) + HTTP_MAX_HEADER_LENGTH);
767
767
  FIO_ASSERT_ALLOC(p);
768
768
  *p = (http1pr_s){
769
769
  .p.protocol =
@@ -791,7 +791,7 @@ void http1_destroy(fio_protocol_s *pr) {
791
791
  http1pr_s *p = (http1pr_s *)pr;
792
792
  http1_pr2handle(p).status = 0;
793
793
  http_s_destroy(&http1_pr2handle(p), 0);
794
- free(p);
794
+ fio_free(p);
795
795
  }
796
796
 
797
797
  /* *****************************************************************************
@@ -799,7 +799,7 @@ Protocol Data
799
799
  ***************************************************************************** */
800
800
 
801
801
  // clang-format off
802
- #define HTTP_SET_STATUS_STR(status, str) [((status)-100)] = { .data = ("HTTP/1.1 " #status " " str "\r\n"), .len = (sizeof("HTTP/1.1 " #status " " str "\r\n") - 1) }
802
+ #define HTTP_SET_STATUS_STR(status, str) [((status)-100)] = { .data = (char*)("HTTP/1.1 " #status " " str "\r\n"), .len = (sizeof("HTTP/1.1 " #status " " str "\r\n") - 1) }
803
803
  // #undef HTTP_SET_STATUS_STR
804
804
  // clang-format on
805
805
 
@@ -169,7 +169,7 @@ inline static int consume_request_line(struct http1_fio_parser_args_s *args,
169
169
  return -1;
170
170
  *tmp = ' ';
171
171
  if (!seek2ch(&host_end, tmp, '/')) {
172
- if (args->on_path(args->parser, "/", 1))
172
+ if (args->on_path(args->parser, (char *)"/", 1))
173
173
  return -1;
174
174
  goto start_version;
175
175
  }
@@ -201,8 +201,8 @@ start_version:
201
201
  if (args->on_http_version(args->parser, (char *)start, end - start))
202
202
  return -1;
203
203
  /* */
204
- if (host_start && args->on_header(args->parser, "host", 4, (char *)host_start,
205
- host_end - host_start))
204
+ if (host_start && args->on_header(args->parser, (char *)"host", 4,
205
+ (char *)host_start, host_end - host_start))
206
206
  return -1;
207
207
  return 0;
208
208
  }
@@ -68,7 +68,7 @@ upgrade:
68
68
  return;
69
69
  }
70
70
  eventsource:
71
- settings->on_upgrade(h, "sse", 3);
71
+ settings->on_upgrade(h, (char *)"sse", 3);
72
72
  return;
73
73
  }
74
74
 
@@ -252,8 +252,8 @@ static void http_lib_init(void *ignr_) {
252
252
  fiobj_obj2hash(HTTP_HVALUE_WS_VERSION);
253
253
 
254
254
  #define REGISTER_MIME(ext, type) \
255
- http_mimetype_register(ext, sizeof(ext) - 1, \
256
- fiobj_str_new(type, sizeof(type) - 1))
255
+ http_mimetype_register((char *)ext, sizeof(ext) - 1, \
256
+ fiobj_str_new((char *)type, sizeof(type) - 1))
257
257
 
258
258
  REGISTER_MIME("123", "application/vnd.lotus-1-2-3");
259
259
  REGISTER_MIME("3dml", "text/vnd.in3d.3dml");
@@ -175,7 +175,7 @@ static inline void http_sse_init(http_sse_internal_s *sse, intptr_t uuid,
175
175
  static inline void http_sse_try_free(http_sse_internal_s *sse) {
176
176
  if (fio_atomic_sub(&sse->ref, 1))
177
177
  return;
178
- free(sse);
178
+ fio_free(sse);
179
179
  }
180
180
 
181
181
  static inline void http_sse_destroy(http_sse_internal_s *sse) {
@@ -309,7 +309,7 @@ static VALUE iodine_cli_parse(VALUE self, VALUE desc) {
309
309
  }
310
310
  char **argv = calloc(argc, sizeof(*argv));
311
311
  FIO_ASSERT_ALLOC(argv);
312
- argv[0] = "iodine";
312
+ argv[0] = (char *)"iodine";
313
313
  for (int i = 1; i < argc; ++i) {
314
314
  VALUE tmp = rb_ary_entry(ARGV, (long)(i - 1));
315
315
  if (TYPE(tmp) != T_STRING) {
@@ -326,13 +326,13 @@ static VALUE iodine_cli_parse(VALUE self, VALUE desc) {
326
326
  /* Levarage the facil.io CLI library */
327
327
  fio_cli_start(
328
328
  argc, (const char **)argv, 0, -1, StringValueCStr(desc),
329
- "\x1B[1m\x1B[4mAddress Binding:\x1B[0m", FIO_CLI_TYPE_PRINT,
329
+ "\x1B[4mAddress Binding:\x1B[0m", FIO_CLI_TYPE_PRINT,
330
330
  "-bind -b -address address to listen to. defaults any available.",
331
331
  "-port -p port number to listen to. defaults port 3000", FIO_CLI_TYPE_INT,
332
- "\n\x1B[1m\x1B[4mConcurrency:\x1B[0m", FIO_CLI_TYPE_PRINT,
332
+ "\n\x1B[4mConcurrency:\x1B[0m", FIO_CLI_TYPE_PRINT,
333
333
  "-workers -w number of processes to use.", FIO_CLI_TYPE_INT,
334
334
  "-threads -t number of threads per process.", FIO_CLI_TYPE_INT,
335
- "\n\x1B[1m\x1B[4mHTTP Server:\x1B[0m", FIO_CLI_TYPE_PRINT,
335
+ "\n\x1B[4mHTTP Server:\x1B[0m", FIO_CLI_TYPE_PRINT,
336
336
  "-public -www public folder, for static file service.",
337
337
  "-log -v HTTP request logging.", FIO_CLI_TYPE_BOOL,
338
338
  "-keep-alive -k -tout HTTP keep-alive timeout (0..255). Default: 40s",
@@ -342,15 +342,14 @@ static VALUE iodine_cli_parse(VALUE self, VALUE desc) {
342
342
  FIO_CLI_TYPE_INT,
343
343
  "-max-header -maxhd header limit per HTTP request in Kb."
344
344
  " Default: 32Kb.",
345
- FIO_CLI_TYPE_INT, "\n\x1B[1m\x1B[4mWebSocket Server:\x1B[0m",
346
- FIO_CLI_TYPE_PRINT,
345
+ FIO_CLI_TYPE_INT, "\n\x1B[4mWebSocket Server:\x1B[0m", FIO_CLI_TYPE_PRINT,
347
346
  "-max-msg -maxms incoming WebSocket message limit in Kb. "
348
347
  "Default: 250Kb",
349
- FIO_CLI_TYPE_INT, "\n\x1B[1m\x1B[4mConnecting Iodine to Redis:\x1B[0m",
348
+ FIO_CLI_TYPE_INT, "\n\x1B[4mConnecting Iodine to Redis:\x1B[0m",
350
349
  FIO_CLI_TYPE_PRINT,
351
350
  "-redis -r an optional Redis URL server address. Default: none.",
352
351
  "-redis-ping -rp websocket ping interval (0..255). Default: 5 minutes",
353
- FIO_CLI_TYPE_INT, "\n\x1B[1m\x1B[4mMisc:\x1B[0m", FIO_CLI_TYPE_PRINT,
352
+ FIO_CLI_TYPE_INT, "\n\x1B[4mMisc:\x1B[0m", FIO_CLI_TYPE_PRINT,
354
353
  "-warmup warm up the application. CAREFUL! iodine might fork.",
355
354
  FIO_CLI_TYPE_BOOL,
356
355
  "-verbosity -V 0..5 server verbosity level. Default: 4",
@@ -250,7 +250,11 @@ static VALUE iodine_connection_pending(VALUE self) {
250
250
  }
251
251
 
252
252
  // clang-format off
253
- /** Returns the connection's protocol Symbol (`:sse`, `:websocket`, etc'), if originated in HTTP (`rack.upgrade`). */
253
+ /**
254
+ * Returns the connection's protocol Symbol (`:sse`, `:websocket` or `:raw`).
255
+ *
256
+ * @Note For compatibility reasons (with ther `rack.upgrade` servers), it might be more prudent to use the data in the {#env} (`env['rack.upgrade?']`). However, this method is provided both as a faster alternative and for those cases where Raw / Custom (TCP/IP) data stream is a valid option.
257
+ */
254
258
  static VALUE iodine_connection_protocol_name(VALUE self) {
255
259
  // clang-format on
256
260
  iodine_connection_data_s *c = iodine_connection_validate_data(self);
@@ -334,14 +338,23 @@ static void iodine_on_pubsub(fio_msg_s *msg) {
334
338
  iodine_connection_data_s *data = msg->udata1;
335
339
  VALUE block = (VALUE)msg->udata2;
336
340
  switch (block) {
337
- case Qnil: /* fallthrough */
338
- case Qtrue: {
341
+ case Qnil: /* fallthrough */
342
+ case Qtrue: { /* Qtrue == binary WebSocket */
339
343
  if (data->info.handler == Qnil || data->info.uuid == -1 ||
340
344
  fio_is_closed(data->info.uuid))
341
345
  return;
342
346
  switch (data->info.type) {
343
347
  case IODINE_CONNECTION_WEBSOCKET: {
344
- websocket_write(data->info.arg, msg->msg, (block == Qnil));
348
+ FIOBJ s = (FIOBJ)fio_message_metadata(
349
+ msg, (block == Qnil ? WEBSOCKET_OPTIMIZE_PUBSUB
350
+ : WEBSOCKET_OPTIMIZE_PUBSUB_BINARY));
351
+ if (s) {
352
+ // fwrite(".", 1, 1, stderr);
353
+ fiobj_send_free(data->info.uuid, fiobj_dup(s));
354
+ } else {
355
+ fwrite("-", 1, 1, stderr);
356
+ websocket_write(data->info.arg, msg->msg, (block == Qnil));
357
+ }
345
358
  return;
346
359
  }
347
360
  case IODINE_CONNECTION_SSE:
@@ -353,7 +366,20 @@ static void iodine_on_pubsub(fio_msg_s *msg) {
353
366
  }
354
367
  }
355
368
  default:
356
- IodineCaller.enterGVL(iodine_on_pubsub_call_block, msg);
369
+ if (data->info.uuid != -1) {
370
+ fio_protocol_s *pr =
371
+ fio_protocol_try_lock(data->info.uuid, FIO_PR_LOCK_TASK);
372
+ if (!pr) {
373
+ // perror("Connection lock failed");
374
+ if (errno != EBADF)
375
+ fio_message_defer(msg);
376
+ break;
377
+ }
378
+ IodineCaller.enterGVL(iodine_on_pubsub_call_block, msg);
379
+ fio_protocol_unlock(pr, FIO_PR_LOCK_TASK);
380
+ } else {
381
+ IodineCaller.enterGVL(iodine_on_pubsub_call_block, msg);
382
+ }
357
383
  break;
358
384
  }
359
385
  }
@@ -364,7 +390,14 @@ static void iodine_on_unsubscribe(void *udata1, void *udata2) {
364
390
  VALUE block = (VALUE)udata2;
365
391
  switch (block) {
366
392
  case Qnil:
393
+ if (data && data->info.type == IODINE_CONNECTION_WEBSOCKET) {
394
+ websocket_optimize4broadcasts(WEBSOCKET_OPTIMIZE_PUBSUB, 0);
395
+ }
396
+ break;
367
397
  case Qtrue:
398
+ if (data && data->info.type == IODINE_CONNECTION_WEBSOCKET) {
399
+ websocket_optimize4broadcasts(WEBSOCKET_OPTIMIZE_PUBSUB_BINARY, 0);
400
+ }
368
401
  break;
369
402
  default:
370
403
  IodineStore.remove(block);
@@ -503,8 +536,15 @@ static VALUE iodine_pubsub_subscribe(int argc, VALUE *argv, VALUE self) {
503
536
  }
504
537
  return Qnil; /* cannot subscribe a closed / invalid connection. */
505
538
  }
506
- if (args.block == Qnil && args.binary) {
507
- args.block = Qtrue;
539
+ if (args.block == Qnil) {
540
+ if (c->info.type == IODINE_CONNECTION_WEBSOCKET)
541
+ websocket_optimize4broadcasts((args.binary
542
+ ? WEBSOCKET_OPTIMIZE_PUBSUB_BINARY
543
+ : WEBSOCKET_OPTIMIZE_PUBSUB),
544
+ 1);
545
+ if (args.binary) {
546
+ args.block = Qtrue;
547
+ }
508
548
  }
509
549
  fio_atomic_add(&c->ref, 1);
510
550
  }
@@ -719,11 +759,11 @@ void iodine_connection_fire_event(VALUE connection,
719
759
  IodineCaller.call2(data->info.handler, on_close_id, 1, args);
720
760
  }
721
761
  fio_lock(&data->lock);
762
+ iodine_sub_clear_all(&data->subscriptions);
722
763
  data->info.handler = Qnil;
723
764
  data->info.env = Qnil;
724
765
  data->info.uuid = -1;
725
766
  data->info.arg = NULL;
726
- iodine_sub_clear_all(&data->subscriptions);
727
767
  fio_unlock(&data->lock);
728
768
  IodineStore.remove(connection);
729
769
  break;
@@ -35,7 +35,7 @@ typedef struct {
35
35
  static void *iodine_io_thread(void *arg) {
36
36
  (void)arg;
37
37
  while (sock_io_thread_flag) {
38
- if (fio_flush_all() > 1)
38
+ if (fio_flush_all())
39
39
  fio_throttle_thread(500000UL);
40
40
  else
41
41
  fio_throttle_thread(150000000UL);
@@ -101,11 +101,11 @@ static void *create_ruby_thread_gvl(void *args) {
101
101
  }
102
102
 
103
103
  static void *fork_using_ruby(void *ignr) {
104
- // stop IO thread and call before_fork callbacks
104
+ // stop IO thread, if running (shouldn't occur)
105
105
  if (sock_io_pthread) {
106
106
  iodine_join_io_thread();
107
107
  }
108
- // fork
108
+ // fork using Ruby
109
109
  const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern2("Process", 7));
110
110
  const VALUE rb_pid = IodineCaller.call(ProcessClass, rb_intern2("fork", 4));
111
111
  intptr_t pid = 0;
@@ -114,7 +114,7 @@ static void *fork_using_ruby(void *ignr) {
114
114
  } else {
115
115
  pid = 0;
116
116
  }
117
- // manage post forking state
117
+ // manage post forking state for Iodine
118
118
  IodineCaller.set_GVL(1); /* enforce GVL state in thread storage */
119
119
  if (!pid) {
120
120
  IodineStore.after_fork();
@@ -376,7 +376,6 @@ static VALUE iodine_on_state(VALUE self, VALUE event) {
376
376
  /* Performs any cleanup before worker dies */
377
377
  static void iodine_defer_on_finish(void *ignr) {
378
378
  (void)ignr;
379
-
380
379
  iodine_join_io_thread();
381
380
  }
382
381
 
@@ -406,7 +405,8 @@ void iodine_defer_initialize(void) {
406
405
  STATE_START_SHUTDOWN = rb_intern("start_shutdown");
407
406
  STATE_ON_FINISH = rb_intern("on_finish");
408
407
 
408
+ /* start the IO thread is workrs (only starts in root if root is worker) */
409
+ fio_state_callback_add(FIO_CALL_ON_START, iodine_start_io_thread, NULL);
410
+ /* stop the IO thread before exit */
409
411
  fio_state_callback_add(FIO_CALL_ON_FINISH, iodine_defer_on_finish, NULL);
410
- fio_state_callback_add(FIO_CALL_PRE_START, iodine_start_io_thread, NULL);
411
- fio_state_callback_add(FIO_CALL_AFTER_FORK, iodine_start_io_thread, NULL);
412
412
  }