iodine 0.7.1 → 0.7.2
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/.travis.yml +3 -3
- data/CHANGELOG.md +8 -0
- data/bin/mustache.rb +12 -40
- data/ext/iodine/fio.c +343 -236
- data/ext/iodine/fio.h +419 -183
- data/ext/iodine/fio_cli.c +4 -5
- data/ext/iodine/fiobj_ary.c +2 -3
- data/ext/iodine/fiobj_data.c +1 -1
- data/ext/iodine/fiobj_hash.c +88 -105
- data/ext/iodine/fiobj_json.c +4 -3
- data/ext/iodine/fiobj_numbers.c +1 -1
- data/ext/iodine/fiobj_str.c +5 -5
- data/ext/iodine/fiobject.c +14 -3
- data/ext/iodine/fiobject.h +4 -0
- data/ext/iodine/http.c +62 -77
- data/ext/iodine/http1.c +9 -12
- data/ext/iodine/http_internal.c +15 -6
- data/ext/iodine/http_internal.h +0 -8
- data/ext/iodine/iodine.c +12 -25
- data/ext/iodine/iodine_defer.c +59 -54
- data/ext/iodine/iodine_http.c +4 -32
- data/ext/iodine/iodine_mustache.c +138 -16
- data/ext/iodine/iodine_mustache.h +3 -3
- data/ext/iodine/iodine_store.c +16 -21
- data/ext/iodine/mustache_parser.h +49 -5
- data/ext/iodine/redis_engine.c +31 -31
- data/ext/iodine/websockets.c +11 -5
- data/lib/iodine.rb +13 -1
- data/lib/iodine/mustache.rb +13 -41
- data/lib/iodine/version.rb +1 -1
- metadata +2 -4
- data/ext/iodine/fio_hashmap.h +0 -813
- data/ext/iodine/fio_str.h +0 -1218
data/ext/iodine/iodine_store.c
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
#include "iodine.h"
|
2
2
|
|
3
|
-
#include "fio_hashmap.h"
|
4
3
|
#include "iodine_store.h"
|
5
4
|
|
6
|
-
#include <fio.h>
|
7
5
|
#include <inttypes.h>
|
8
6
|
#include <stdint.h>
|
9
7
|
|
8
|
+
#define FIO_SET_NAME fio_hash
|
9
|
+
#define FIO_SET_OBJ_TYPE uintptr_t
|
10
|
+
#include <fio.h>
|
11
|
+
|
10
12
|
fio_lock_i lock = FIO_LOCK_INIT;
|
11
|
-
fio_hash_s storage =
|
13
|
+
fio_hash_s storage = FIO_SET_INIT;
|
12
14
|
|
13
15
|
#ifndef IODINE_DEBUG
|
14
16
|
#define IODINE_DEBUG 0
|
@@ -23,10 +25,8 @@ static VALUE storage_add(VALUE obj) {
|
|
23
25
|
if (obj == Qnil || obj == Qtrue || obj == Qfalse)
|
24
26
|
return obj;
|
25
27
|
fio_lock(&lock);
|
26
|
-
uintptr_t val =
|
27
|
-
|
28
|
-
fio_hash_insert(&storage, obj, (void *)(val + 1));
|
29
|
-
}
|
28
|
+
uintptr_t *val = fio_hash_insert(&storage, obj, 0);
|
29
|
+
++val[0];
|
30
30
|
fio_unlock(&lock);
|
31
31
|
return obj;
|
32
32
|
}
|
@@ -36,14 +36,9 @@ static VALUE storage_remove(VALUE obj) {
|
|
36
36
|
storage.count == 0)
|
37
37
|
return obj;
|
38
38
|
fio_lock(&lock);
|
39
|
-
uintptr_t val = (
|
40
|
-
if (val
|
41
|
-
|
42
|
-
}
|
43
|
-
if ((storage.count << 1) <= storage.pos &&
|
44
|
-
(storage.pos << 1) > storage.capa) {
|
45
|
-
fio_hash_compact(&storage);
|
46
|
-
}
|
39
|
+
uintptr_t *val = fio_hash_find(&storage, obj, 0);
|
40
|
+
if (val && *val <= 1)
|
41
|
+
fio_hash_remove(&storage, obj, 0);
|
47
42
|
fio_unlock(&lock);
|
48
43
|
return obj;
|
49
44
|
}
|
@@ -55,10 +50,10 @@ static void storage_print(void) {
|
|
55
50
|
fprintf(stderr, "Ruby <=> C Memory storage stats (pid: %d):\n", getpid());
|
56
51
|
fio_lock(&lock);
|
57
52
|
uintptr_t index = 0;
|
58
|
-
|
53
|
+
FIO_SET_FOR_LOOP(&storage, pos) {
|
59
54
|
if (pos->obj) {
|
60
55
|
fprintf(stderr, "[%" PRIuPTR "] => %" PRIuPTR " X obj %p type %d\n",
|
61
|
-
index++,
|
56
|
+
index++, pos->obj, (void *)pos->hash, TYPE(pos->hash));
|
62
57
|
}
|
63
58
|
}
|
64
59
|
fprintf(stderr, "Total of %" PRIuPTR " objects protected form GC\n", index);
|
@@ -88,9 +83,9 @@ static void storage_mark(void *ignore) {
|
|
88
83
|
#endif
|
89
84
|
fio_lock(&lock);
|
90
85
|
// fio_hash_compact(&storage);
|
91
|
-
|
86
|
+
FIO_SET_FOR_LOOP(&storage, pos) {
|
92
87
|
if (pos->obj) {
|
93
|
-
rb_gc_mark((VALUE)pos->
|
88
|
+
rb_gc_mark((VALUE)pos->hash);
|
94
89
|
}
|
95
90
|
}
|
96
91
|
fio_unlock(&lock);
|
@@ -104,7 +99,7 @@ static void storage_clear(void *ignore) {
|
|
104
99
|
#endif
|
105
100
|
fio_lock(&lock);
|
106
101
|
fio_hash_free(&storage);
|
107
|
-
storage = (fio_hash_s)
|
102
|
+
storage = (fio_hash_s)FIO_SET_INIT;
|
108
103
|
fio_unlock(&lock);
|
109
104
|
}
|
110
105
|
|
@@ -131,7 +126,7 @@ struct IodineStorage_s IodineStore = {
|
|
131
126
|
|
132
127
|
/** Initializes the storage unit for first use. */
|
133
128
|
void iodine_storage_init(void) {
|
134
|
-
|
129
|
+
fio_hash_capa_require(&storage, 512);
|
135
130
|
VALUE tmp =
|
136
131
|
rb_define_class_under(rb_cObject, "IodineObjectStorage", rb_cData);
|
137
132
|
VALUE storage_obj =
|
@@ -114,6 +114,10 @@ typedef struct {
|
|
114
114
|
char const *filename;
|
115
115
|
/** The file name's length. */
|
116
116
|
size_t filename_len;
|
117
|
+
/** If data and data_len are set, they will be used as the file's contents. */
|
118
|
+
char const *data;
|
119
|
+
/** If data and data_len are set, they will be used as the file's contents. */
|
120
|
+
size_t data_len;
|
117
121
|
/** Parsing error reporting (can be NULL). */
|
118
122
|
mustache_error_en *err;
|
119
123
|
} mustache_load_args_s;
|
@@ -551,7 +555,8 @@ MUSTACHE_FUNC mustache_s *(mustache_load)(mustache_load_args_s args) {
|
|
551
555
|
}
|
552
556
|
|
553
557
|
/* copy the path data (and resolve) into writable memory */
|
554
|
-
if (args.filename[0] == '~' && args.filename[1] == '/' &&
|
558
|
+
if (args.filename && args.filename[0] == '~' && args.filename[1] == '/' &&
|
559
|
+
getenv("HOME")) {
|
555
560
|
const char *home = getenv("HOME");
|
556
561
|
path_len = strlen(home);
|
557
562
|
path_capa =
|
@@ -569,7 +574,6 @@ MUSTACHE_FUNC mustache_s *(mustache_load)(mustache_load_args_s args) {
|
|
569
574
|
args.filename_len += path_len;
|
570
575
|
args.filename = path;
|
571
576
|
}
|
572
|
-
/* divide faile name from the root path to the file */
|
573
577
|
|
574
578
|
/*
|
575
579
|
* We need a dynamic array to hold the list of instructions...
|
@@ -759,7 +763,7 @@ MUSTACHE_FUNC mustache_s *(mustache_load)(mustache_load_args_s args) {
|
|
759
763
|
} \
|
760
764
|
goto error; \
|
761
765
|
} \
|
762
|
-
if (pread(fd, (data + data_len + 4 +
|
766
|
+
if (pread(fd, (data + data_len + 4 + 2 + 4 + path_len), f_data.st_size, \
|
763
767
|
0) != (ssize_t)f_data.st_size) { \
|
764
768
|
if (args.err) { \
|
765
769
|
*args.err = MUSTACHE_ERR_FILE_NOT_FOUND; \
|
@@ -794,8 +798,48 @@ MUSTACHE_FUNC mustache_s *(mustache_load)(mustache_load_args_s args) {
|
|
794
798
|
(str) += (step); \
|
795
799
|
}
|
796
800
|
|
797
|
-
|
798
|
-
|
801
|
+
if (args.data_len) {
|
802
|
+
/* allocate data segment */
|
803
|
+
data_len = 4 + 2 + 4 + args.data_len + args.filename_len + 1;
|
804
|
+
data = malloc(data_len);
|
805
|
+
if (!data) {
|
806
|
+
perror("FATAL ERROR: couldn't reallocate memory for mustache "
|
807
|
+
"data segment");
|
808
|
+
exit(errno);
|
809
|
+
}
|
810
|
+
/* save instruction position length into template header */
|
811
|
+
data[0] = (instructions->head.u.read_only.intruction_count >> 3) & 0xFF;
|
812
|
+
data[1] = (instructions->head.u.read_only.intruction_count >> 2) & 0xFF;
|
813
|
+
data[2] = (instructions->head.u.read_only.intruction_count >> 1) & 0xFF;
|
814
|
+
data[3] = (instructions->head.u.read_only.intruction_count) & 0xFF;
|
815
|
+
/* Add section start marker (to support recursion or repeated partials) */
|
816
|
+
PUSH_INSTRUCTION(.instruction = MUSTACHE_SECTION_START);
|
817
|
+
/* save filename length */
|
818
|
+
data[4 + 0] = (args.filename_len >> 1) & 0xFF;
|
819
|
+
data[4 + 1] = args.filename_len & 0xFF;
|
820
|
+
/* save data length ("next" pointer) */
|
821
|
+
data[4 + 2 + 0] = ((uint32_t)data_len >> 3) & 0xFF;
|
822
|
+
data[4 + 2 + 1] = ((uint32_t)data_len >> 2) & 0xFF;
|
823
|
+
data[4 + 2 + 2] = ((uint32_t)data_len >> 1) & 0xFF;
|
824
|
+
data[4 + 2 + 3] = ((uint32_t)data_len) & 0xFF;
|
825
|
+
/* copy filename */
|
826
|
+
if (args.filename && args.filename_len)
|
827
|
+
memcpy(data + 4 + 2 + 4, args.filename, args.filename_len);
|
828
|
+
/* copy data */
|
829
|
+
memcpy(data + 4 + 2 + 4 + args.filename_len, args.data, args.data_len);
|
830
|
+
++stack_pos;
|
831
|
+
template_stack[stack_pos].data_start = 0;
|
832
|
+
template_stack[stack_pos].data_pos = 4 + 3 + 3 + args.filename_len;
|
833
|
+
template_stack[stack_pos].data_end = data_len - 1;
|
834
|
+
template_stack[stack_pos].delimiter_start = (uint8_t *)"{{";
|
835
|
+
template_stack[stack_pos].delimiter_end = (uint8_t *)"}}";
|
836
|
+
template_stack[stack_pos].del_start_len = 2;
|
837
|
+
template_stack[stack_pos].del_end_len = 2;
|
838
|
+
data[data_len - 1] = 0;
|
839
|
+
} else {
|
840
|
+
/* Our first template to load is the root template */
|
841
|
+
LOAD_TEMPLATE(path, 0, args.filename, args.filename_len);
|
842
|
+
}
|
799
843
|
|
800
844
|
/*** As long as the stack has templated to parse - parse the template ***/
|
801
845
|
while (stack_pos) {
|
data/ext/iodine/redis_engine.c
CHANGED
@@ -182,8 +182,7 @@ RESP parser callbacks
|
|
182
182
|
/** a local static callback, called when a parser / protocol error occurs. */
|
183
183
|
static int resp_on_parser_error(resp_parser_s *parser) {
|
184
184
|
struct redis_engine_internal_s *i = parser2data(parser);
|
185
|
-
|
186
|
-
"ERROR: (redis) parser error - attempting to restart connection.\n");
|
185
|
+
FIO_LOG_ERROR("(redis) parser error - attempting to restart connection.\n");
|
187
186
|
fio_close(i->uuid);
|
188
187
|
return -1;
|
189
188
|
}
|
@@ -339,9 +338,8 @@ static void resp_on_pub_message(struct redis_engine_internal_s *i, FIOBJ msg) {
|
|
339
338
|
fio_unlock(&r->lock);
|
340
339
|
if (!node) {
|
341
340
|
/* TODO: possible ping? from server?! not likely... */
|
342
|
-
|
343
|
-
|
344
|
-
getpid());
|
341
|
+
FIO_LOG_WARNING("(redis %d) received a reply when no command was sent.",
|
342
|
+
getpid());
|
345
343
|
return;
|
346
344
|
}
|
347
345
|
node->next = (void *)fiobj_dup(msg);
|
@@ -360,8 +358,8 @@ static void resp_on_sub_message(struct redis_engine_internal_s *i, FIOBJ msg) {
|
|
360
358
|
if (FIOBJ_TYPE(msg) != FIOBJ_T_ARRAY) {
|
361
359
|
if (FIOBJ_TYPE(msg) != FIOBJ_T_STRING || fiobj_obj2cstr(msg).len != 4 ||
|
362
360
|
fiobj_obj2cstr(msg).data[0] != 'P') {
|
363
|
-
|
364
|
-
|
361
|
+
FIO_LOG_WARNING("(redis) unexpected data format in "
|
362
|
+
"subscription stream:");
|
365
363
|
fio_str_info_s tmp = fiobj_obj2cstr(msg);
|
366
364
|
FIO_LOG_STATE(" %s\n", tmp.data);
|
367
365
|
}
|
@@ -429,9 +427,9 @@ static void redis_on_close(intptr_t uuid, fio_protocol_s *pr) {
|
|
429
427
|
if (r->flag) {
|
430
428
|
/* reconnection for subscription connection. */
|
431
429
|
if (uuid != -1) {
|
432
|
-
|
433
|
-
|
434
|
-
|
430
|
+
FIO_LOG_WARNING("(redis %d) subscription connection lost. "
|
431
|
+
"Reconnecting...",
|
432
|
+
(int)getpid());
|
435
433
|
}
|
436
434
|
fio_atomic_sub(&r->ref, 1);
|
437
435
|
fio_defer(redis_connect, r, internal);
|
@@ -441,9 +439,9 @@ static void redis_on_close(intptr_t uuid, fio_protocol_s *pr) {
|
|
441
439
|
} else {
|
442
440
|
r = pub2redis(pr);
|
443
441
|
if (r->flag && uuid != -1) {
|
444
|
-
|
445
|
-
|
446
|
-
|
442
|
+
FIO_LOG_WARNING("(redis %d) publication connection lost. "
|
443
|
+
"Reconnecting...",
|
444
|
+
(int)getpid());
|
447
445
|
}
|
448
446
|
r->pub_send = 0;
|
449
447
|
fio_close(r->sub_data.uuid);
|
@@ -471,8 +469,7 @@ static void redis_sub_ping(intptr_t uuid, fio_protocol_s *pr) {
|
|
471
469
|
static void redis_pub_ping(intptr_t uuid, fio_protocol_s *pr) {
|
472
470
|
redis_engine_s *r = pub2redis(pr);
|
473
471
|
if (fio_ls_embd_any(&r->queue)) {
|
474
|
-
|
475
|
-
"WARNING: (redis) Redis server unresponsive, disconnecting.\n");
|
472
|
+
FIO_LOG_WARNING("(redis) Redis server unresponsive, disconnecting.");
|
476
473
|
fio_close(uuid);
|
477
474
|
return;
|
478
475
|
}
|
@@ -489,9 +486,9 @@ Connecting to Redis
|
|
489
486
|
static void redis_on_auth(fio_pubsub_engine_s *e, FIOBJ reply, void *udata) {
|
490
487
|
if (FIOBJ_TYPE_IS(reply, FIOBJ_T_TRUE)) {
|
491
488
|
fio_str_info_s s = fiobj_obj2cstr(reply);
|
492
|
-
|
493
|
-
|
494
|
-
|
489
|
+
FIO_LOG_WARNING("(redis) Authentication FAILED."
|
490
|
+
" %.*s",
|
491
|
+
(int)s.len, s.data);
|
495
492
|
}
|
496
493
|
(void)e;
|
497
494
|
(void)udata;
|
@@ -512,8 +509,8 @@ static void redis_on_connect(intptr_t uuid, void *i_) {
|
|
512
509
|
if (r->pub_data.uuid == -1) {
|
513
510
|
fio_defer(redis_connect, r, &r->pub_data);
|
514
511
|
}
|
515
|
-
|
516
|
-
|
512
|
+
FIO_LOG_INFO("(redis %d) subscription connection established.",
|
513
|
+
(int)getpid());
|
517
514
|
} else {
|
518
515
|
r = pub2redis(i);
|
519
516
|
if (r->auth_len) {
|
@@ -535,8 +532,8 @@ static void redis_on_connect(intptr_t uuid, void *i_) {
|
|
535
532
|
}
|
536
533
|
r->pub_send = 1;
|
537
534
|
fio_unlock(&r->lock);
|
538
|
-
|
539
|
-
|
535
|
+
FIO_LOG_INFO("(redis %d) publication connection established.",
|
536
|
+
(int)getpid());
|
540
537
|
}
|
541
538
|
|
542
539
|
i->protocol.rsv = 0;
|
@@ -639,7 +636,7 @@ static void redis_on_publish_root(const fio_pubsub_engine_s *eng,
|
|
639
636
|
*buf++ = '\r';
|
640
637
|
*buf++ = '\n';
|
641
638
|
*buf = 0;
|
642
|
-
FIO_LOG_DEBUG("(%d) Publishing:\n%s
|
639
|
+
FIO_LOG_DEBUG("(%d) Publishing:\n%s", getpid(), cmd->cmd);
|
643
640
|
cmd->cmd_len = (uintptr_t)buf - (uintptr_t)(cmd + 1);
|
644
641
|
redis_attach_cmd(r, cmd);
|
645
642
|
return;
|
@@ -690,7 +687,7 @@ static void redis_on_internal_publish(fio_msg_s *msg) {
|
|
690
687
|
msg->channel.len -= 8;
|
691
688
|
msg->channel.data += 8;
|
692
689
|
/* forward to publishing */
|
693
|
-
FIO_LOG_DEBUG("Forwarding to engine %p, on channel %s
|
690
|
+
FIO_LOG_DEBUG("Forwarding to engine %p, on channel %s", msg->udata1,
|
694
691
|
msg->channel.data);
|
695
692
|
redis_on_publish_root(msg->udata1, msg->channel, msg->msg, msg->is_json);
|
696
693
|
}
|
@@ -706,7 +703,7 @@ static void redis_forward_reply(fio_pubsub_engine_s *e, FIOBJ reply,
|
|
706
703
|
fio_pubsub_engine_s *engine = (fio_pubsub_engine_s *)fio_str2u64(data + 0);
|
707
704
|
void *callback = (void *)fio_str2u64(data + 8);
|
708
705
|
if (engine != e || !callback) {
|
709
|
-
FIO_LOG_DEBUG("Redis reply not forwarded (callback: %p)
|
706
|
+
FIO_LOG_DEBUG("Redis reply not forwarded (callback: %p)", callback);
|
710
707
|
return;
|
711
708
|
}
|
712
709
|
int32_t pid = (int32_t)fio_str2u32(data + 24);
|
@@ -740,7 +737,7 @@ static void redis_on_internal_reply(fio_msg_s *msg) {
|
|
740
737
|
fio_pubsub_engine_s *engine =
|
741
738
|
(fio_pubsub_engine_s *)fio_str2u64(msg->channel.data + 0);
|
742
739
|
if (engine != msg->udata1) {
|
743
|
-
FIO_LOG_DEBUG("Redis reply not forwarded (engine mismatch: %p != %p)
|
740
|
+
FIO_LOG_DEBUG("Redis reply not forwarded (engine mismatch: %p != %p)",
|
744
741
|
(void *)engine, msg->udata1);
|
745
742
|
return;
|
746
743
|
}
|
@@ -759,8 +756,7 @@ intptr_t redis_engine_send(fio_pubsub_engine_s *engine, FIOBJ command,
|
|
759
756
|
void *udata),
|
760
757
|
void *udata) {
|
761
758
|
if ((uintptr_t)engine < 4) {
|
762
|
-
|
763
|
-
"core engines\n");
|
759
|
+
FIO_LOG_WARNING("(redis send) trying to use one of the core engines");
|
764
760
|
return -1;
|
765
761
|
}
|
766
762
|
// if(fio_is_master()) {
|
@@ -830,8 +826,11 @@ static void redis_on_engine_fork(void *r_) {
|
|
830
826
|
fio_pubsub_engine_s *redis_engine_create
|
831
827
|
FIO_IGNORE_MACRO(struct redis_engine_create_args args) {
|
832
828
|
if (getpid() != fio_parent_pid()) {
|
833
|
-
|
834
|
-
|
829
|
+
FIO_LOG_FATAL("(redis) Redis engine initialization can only "
|
830
|
+
"be performed in the Root process.");
|
831
|
+
kill(0, SIGINT);
|
832
|
+
fio_stop();
|
833
|
+
return NULL;
|
835
834
|
}
|
836
835
|
if (!args.address.len && args.address.data)
|
837
836
|
args.address.len = strlen(args.address.data);
|
@@ -911,6 +910,7 @@ FIO_IGNORE_MACRO(struct redis_engine_create_args args) {
|
|
911
910
|
/* if restarting */
|
912
911
|
fio_state_callback_add(FIO_CALL_PRE_START, redis_on_facil_start, r);
|
913
912
|
|
913
|
+
FIO_LOG_DEBUG("Redis engine initialized %p", (void *)r);
|
914
914
|
return &r->en;
|
915
915
|
}
|
916
916
|
|
@@ -925,6 +925,6 @@ void redis_engine_destroy(fio_pubsub_engine_s *engine) {
|
|
925
925
|
fio_state_callback_remove(FIO_CALL_IN_CHILD, redis_on_engine_fork, r);
|
926
926
|
fio_state_callback_remove(FIO_CALL_ON_SHUTDOWN, redis_on_facil_shutdown, r);
|
927
927
|
fio_state_callback_remove(FIO_CALL_PRE_START, redis_on_facil_start, r);
|
928
|
-
FIO_LOG_DEBUG("Redis engine destroyed %p
|
928
|
+
FIO_LOG_DEBUG("Redis engine destroyed %p", (void *)r);
|
929
929
|
redis_free(r);
|
930
930
|
}
|
data/ext/iodine/websockets.c
CHANGED
@@ -116,6 +116,7 @@ struct ws_s {
|
|
116
116
|
size_t max_msg_size;
|
117
117
|
/** active pub/sub subscriptions */
|
118
118
|
fio_ls_s subscriptions;
|
119
|
+
fio_lock_i sub_lock;
|
119
120
|
/** socket buffer. */
|
120
121
|
struct buffer_s buffer;
|
121
122
|
/** data length (how much of the buffer actually used). */
|
@@ -133,9 +134,11 @@ Create/Destroy the websocket subscription objects
|
|
133
134
|
***************************************************************************** */
|
134
135
|
|
135
136
|
static inline void clear_subscriptions(ws_s *ws) {
|
137
|
+
fio_lock(&ws->sub_lock);
|
136
138
|
while (fio_ls_any(&ws->subscriptions)) {
|
137
139
|
fio_unsubscribe(fio_ls_pop(&ws->subscriptions));
|
138
140
|
}
|
141
|
+
fio_unlock(&ws->sub_lock);
|
139
142
|
}
|
140
143
|
|
141
144
|
/* *****************************************************************************
|
@@ -325,7 +328,7 @@ void websocket_attach(intptr_t uuid, http_settings_s *http_settings,
|
|
325
328
|
websocket_settings_s *args, void *data, size_t length) {
|
326
329
|
ws_s *ws = new_websocket(uuid);
|
327
330
|
if (!ws) {
|
328
|
-
|
331
|
+
FIO_LOG_FATAL("couldn't allocate Websocket protocol object");
|
329
332
|
exit(errno);
|
330
333
|
}
|
331
334
|
// we have an active websocket connection - prep the connection buffer
|
@@ -615,10 +618,7 @@ uintptr_t websocket_subscribe(struct websocket_subscribe_s args) {
|
|
615
618
|
if (!args.ws)
|
616
619
|
goto error;
|
617
620
|
websocket_sub_data_s *d = malloc(sizeof(*d));
|
618
|
-
|
619
|
-
websocket_close(args.ws);
|
620
|
-
goto error;
|
621
|
-
}
|
621
|
+
FIO_ASSERT_ALLOC(d);
|
622
622
|
*d = (websocket_sub_data_s){
|
623
623
|
.udata = args.udata,
|
624
624
|
.on_message = args.on_message,
|
@@ -640,7 +640,10 @@ uintptr_t websocket_subscribe(struct websocket_subscribe_s args) {
|
|
640
640
|
/* don't free `d`, return (`d` freed by callback) */
|
641
641
|
return 0;
|
642
642
|
}
|
643
|
+
fio_lock(&args.ws->sub_lock);
|
643
644
|
fio_ls_push(&args.ws->subscriptions, sub);
|
645
|
+
fio_unlock(&args.ws->sub_lock);
|
646
|
+
|
644
647
|
return (uintptr_t)args.ws->subscriptions.prev;
|
645
648
|
error:
|
646
649
|
if (args.on_unsubscribe)
|
@@ -653,7 +656,10 @@ error:
|
|
653
656
|
*/
|
654
657
|
void websocket_unsubscribe(ws_s *ws, uintptr_t subscription_id) {
|
655
658
|
fio_unsubscribe((subscription_s *)((fio_ls_s *)subscription_id)->obj);
|
659
|
+
fio_lock(&ws->sub_lock);
|
656
660
|
fio_ls_remove((fio_ls_s *)subscription_id);
|
661
|
+
fio_unlock(&ws->sub_lock);
|
662
|
+
|
657
663
|
(void)ws;
|
658
664
|
}
|
659
665
|
|
data/lib/iodine.rb
CHANGED
@@ -121,6 +121,18 @@ if(!defined?(after_fork))
|
|
121
121
|
Iodine.after_fork(*args, &block)
|
122
122
|
end
|
123
123
|
end
|
124
|
+
if(!defined?(after_fork_in_worker))
|
125
|
+
# Performs a block of code whenever a new worker process spins up (performed once per worker).
|
126
|
+
def after_fork_in_worker(*args, &block)
|
127
|
+
Iodine.after_fork_in_worker(*args, &block)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
if(!defined?(after_fork_in_master))
|
131
|
+
# Performs a block of code whenever a new worker process spins up (performed once per worker).
|
132
|
+
def after_fork_in_master(*args, &block)
|
133
|
+
Iodine.after_fork_in_master(*args, &block)
|
134
|
+
end
|
135
|
+
end
|
124
136
|
if(!defined?(on_worker_boot))
|
125
137
|
# Performs a block of code whenever a new worker process spins up (performed once per worker).
|
126
138
|
def on_worker_boot(*args, &block)
|
@@ -128,7 +140,7 @@ if(!defined?(on_worker_boot))
|
|
128
140
|
end
|
129
141
|
end
|
130
142
|
if(!defined?(before_fork))
|
131
|
-
# Performs a block of code just before a new worker process spins up (performed once per worker).
|
143
|
+
# Performs a block of code just before a new worker process spins up (performed once per worker, in the master thread).
|
132
144
|
def before_fork(*args, &block)
|
133
145
|
Iodine.before_fork(*args, &block)
|
134
146
|
end
|