iodine 0.4.19 → 0.5.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/CHANGELOG.md +22 -0
  4. data/LIMITS.md +19 -9
  5. data/README.md +92 -77
  6. data/SPEC-PubSub-Draft.md +113 -0
  7. data/SPEC-Websocket-Draft.md +127 -143
  8. data/bin/http-hello +0 -1
  9. data/bin/raw-rbhttp +1 -1
  10. data/bin/raw_broadcast +8 -10
  11. data/bin/updated api +2 -2
  12. data/bin/ws-broadcast +2 -4
  13. data/bin/ws-echo +2 -2
  14. data/examples/config.ru +13 -13
  15. data/examples/echo.ru +5 -6
  16. data/examples/hello.ru +2 -3
  17. data/examples/info.md +316 -0
  18. data/examples/pubsub_engine.ru +81 -0
  19. data/examples/redis.ru +9 -9
  20. data/examples/shootout.ru +45 -11
  21. data/ext/iodine/defer.c +194 -297
  22. data/ext/iodine/defer.h +61 -53
  23. data/ext/iodine/evio.c +0 -260
  24. data/ext/iodine/evio.h +50 -22
  25. data/ext/iodine/evio_callbacks.c +26 -0
  26. data/ext/iodine/evio_epoll.c +251 -0
  27. data/ext/iodine/evio_kqueue.c +193 -0
  28. data/ext/iodine/extconf.rb +1 -1
  29. data/ext/iodine/facil.c +1420 -542
  30. data/ext/iodine/facil.h +151 -64
  31. data/ext/iodine/fio_ary.h +418 -0
  32. data/ext/iodine/{base64.c → fio_base64.c} +33 -24
  33. data/ext/iodine/{base64.h → fio_base64.h} +6 -7
  34. data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
  35. data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
  36. data/ext/iodine/fio_hashmap.h +759 -0
  37. data/ext/iodine/fio_json_parser.h +651 -0
  38. data/ext/iodine/fio_llist.h +257 -0
  39. data/ext/iodine/fio_mem.c +672 -0
  40. data/ext/iodine/fio_mem.h +140 -0
  41. data/ext/iodine/fio_random.c +248 -0
  42. data/ext/iodine/{random.h → fio_random.h} +11 -14
  43. data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
  44. data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
  45. data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
  46. data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
  47. data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
  48. data/ext/iodine/fio_siphash.h +18 -0
  49. data/ext/iodine/fio_tmpfile.h +38 -0
  50. data/ext/iodine/fiobj.h +24 -7
  51. data/ext/iodine/fiobj4sock.h +23 -0
  52. data/ext/iodine/fiobj_ary.c +143 -226
  53. data/ext/iodine/fiobj_ary.h +17 -16
  54. data/ext/iodine/fiobj_data.c +1160 -0
  55. data/ext/iodine/fiobj_data.h +164 -0
  56. data/ext/iodine/fiobj_hash.c +298 -406
  57. data/ext/iodine/fiobj_hash.h +101 -54
  58. data/ext/iodine/fiobj_json.c +478 -601
  59. data/ext/iodine/fiobj_json.h +34 -9
  60. data/ext/iodine/fiobj_numbers.c +383 -51
  61. data/ext/iodine/fiobj_numbers.h +87 -11
  62. data/ext/iodine/fiobj_str.c +423 -184
  63. data/ext/iodine/fiobj_str.h +81 -32
  64. data/ext/iodine/fiobject.c +273 -522
  65. data/ext/iodine/fiobject.h +477 -112
  66. data/ext/iodine/http.c +2243 -83
  67. data/ext/iodine/http.h +842 -121
  68. data/ext/iodine/http1.c +810 -385
  69. data/ext/iodine/http1.h +16 -39
  70. data/ext/iodine/http1_parser.c +146 -74
  71. data/ext/iodine/http1_parser.h +15 -4
  72. data/ext/iodine/http_internal.c +1258 -0
  73. data/ext/iodine/http_internal.h +226 -0
  74. data/ext/iodine/http_mime_parser.h +341 -0
  75. data/ext/iodine/iodine.c +86 -68
  76. data/ext/iodine/iodine.h +26 -11
  77. data/ext/iodine/iodine_helpers.c +8 -7
  78. data/ext/iodine/iodine_http.c +487 -324
  79. data/ext/iodine/iodine_json.c +304 -0
  80. data/ext/iodine/iodine_json.h +6 -0
  81. data/ext/iodine/iodine_protocol.c +107 -45
  82. data/ext/iodine/iodine_pubsub.c +526 -225
  83. data/ext/iodine/iodine_pubsub.h +10 -0
  84. data/ext/iodine/iodine_websockets.c +268 -510
  85. data/ext/iodine/iodine_websockets.h +2 -4
  86. data/ext/iodine/pubsub.c +726 -432
  87. data/ext/iodine/pubsub.h +85 -103
  88. data/ext/iodine/rb-call.c +4 -4
  89. data/ext/iodine/rb-defer.c +46 -22
  90. data/ext/iodine/rb-fiobj2rb.h +117 -0
  91. data/ext/iodine/rb-rack-io.c +73 -238
  92. data/ext/iodine/rb-rack-io.h +2 -2
  93. data/ext/iodine/rb-registry.c +35 -93
  94. data/ext/iodine/rb-registry.h +1 -0
  95. data/ext/iodine/redis_engine.c +742 -304
  96. data/ext/iodine/redis_engine.h +42 -39
  97. data/ext/iodine/resp_parser.h +311 -0
  98. data/ext/iodine/sock.c +627 -490
  99. data/ext/iodine/sock.h +345 -297
  100. data/ext/iodine/spnlock.inc +15 -4
  101. data/ext/iodine/websocket_parser.h +16 -20
  102. data/ext/iodine/websockets.c +188 -257
  103. data/ext/iodine/websockets.h +24 -133
  104. data/lib/iodine.rb +52 -7
  105. data/lib/iodine/cli.rb +6 -24
  106. data/lib/iodine/json.rb +40 -0
  107. data/lib/iodine/version.rb +1 -1
  108. data/lib/iodine/websocket.rb +5 -3
  109. data/lib/rack/handler/iodine.rb +58 -13
  110. metadata +38 -48
  111. data/bin/ws-shootout +0 -107
  112. data/examples/broadcast.ru +0 -56
  113. data/ext/iodine/bscrypt-common.h +0 -116
  114. data/ext/iodine/bscrypt.h +0 -49
  115. data/ext/iodine/fio2resp.c +0 -60
  116. data/ext/iodine/fio2resp.h +0 -51
  117. data/ext/iodine/fio_dict.c +0 -446
  118. data/ext/iodine/fio_dict.h +0 -99
  119. data/ext/iodine/fio_hash_table.h +0 -370
  120. data/ext/iodine/fio_list.h +0 -111
  121. data/ext/iodine/fiobj_internal.h +0 -280
  122. data/ext/iodine/fiobj_primitives.c +0 -131
  123. data/ext/iodine/fiobj_primitives.h +0 -55
  124. data/ext/iodine/fiobj_sym.c +0 -135
  125. data/ext/iodine/fiobj_sym.h +0 -60
  126. data/ext/iodine/hex.c +0 -124
  127. data/ext/iodine/hex.h +0 -70
  128. data/ext/iodine/http1_request.c +0 -81
  129. data/ext/iodine/http1_request.h +0 -58
  130. data/ext/iodine/http1_response.c +0 -417
  131. data/ext/iodine/http1_response.h +0 -95
  132. data/ext/iodine/http_request.c +0 -111
  133. data/ext/iodine/http_request.h +0 -102
  134. data/ext/iodine/http_response.c +0 -1703
  135. data/ext/iodine/http_response.h +0 -250
  136. data/ext/iodine/misc.c +0 -182
  137. data/ext/iodine/misc.h +0 -74
  138. data/ext/iodine/random.c +0 -208
  139. data/ext/iodine/redis_connection.c +0 -278
  140. data/ext/iodine/redis_connection.h +0 -86
  141. data/ext/iodine/resp.c +0 -842
  142. data/ext/iodine/resp.h +0 -261
  143. data/ext/iodine/siphash.c +0 -154
  144. data/ext/iodine/siphash.h +0 -22
  145. data/ext/iodine/xor-crypt.c +0 -193
  146. data/ext/iodine/xor-crypt.h +0 -107
data/ext/iodine/pubsub.h CHANGED
@@ -6,19 +6,21 @@ Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
7
  #ifndef H_FACIL_PUBSUB_H
8
8
  /**
9
- This pub/sub API is designed to unload pub/sub stress from external messanging
10
- systems onto the local process.
11
-
12
- For example, the NULL pub/sub engine, which is routed to the facil_cluster
13
- engine, will only publish a single message per process instead of a message per
14
- client, allowing the cluster communication channel to be less crowded when
15
- possible.
16
-
17
- This should allow pub/sub engines, such as Redis, to spread their workload
18
- between all of an application's processes, enhancing overall performance.
9
+ * This pub/sub API is designed to unload pub/sub stress from external messanging
10
+ * systems onto the local process.
11
+
12
+ * For example, the NULL pub/sub engine, which is routed to the facil_cluster
13
+ * engine, will only publish a single message per process instead of a message
14
+ per
15
+ * client, allowing the cluster communication channel to be less crowded when
16
+ * possible.
17
+ *
18
+ * This should allow pub/sub engines, such as Redis, to spread their workload
19
+ * between all of an application's processes, enhancing overall performance.
19
20
  */
20
21
  #define H_FACIL_PUBSUB_H
21
22
  #include "facil.h"
23
+ #include "fiobj.h"
22
24
 
23
25
  /* support C++ */
24
26
  #ifdef __cplusplus
@@ -35,22 +37,31 @@ typedef struct pubsub_sub_s *pubsub_sub_pt;
35
37
  /** A pub/sub engine data structure. See details later on. */
36
38
  typedef struct pubsub_engine_s pubsub_engine_s;
37
39
 
38
- /** The information a "client" (callback) receives. */
40
+ /** The default pub/sub engine.
41
+ * This engine performs pub/sub within a group of processes (process cluster).
42
+ *
43
+ * The process cluser is initialized by the `facil_run` command with `processes`
44
+ * set to more than 1.
45
+ */
46
+ extern pubsub_engine_s const *PUBSUB_CLUSTER_ENGINE;
47
+
48
+ /** An engine that performs pub/sub only within a single process. */
49
+ extern pubsub_engine_s const *PUBSUB_PROCESS_ENGINE;
50
+
51
+ /** Allows process wide changes to the default Pub/Sub Engine.
52
+ * Setting a new default before calling `facil_run` will change the default for
53
+ * the whole process cluster.
54
+ */
55
+ extern pubsub_engine_s *PUBSUB_DEFAULT_ENGINE;
56
+
57
+ /** Publishing and on_message callback arguments. */
39
58
  typedef struct pubsub_message_s {
40
- /** The pub/sub engine farwarding this message. */
59
+ /** The pub/sub engine that should be used to farward this message. */
41
60
  pubsub_engine_s const *engine;
42
61
  /** The pub/sub target channnel. */
43
- struct {
44
- char *name;
45
- uint32_t len;
46
- } channel;
62
+ FIOBJ channel;
47
63
  /** The pub/sub message. */
48
- struct {
49
- char *data;
50
- uint32_t len;
51
- } msg;
52
- /** indicates that pattern matching was used. */
53
- unsigned use_pattern : 1;
64
+ FIOBJ message;
54
65
  /** The subscription that prompted the message to be routed to the client. */
55
66
  pubsub_sub_pt subscription;
56
67
  /** Client opaque data pointer (from the `subscribe`) function call. */
@@ -61,13 +72,8 @@ typedef struct pubsub_message_s {
61
72
 
62
73
  /** The arguments used for `pubsub_subscribe` or `pubsub_find_sub`. */
63
74
  struct pubsub_subscribe_args {
64
- /** The pub/sub engine to use. NULL defaults to the local cluster engine. */
65
- pubsub_engine_s const *engine;
66
- /** The channel to subscribe to. */
67
- struct {
68
- char *name;
69
- uint32_t len;
70
- } channel;
75
+ /** The channel namr used for the subscription. */
76
+ FIOBJ channel;
71
77
  /** The on message callback. the `*msg` pointer is to a temporary object. */
72
78
  void (*on_message)(pubsub_message_s *msg);
73
79
  /** An optional callback for when a subscription is fully canceled. */
@@ -80,34 +86,12 @@ struct pubsub_subscribe_args {
80
86
  unsigned use_pattern : 1;
81
87
  };
82
88
 
83
- /** The arguments used for `pubsub_publish`. */
84
- struct pubsub_publish_args {
85
- /** The pub/sub engine to use. NULL defaults to the local cluster engine. */
86
- pubsub_engine_s const *engine;
87
- /** The channel to publish to. */
88
- struct {
89
- char *name;
90
- uint32_t len;
91
- } channel;
92
- /** The data being pushed. */
93
- struct {
94
- char *data;
95
- uint32_t len;
96
- } msg;
97
- /** Use pattern matching for channel publication. */
98
- unsigned use_pattern : 1;
99
- /**
100
- * Push the message to the whole cluster, using the cluster engine.
101
- * Always TRUE unless an engine was specified.
102
- */
103
- unsigned push2cluster : 1;
104
- };
105
-
106
89
  /**
107
90
  * Subscribes to a specific channel.
108
91
  *
109
92
  * Returns a subscription pointer or NULL (failure).
110
- */ pubsub_sub_pt pubsub_subscribe(struct pubsub_subscribe_args);
93
+ */
94
+ pubsub_sub_pt pubsub_subscribe(struct pubsub_subscribe_args);
111
95
  #define pubsub_subscribe(...) \
112
96
  pubsub_subscribe((struct pubsub_subscribe_args){__VA_ARGS__})
113
97
 
@@ -125,20 +109,28 @@ pubsub_sub_pt pubsub_find_sub(struct pubsub_subscribe_args);
125
109
  pubsub_find_sub((struct pubsub_subscribe_args){__VA_ARGS__})
126
110
 
127
111
  /**
128
- * Unsubscribes from a specific channel.
112
+ * Unsubscribes from a specific subscription.
113
+ *
114
+ * Note: This should be called exactly the same number times as
115
+ * `pubsub_subscribe`. Any less and a memory leak might occur. Any more, and the
116
+ * program might crash.
129
117
  *
130
118
  * Returns 0 on success and -1 on failure.
131
119
  */
132
- void pubsub_unsubscribe(pubsub_sub_pt subscription);
120
+ int pubsub_unsubscribe(pubsub_sub_pt subscription);
133
121
 
134
122
  /**
135
123
  * Publishes a message to a channel belonging to a pub/sub service (engine).
136
124
  *
137
- * Returns 0 on success and -1 on failure.
125
+ * Returns 0 on success and -1 on failure (i.e., no channel, no message or no
126
+ * known subscriptions).
127
+ *
128
+ * NOTE: Memory ownership is retained by the calling function. Both the channel
129
+ * and the message should be freed when the caller is done with them.
138
130
  */
139
- int pubsub_publish(struct pubsub_publish_args);
131
+ int pubsub_publish(struct pubsub_message_s);
140
132
  #define pubsub_publish(...) \
141
- pubsub_publish((struct pubsub_publish_args){__VA_ARGS__})
133
+ pubsub_publish((struct pubsub_message_s){__VA_ARGS__})
142
134
 
143
135
  /**
144
136
  * defers message hadling if it can't be performed (i.e., resource is busy) or
@@ -160,59 +152,49 @@ void pubsub_defer(pubsub_message_s *msg);
160
152
  /**
161
153
  * Pub/Sub services (engines) MUST provide the listed function pointers.
162
154
  *
155
+ * Engines should also register using the `pubsub_engine_register` function.
156
+ *
157
+ * Engines should deregister, before being destroyed, by using the
158
+ * `pubsub_engine_deregister` function.
159
+ *
163
160
  * When an engine received a message to publish, they should call the
164
- * `pubsub_eng_distribute` function. i.e.:
165
- *
166
- * pubsub_engine_distribute(
167
- * .engine = self,
168
- * .channel.name = "channel 1",
169
- * .channel.len = 9,
170
- * .msg.data = "hello",
171
- * .msg.len = 5,
172
- * .push2cluster = self->push2cluster,
173
- * .use_pattern = 0 );
174
- *
175
- * Engines MUST survive until the pub/sub service is finished using them and
176
- * there are no more subscriptions.
161
+ * `pubsub_publish` function with the engine to which the message is forwarded.
162
+ * i.e.:
163
+ *
164
+ * pubsub_publish(
165
+ * .engine = PUBSUB_PROCESS_ENGINE,
166
+ * .channel = channel_name,
167
+ * .message = msg_body );
168
+ *
169
+ * Engines MUST NOT free any of the FIOBJ objects they receive.
170
+ *
177
171
  */
178
172
  struct pubsub_engine_s {
179
- /** Should return 0 on success and -1 on failure. */
180
- int (*subscribe)(const pubsub_engine_s *eng, const char *ch, size_t ch_len,
181
- uint8_t use_pattern);
182
- /** Return value is ignored. */
183
- void (*unsubscribe)(const pubsub_engine_s *eng, const char *ch, size_t ch_len,
173
+ /** Must subscribe channel. Failures are ignored. */
174
+ void (*subscribe)(const pubsub_engine_s *eng, FIOBJ channel,
175
+ uint8_t use_pattern);
176
+ /** Must unsubscribe channel. Failures are ignored. */
177
+ void (*unsubscribe)(const pubsub_engine_s *eng, FIOBJ channel,
184
178
  uint8_t use_pattern);
185
179
  /** Should return 0 on success and -1 on failure. */
186
- int (*publish)(const pubsub_engine_s *eng, const char *ch, size_t ch_len,
187
- const char *msg, size_t msg_len, uint8_t use_pattern);
188
- /** Set to TRUE (1) if published messages should propegate to the cluster. */
189
- unsigned push2cluster : 1;
180
+ int (*publish)(const pubsub_engine_s *eng, FIOBJ channel, FIOBJ msg);
181
+ /**
182
+ * facil.io will call this callback whenever starting, or restarting, the
183
+ * reactor.
184
+ *
185
+ * This will be called when facil.io starts (the master process).
186
+ *
187
+ * This will also be called when forking, after facil.io closes all
188
+ * connections and claim to shut down (running all deferred event).
189
+ */
190
+ void (*on_startup)(const pubsub_engine_s *eng);
190
191
  };
191
192
 
192
- /** The default pub/sub engine.
193
- * This engine performs pub/sub within a group of processes (process cluster).
194
- *
195
- * The process cluser is initialized by the `facil_run` command with `processes`
196
- * set to more than 1.
197
- */
198
- extern const pubsub_engine_s *PUBSUB_CLUSTER_ENGINE;
199
-
200
- /** An engine that performs pub/sub only within a single process. */
201
- extern const pubsub_engine_s *PUBSUB_PROCESS_ENGINE;
202
-
203
- /** Allows process wide changes to the default Pub/Sub Engine.
204
- * Setting a new default before calling `facil_run` will change the default for
205
- * the whole process cluster.
206
- */
207
- extern const pubsub_engine_s *PUBSUB_DEFAULT_ENGINE;
193
+ /** Registers an engine, so it's callback can be called. */
194
+ void pubsub_engine_register(pubsub_engine_s *engine);
208
195
 
209
- /**
210
- * The function used by engines to distribute received messages.
211
- * The `udata*` and `subscription` fields are ignored.
212
- */
213
- void pubsub_engine_distribute(pubsub_message_s msg);
214
- #define pubsub_engine_distribute(...) \
215
- pubsub_engine_distribute((pubsub_message_s){__VA_ARGS__})
196
+ /** Unregisters an engine, so it could be safely destroyed. */
197
+ void pubsub_engine_deregister(pubsub_engine_s *engine);
216
198
 
217
199
  /**
218
200
  * Engines can ask facil.io to resubscribe to all active channels.
data/ext/iodine/rb-call.c CHANGED
@@ -23,7 +23,6 @@ typedef struct {
23
23
  VALUE obj;
24
24
  int argc;
25
25
  VALUE *argv;
26
- VALUE returned;
27
26
  ID method;
28
27
  int exception;
29
28
  } iodine_rb_task_s;
@@ -70,7 +69,7 @@ static void *handle_exception(void *ignr) {
70
69
  (int)RSTRING_LEN(msg), RSTRING_PTR(msg));
71
70
  }
72
71
  rb_backtrace();
73
- fprintf(stderr, "\n");
72
+ fprintf(stderr, "\n\n");
74
73
  rb_set_errinfo(Qnil);
75
74
  }
76
75
  return (void *)Qnil;
@@ -130,8 +129,9 @@ static VALUE iodin_rb_call_arg(VALUE obj, ID method, int argc, VALUE *argv) {
130
129
  .argc = argc,
131
130
  .argv = argv};
132
131
  void *ret;
133
- if (in_gvl)
134
- return (VALUE)rb_funcall2(obj, method, argc, argv);
132
+ if (in_gvl) {
133
+ return (VALUE)iodine_protected_call(&task);
134
+ }
135
135
  in_gvl = 1;
136
136
  ret = rb_thread_call_with_gvl(iodine_protected_call, &task);
137
137
  in_gvl = 0;
@@ -6,14 +6,19 @@ Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
7
  // clang-format off
8
8
  #include "rb-registry.h"
9
+ #include "rb-call.h"
10
+ #include "iodine.h"
9
11
  #include <ruby.h>
10
12
  #include <ruby/thread.h>
11
13
 
12
14
  #include <stdint.h>
13
15
  // clang-format on
14
16
 
17
+ #include <spnlock.inc>
15
18
  #include "defer.h"
16
19
 
20
+ #include <pthread.h>
21
+
17
22
  /* *****************************************************************************
18
23
  Local helpers
19
24
  ***************************************************************************** */
@@ -26,33 +31,46 @@ struct CreateThreadArgs {
26
31
  /* used here but declared elsewhere */
27
32
  void call_async_signal(void *pool) { defer_pool_stop((pool_pt)pool); }
28
33
 
29
- /* the thread's GVL release */
30
- static VALUE thread_loop(void *args_) {
34
+ static void *defer_thread_start(void *args_) {
31
35
  struct CreateThreadArgs *args = args_;
32
36
  void *(*thread_func)(void *) = args->thread_func;
33
37
  void *arg = args->arg;
34
- free(args_);
35
- rb_thread_call_without_gvl2(thread_func, arg,
36
- (void (*)(void *))call_async_signal, arg);
38
+ free(args);
39
+ RubyCaller.set_gvl_state(0);
40
+ thread_func(arg);
41
+ return NULL;
42
+ }
43
+
44
+ /* the thread's GVL release */
45
+ static VALUE defer_thread_inGVL(void *args_) {
46
+ struct CreateThreadArgs *args = args_;
47
+ rb_thread_call_without_gvl(defer_thread_start, args_,
48
+ (void (*)(void *))call_async_signal, args->arg);
37
49
  return Qnil;
38
50
  }
39
51
 
40
52
  /* Within the GVL, creates a Ruby thread using an API call */
41
53
  static void *create_ruby_thread_gvl(void *args) {
42
- return (void *)Registry.add(rb_thread_create(thread_loop, args));
43
- }
44
-
45
- /* protect the call to join from any exceptions */
46
- static void *inner_join_with_rbthread_(void *rbt) {
47
- return (void *)rb_funcall((VALUE)rbt, rb_intern("join"), 0);
54
+ return (void *)Registry.add(rb_thread_create(defer_thread_inGVL, args));
48
55
  }
49
56
 
50
57
  static void *fork_using_ruby(void *ignr) {
58
+ RubyCaller.call(Iodine, rb_intern("before_fork"));
51
59
  const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern("Process"));
52
- const VALUE pid = rb_funcall(ProcessClass, rb_intern("fork"), 0);
53
- if (pid == Qnil)
54
- return (void *)0;
55
- return (void *)(intptr_t)(NUM2INT(pid));
60
+ const VALUE rb_pid = RubyCaller.call(ProcessClass, rb_intern("fork"));
61
+ intptr_t pid = 0;
62
+ if (rb_pid != Qnil) {
63
+ pid = NUM2INT(rb_pid);
64
+ } else {
65
+ pid = 0;
66
+ }
67
+ RubyCaller.set_gvl_state(1); /* enforce GVL state in thread storage */
68
+ if (!pid) {
69
+ Registry.on_fork();
70
+ RubyCaller.call(Iodine, rb_intern("after_fork"));
71
+ }
72
+ return (void *)pid;
73
+ (void)ignr;
56
74
  }
57
75
 
58
76
  /* *****************************************************************************
@@ -62,14 +80,17 @@ The Defer library overriding functions
62
80
  /**
63
81
  OVERRIDE THIS to replace the default pthread implementation.
64
82
  */
65
- void *defer_new_thread(void *(*thread_func)(void *), pool_pt pool) {
83
+ void *defer_new_thread(void *(*thread_func)(void *), void *arg) {
66
84
  struct CreateThreadArgs *data = malloc(sizeof(*data));
67
85
  if (!data)
68
86
  return NULL;
69
- *data = (struct CreateThreadArgs){.thread_func = thread_func, .arg = pool};
70
- void *thr = rb_thread_call_with_gvl(create_ruby_thread_gvl, data);
71
- if (!thr || thr == (void *)Qnil || thr == (void *)Qfalse)
87
+ *data = (struct CreateThreadArgs){
88
+ .thread_func = thread_func, .arg = arg,
89
+ };
90
+ void *thr = RubyCaller.call_c(create_ruby_thread_gvl, data);
91
+ if (!thr || thr == (void *)Qnil || thr == (void *)Qfalse) {
72
92
  thr = NULL;
93
+ }
73
94
  return thr;
74
95
  }
75
96
 
@@ -79,18 +100,21 @@ OVERRIDE THIS to replace the default pthread implementation.
79
100
  int defer_join_thread(void *thr) {
80
101
  if (!thr || (VALUE)thr == Qfalse || (VALUE)thr == Qnil)
81
102
  return -1;
82
- rb_thread_call_with_gvl(inner_join_with_rbthread_, (void *)thr);
103
+ RubyCaller.call((VALUE)thr, rb_intern("join"));
83
104
  Registry.remove((VALUE)thr);
84
105
  return 0;
85
106
  }
86
107
 
108
+ // void defer_free_thread(void *thr) { (void)thr; }
109
+ void defer_free_thread(void *thr) { Registry.remove((VALUE)thr); }
110
+
87
111
  /**
88
112
  OVERRIDE THIS to replace the default `fork` implementation or to inject hooks
89
113
  into the forking function.
90
114
 
91
115
  Behaves like the system's `fork`.
92
116
  */
93
- int defer_new_child(void) {
94
- intptr_t pid = (intptr_t)rb_thread_call_with_gvl(fork_using_ruby, NULL);
117
+ int facil_fork(void) {
118
+ intptr_t pid = (intptr_t)RubyCaller.call_c(fork_using_ruby, NULL);
95
119
  return (int)pid;
96
120
  }
@@ -0,0 +1,117 @@
1
+ #ifndef H_RB_FIOBJ2RUBY_H
2
+ /*
3
+ Copyright: Boaz segev, 2016-2017
4
+ License: MIT
5
+
6
+ Feel free to copy, use and enjoy according to the license provided.
7
+ */
8
+ #define H_RB_FIOBJ2RUBY_H
9
+ #include <fiobj.h>
10
+ #include <ruby.h>
11
+
12
+ #include "rb-registry.h"
13
+
14
+ typedef struct {
15
+ FIOBJ stack;
16
+ uintptr_t count;
17
+ VALUE rb;
18
+ uint8_t str2sym;
19
+ } fiobj2rb_s;
20
+
21
+ typedef struct { uint8_t str2sym; } fiobj2rb_settings_s;
22
+
23
+ static inline VALUE fiobj2rb(FIOBJ o, uint8_t str2sym) {
24
+ VALUE rb;
25
+ if (!o)
26
+ return Qnil;
27
+ switch (FIOBJ_TYPE(o)) {
28
+ case FIOBJ_T_NUMBER:
29
+ rb = LONG2FIX(fiobj_obj2num(o));
30
+ break;
31
+ case FIOBJ_T_NULL:
32
+ rb = Qnil;
33
+ break;
34
+ case FIOBJ_T_TRUE:
35
+ rb = Qtrue;
36
+ break;
37
+ case FIOBJ_T_FALSE:
38
+ rb = Qfalse;
39
+ break;
40
+ case FIOBJ_T_FLOAT:
41
+ rb = DBL2NUM(fiobj_obj2float(o));
42
+ break;
43
+ case FIOBJ_T_DATA: /* fallthrough */
44
+ case FIOBJ_T_UNKNOWN: /* fallthrough */
45
+ case FIOBJ_T_STRING: {
46
+ fio_cstr_s tmp = fiobj_obj2cstr(o);
47
+ if (str2sym) {
48
+ rb = rb_intern2(tmp.data, tmp.len);
49
+ rb = ID2SYM(rb);
50
+ } else {
51
+ rb = rb_str_new(tmp.data, tmp.len);
52
+ }
53
+
54
+ } break;
55
+ case FIOBJ_T_ARRAY:
56
+ rb = rb_ary_new();
57
+ break;
58
+ case FIOBJ_T_HASH:
59
+ rb = rb_hash_new();
60
+ break;
61
+ };
62
+ return rb;
63
+ }
64
+
65
+ static int fiobj2rb_task(FIOBJ o, void *data_) {
66
+ fiobj2rb_s *data = data_;
67
+ VALUE rb_tmp;
68
+ rb_tmp = fiobj2rb(o, 0);
69
+ Registry.add(rb_tmp);
70
+ if (data->rb) {
71
+ if (RB_TYPE_P(data->rb, T_HASH)) {
72
+ rb_hash_aset(data->rb, fiobj2rb(fiobj_hash_key_in_loop(), data->str2sym),
73
+ rb_tmp);
74
+ } else {
75
+ rb_ary_push(data->rb, rb_tmp);
76
+ }
77
+ --(data->count);
78
+ Registry.remove(rb_tmp);
79
+ } else {
80
+ data->rb = rb_tmp;
81
+ // Registry.add(rb_tmp);
82
+ }
83
+ if (FIOBJ_TYPE_IS(o, FIOBJ_T_ARRAY)) {
84
+ fiobj_ary_push(data->stack, (FIOBJ)data->count);
85
+ fiobj_ary_push(data->stack, (FIOBJ)data->rb);
86
+ data->count = fiobj_ary_count(o);
87
+ data->rb = rb_tmp;
88
+ } else if (FIOBJ_TYPE_IS(o, FIOBJ_T_HASH)) {
89
+ fiobj_ary_push(data->stack, (FIOBJ)data->count);
90
+ fiobj_ary_push(data->stack, (FIOBJ)data->rb);
91
+ data->count = fiobj_hash_count(o);
92
+ data->rb = rb_tmp;
93
+ }
94
+ while (data->count == 0 && fiobj_ary_count(data->stack)) {
95
+ data->rb = fiobj_ary_pop(data->stack);
96
+ data->count = fiobj_ary_pop(data->stack);
97
+ }
98
+ return 0;
99
+ }
100
+
101
+ static inline VALUE fiobj2rb_deep(FIOBJ obj, uint8_t str2sym) {
102
+ fiobj2rb_s data = {.stack = fiobj_ary_new2(4), .str2sym = str2sym};
103
+
104
+ /* deep copy */
105
+ fiobj_each2(obj, fiobj2rb_task, &data);
106
+ /* cleanup (shouldn't happen, but what the hell)... */
107
+ while (fiobj_ary_pop(data.stack))
108
+ ;
109
+ fiobj_free(data.stack);
110
+ Registry.remove(data.rb);
111
+ return data.rb;
112
+ }
113
+
114
+ // require 'iodine'
115
+ // Iodine::JSON.parse "{\"1\":[1,2,3,4]}"
116
+ // Iodine::JSON.parse IO.binread("")
117
+ #endif /* H_RB_FIOBJ2RUBY_H */