iodine 0.5.0 → 0.5.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ddc0f34881258b83f214f4809227c826c6bc8f1e259a29fecc0d583c2d6c9a69
4
- data.tar.gz: 58686f504218966ed558172cca8176c05fde580c122d8d2dc8196253f31c8d14
3
+ metadata.gz: '0801b0def77514bb565e4330fba285d1a35fc84fb039e8931791f3f49af164f7'
4
+ data.tar.gz: 2f17d26fbae2495c70f1b4d9f822641ad8501940c872a4cd3e1d7636bbfdb1a9
5
5
  SHA512:
6
- metadata.gz: 608097ab4f29ed39435098c4b2930379d164b4e6d76634032ea056efc8b7f55dad2092cc28ab4bdf4172630eb3c707f68eecfd31f0a43c5e3b6511d9268994f6
7
- data.tar.gz: d36b60bc3a67815afa9b2be2c1a2a00a773264146d4ecb5f796e12ab7c143664e2dd3e66f535272ba1c74a6e381e27ff57752d7f88dc3ba4f0d40a7032a6bc19
6
+ metadata.gz: abbb75f0b612e43054d2c1e0725a8bcb7c70815be580fe1b62d6f64ae203a30ac41508f8652b9a005b8d65de17bf0e9f404b9b73a5b6899e2115dfca51bc9d1a
7
+ data.tar.gz: a1cc7e4f532b93c33e3cdb29040eef2ce02b2c3d6b03d13fb3daa96bbce3bc986dae0132694feb41cbc7b0c5c8d689cfe393b0b44cbce1a93ede3745f6d87219
@@ -6,6 +6,12 @@ Please notice that this change log contains changes for upcoming releases as wel
6
6
 
7
7
  ## Changes:
8
8
 
9
+ #### Change log v.0.5.1 (next release)
10
+
11
+ **Fix**: fixed compilation issues on OS X version < 10.12 and Alpine Linux. Credit to @jdickey (Jeff Dickey) for opening issue #32.
12
+
13
+ **Fix**: fixed some documentation errors. Credit to @janko-m (Janko Marohnić) for catching typos in the README.
14
+
9
15
  #### Change log v.0.5.0
10
16
 
11
17
  Changed... everything. At least all the internal bits and some of the API.
data/README.md CHANGED
@@ -7,8 +7,6 @@
7
7
 
8
8
  [![Logo](https://github.com/boazsegev/iodine/raw/master/logo.png)](https://github.com/boazsegev/iodine)
9
9
 
10
- **Notice: *iodine's core library, [facil.io](https://github.com/boazsegev/facil.io) is being re-vamped with many updates and changes. This is a time to ask - what features are important for you? [let me know here](https://github.com/boazsegev/facil.io/issues/24)***.
11
-
12
10
  Iodine is a fast concurrent web server for real-time Ruby applications, with native support for:
13
11
 
14
12
  * Websockets and EventSource (SSE);
@@ -25,7 +23,7 @@ Iodine is an **evented** framework with a simple API that builds off the low lev
25
23
 
26
24
  * Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections)!
27
25
 
28
- * Iodine supports only **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are totally different).
26
+ * Iodine supports only **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are totally different). Currently, macOS support is limited to 10.12 or higher (see [issue #32](https://github.com/boazsegev/iodine/issues/32))
29
27
 
30
28
  Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but Rack requires Ruby 2.2.2, and so iodine matches this requirement.
31
29
 
@@ -145,13 +143,13 @@ Upgrading an HTTP connection can be performed either using iodine's native WebSo
145
143
 
146
144
  Iodine treats EventSource / SSE connections as if they were a half-duplex WebSocket connection, using the exact same API and callbacks as WebSockets.
147
145
 
148
- When an EventSource / SSE request is received, iodine will set the Rack Hash's upgrade property to `:sse`, so that: `env[rack.upgrade?] == :sse`.
146
+ When an EventSource / SSE request is received, iodine will set the Rack Hash's upgrade property to `:sse`, so that: `env['rack.upgrade?'] == :sse`.
149
147
 
150
148
  The rest is detailed in the WebSocket support section.
151
149
 
152
150
  #### WebSockets
153
151
 
154
- When a WebSocket connection request is received, iodine will set the Rack Hash's upgrade property to `:websocket`, so that: `env[rack.upgrade?] == :websocket`
152
+ When a WebSocket connection request is received, iodine will set the Rack Hash's upgrade property to `:websocket`, so that: `env['rack.upgrade?'] == :websocket`
155
153
 
156
154
  To "upgrade" the HTTP request to the WebSockets protocol (or SSE), simply provide iodine with a WebSocket Callback Object instance or class: `env['rack.upgrade'] = MyWebsocketClass` or `env['rack.upgrade'] = MyWebsocketClass.new(args)`
157
155
 
@@ -1,5 +1,7 @@
1
1
  # Ruby's Rack Push: Decoupling the real-time web application from the web
2
2
 
3
+ ![](https://bowild.files.wordpress.com/2018/05/6865783407_84f470ec02_o.jpg)
4
+
3
5
  Something exciting is coming.
4
6
 
5
7
  Everyone is talking about WebSockets and their older cousin EventSource / Server Sent Events (SSE). Faye and ActionCable are all the rage and real-time updates are becoming easier than ever.
@@ -56,7 +58,7 @@ Using `require 'faye'` will add WebSockets to your application, but it will take
56
58
 
57
59
  On the other hand, using the `agoo` or `iodine` HTTP servers will add both WebScokets and SSE to your application without any extra memory consumption.
58
60
 
59
- To be more specific, using `iodine` will consume about 2Mb of memory, less than Puma, while providing both HTTP and real-time capabilities.
61
+ To be more specific, using `iodine` will consume about 2Mb of memory, marginally less than Puma, while providing both HTTP and real-time capabilities.
60
62
 
61
63
  ### The hidden `hijack` price
62
64
 
@@ -111,7 +113,7 @@ To set a callback object, the `env['rack.upgrade']` is introduced (notice the mi
111
113
  Now the design might look like this:
112
114
 
113
115
  ```ruby
114
- # place in config.ru
116
+ # Place in config.ru
115
117
  RESPONSE = [200, { 'Content-Type' => 'text/html',
116
118
  'Content-Length' => '12' }, [ 'Hello World!' ] ]
117
119
  # a Callback class
@@ -130,7 +132,7 @@ end
130
132
  APP = Proc.new do |env|
131
133
  if(env['rack.upgrade?'])
132
134
  env['rack.upgrade'] = MyCallbacks.new
133
- [0, {}, []]
135
+ [200, {}, []]
134
136
  else
135
137
  RESPONSE
136
138
  end
@@ -150,7 +152,7 @@ gem install iodine
150
152
  iodine -t 1
151
153
  ```
152
154
 
153
- Now open the browser, visit [localhost:3000](http://localhost:3000) and open the browser console to test some Javascript.
155
+ Now open the browser, visit [localhost:3000](http://localhost:3000) and open the browser console to test some JavaScript.
154
156
 
155
157
  First try an EventSource (SSE) connection (run in browser console):
156
158
 
@@ -198,7 +200,7 @@ So far, it's so simple, it's hard to notice how powerful this is.
198
200
  Consider implementing a stock ticker, or in this case, a timer:
199
201
 
200
202
  ```ruby
201
- # place in config.ru
203
+ # Place in config.ru
202
204
  RESPONSE = [200, { 'Content-Type' => 'text/html',
203
205
  'Content-Length' => '12' }, [ 'Hello World!' ] ]
204
206
 
@@ -212,10 +214,31 @@ module LiveList
212
214
  def self.>>(connection)
213
215
  @lock.synchronize { @list.delete connection }
214
216
  end
217
+ def any?
218
+ # remove connection to the "live list"
219
+ @lock.synchronize { @list.any? }
220
+ end
221
+ # this will send a message to all the connections that share the same process.
222
+ # (in cluster mode we get partial broadcasting only and this doesn't scale)
215
223
  def self.broadcast(data)
216
- @lock.synchronize {
217
- @list.each {|c| c.write data }
218
- }
224
+ @lock.synchronize do
225
+ @list.each do |c|
226
+ begin
227
+ c.write data
228
+ rescue IOError => _e
229
+ # An IOError can occur if the connection was closed during the loop.
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
235
+
236
+ # Broadcast the time very second... but...
237
+ # Threads will BREAK in cluster mode.
238
+ @thread = Thread.new do
239
+ while(LiveList.any?) do
240
+ sleep(1)
241
+ LiveList.broadcast "The time is: #{Time.now}"
219
242
  end
220
243
  end
221
244
 
@@ -235,19 +258,11 @@ class MyCallbacks
235
258
  end
236
259
  end
237
260
 
238
- # Broadcast the time very second
239
- Thread.new do
240
- while(true) do
241
- sleep(1)
242
- LiveList.broadcast "The time is: #{Time.now}"
243
- end
244
- end
245
-
246
261
  # The Rack application
247
262
  APP = Proc.new do |env|
248
263
  if(env['rack.upgrade?'])
249
264
  env['rack.upgrade'] = MyCallbacks.new
250
- [0, {}, []]
265
+ [200, {}, []]
251
266
  else
252
267
  RESPONSE
253
268
  end
@@ -256,12 +271,22 @@ end
256
271
  run APP
257
272
  ```
258
273
 
259
- For this next example, I will use Iodine's pub/sub extension API to demonstrate the power offered by the new `env['rack.upgrade']` approach. This avoids the LiveList object and will make scaling easier.
274
+ Run the iodine server in single process mode: `iodine -w 1` and the little timer is ticking.
275
+
276
+ Honestly, I don't love the code I just wrote for the previous example. It's a little long, it's slightly iffy and we can't use iodine's cluster mode.
277
+
278
+ For my next example, I'll author a chat room in 32 lines (including comments).
279
+
280
+ I will use Iodine's pub/sub extension API to avoid the LiveList module and the timer thread (I don't need a timer, so I'll skip the [`Iodine.run_every` method](https://www.rubydoc.info/github/boazsegev/iodine/master/Iodine#run_every-class_method)).
281
+
282
+ Also, I'll limit the interaction to WebSocket clients. Why? to show I can.
283
+
284
+ This will better demonstrate the power offered by the new `env['rack.upgrade']` approach and it will also work in cluster mode.
260
285
 
261
- Here is a simple chat room, but in this case I limit the interaction to WebSocket client. Why? because I can.
286
+ Sadly, this means that the example won't run on Agoo for now.
262
287
 
263
288
  ```ruby
264
- # place in config.ru
289
+ # Place in config.ru
265
290
  RESPONSE = [200, { 'Content-Type' => 'text/html',
266
291
  'Content-Length' => '12' }, [ 'Hello World!' ] ]
267
292
  # a Callback class
@@ -281,11 +306,11 @@ class MyCallbacks
281
306
  publish :chat, "#{@name} left the chat."
282
307
  end
283
308
  end
284
- # note the `env` variable
309
+ # The actual Rack application
285
310
  APP = Proc.new do |env|
286
311
  if(env['rack.upgrade?'] == :websocket)
287
312
  env['rack.upgrade'] = MyCallbacks.new(env)
288
- [0, {}, []]
313
+ [200, {}, []]
289
314
  else
290
315
  RESPONSE
291
316
  end
@@ -294,6 +319,12 @@ end
294
319
  run APP
295
320
  ```
296
321
 
322
+ Start the application from the command line (in terminal):
323
+
324
+ ```bash
325
+ iodine
326
+ ```
327
+
297
328
  Now try (in the browser console):
298
329
 
299
330
  ```js
@@ -278,15 +278,18 @@ error:
278
278
  */
279
279
  #pragma weak defer_free_thread
280
280
  void defer_free_thread(void *p_thr) {
281
- pthread_detach(*((pthread_t *)p_thr));
281
+ if (*((pthread_t *)p_thr)) {
282
+ pthread_detach(*((pthread_t *)p_thr));
283
+ }
282
284
  free(p_thr);
283
285
  }
284
286
 
285
287
  #pragma weak defer_join_thread
286
288
  int defer_join_thread(void *p_thr) {
287
- if (!p_thr)
289
+ if (!p_thr || !(*((pthread_t *)p_thr)))
288
290
  return -1;
289
291
  pthread_join(*((pthread_t *)p_thr), NULL);
292
+ *((pthread_t *)p_thr) = NULL;
290
293
  defer_free_thread(p_thr);
291
294
  return 0;
292
295
  }
@@ -1,11 +1,5 @@
1
1
  require 'mkmf'
2
2
 
3
- def check_for_stdatomics
4
- RbConfig::MAKEFILE_CONFIG['CC'] = $CC = ENV['CC'] if ENV['CC']
5
- RbConfig::MAKEFILE_CONFIG['CPP'] = $CPP = ENV['CPP'] if ENV['CPP']
6
- puts 'Missing support for atomic operations (support for C11) - is your compiler updated?' unless have_header('stdatomic.h')
7
- end
8
-
9
3
  abort 'Missing a Linux/Unix OS evented API (epoll/kqueue).' unless have_func('kevent') || have_func('epoll_ctl')
10
4
 
11
5
  if ENV['CC']
@@ -16,6 +10,10 @@ elsif find_executable('clang') && puts('testing clang for stdatomic support...')
16
10
  $CC = ENV['CC'] = 'clang'
17
11
  $CPP = ENV['CPP'] = 'clang'
18
12
  puts "using clang compiler v. #{`clang -dumpversion`}."
13
+ elsif find_executable('gcc') && (`gcc -dumpversion 2>&1`.to_i >= 5)
14
+ $CC = ENV['CC'] = 'gcc'
15
+ $CPP = ENV['CPP'] = find_executable('g++') ? 'g++' : 'gcc'
16
+ puts "using gcc #{ `gcc -dumpversion 2>&1`.to_i }"
19
17
  elsif find_executable('gcc-6')
20
18
  $CC = ENV['CC'] = 'gcc-6'
21
19
  $CPP = ENV['CPP'] = find_executable('g++-6') ? 'g++-6' : 'gcc-6'
@@ -29,7 +27,6 @@ elsif find_executable('gcc-4.9')
29
27
  $CPP = ENV['CPP'] = find_executable('g++-4.9') ? 'g++-4.9' : 'gcc-4.9'
30
28
  puts 'using gcc-4.9 compiler.'
31
29
  else
32
- # check_for_stdatomics
33
30
  puts 'using an unknown (old?) compiler... who knows if this will work out... we hope.'
34
31
  end
35
32
 
@@ -27,6 +27,27 @@ Feel free to copy, use and enjoy according to the license provided.
27
27
  #define __attribute__(...)
28
28
  #endif
29
29
 
30
+ /* *****************************************************************************
31
+ Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
32
+ ***************************************************************************** */
33
+ #if defined(__MACH__) && !defined(CLOCK_REALTIME)
34
+ #include <sys/time.h>
35
+ #define CLOCK_REALTIME 0
36
+ #define clock_gettime patch_clock_gettime
37
+ // clock_gettime is not implemented on older versions of OS X (< 10.12).
38
+ // If implemented, CLOCK_REALTIME will have already been defined.
39
+ static inline int patch_clock_gettime(int clk_id, struct timespec *t) {
40
+ struct timeval now;
41
+ int rv = gettimeofday(&now, NULL);
42
+ if (rv)
43
+ return rv;
44
+ t->tv_sec = now.tv_sec;
45
+ t->tv_nsec = now.tv_usec * 1000;
46
+ return 0;
47
+ (void)clk_id;
48
+ }
49
+ #endif
50
+
30
51
  /* *****************************************************************************
31
52
  Data Structures
32
53
  ***************************************************************************** */
@@ -426,9 +447,9 @@ static void facil_lib_init(void) {
426
447
  spn_lock(&facil_libinit_lock);
427
448
  if (facil_data)
428
449
  goto finish;
429
- facil_data = mmap(NULL, mem_size, PROT_READ | PROT_WRITE | PROT_EXEC,
450
+ facil_data = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
430
451
  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
431
- if (!facil_data) {
452
+ if (!facil_data || facil_data == MAP_FAILED) {
432
453
  perror("ERROR: Couldn't initialize the facil.io library");
433
454
  exit(0);
434
455
  }
@@ -141,18 +141,17 @@ static inline void *sys_alloc(size_t len, uint8_t is_indi) {
141
141
  /* hope for the best? */
142
142
  #ifdef MAP_ALIGNED
143
143
  result = mmap(
144
- next_alloc, len, PROT_READ | PROT_WRITE | PROT_EXEC,
144
+ next_alloc, len, PROT_READ | PROT_WRITE,
145
145
  MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED(FIO_MEMORY_BLOCK_SIZE), -1, 0);
146
146
  #else
147
- result = mmap(next_alloc, len, PROT_READ | PROT_WRITE | PROT_EXEC,
147
+ result = mmap(next_alloc, len, PROT_READ | PROT_WRITE,
148
148
  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
149
149
  #endif
150
150
  if (result == MAP_FAILED)
151
151
  return NULL;
152
152
  if (((uintptr_t)result & FIO_MEMORY_BLOCK_MASK)) {
153
153
  munmap(result, len);
154
- result = mmap(NULL, len + FIO_MEMORY_BLOCK_SIZE,
155
- PROT_READ | PROT_WRITE | PROT_EXEC,
154
+ result = mmap(NULL, len + FIO_MEMORY_BLOCK_SIZE, PROT_READ | PROT_WRITE,
156
155
  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
157
156
  if (result == MAP_FAILED)
158
157
  return NULL;
@@ -180,9 +179,9 @@ static void *sys_realloc(void *mem, size_t prev_len, size_t new_len) {
180
179
  if (result == MAP_FAILED)
181
180
  return NULL;
182
181
  #else
183
- void *result = mmap((void *)((uintptr_t)mem + prev_len), new_len - prev_len,
184
- PROT_READ | PROT_WRITE | PROT_EXEC,
185
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
182
+ void *result =
183
+ mmap((void *)((uintptr_t)mem + prev_len), new_len - prev_len,
184
+ PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
186
185
  if (result == (void *)((uintptr_t)mem + prev_len)) {
187
186
  result = mem;
188
187
  } else {
@@ -391,8 +390,11 @@ Non-Block allocations (direct from the system)
391
390
  static inline void *big_alloc(size_t size) {
392
391
  size = sys_round_size(size + 16);
393
392
  size_t *mem = sys_alloc(size, 1);
394
- *mem = size;
395
- return (void *)(((uintptr_t)mem) + 16);
393
+ if (mem) { /* likely */
394
+ *mem = size;
395
+ return (void *)(((uintptr_t)mem) + 16);
396
+ }
397
+ return NULL;
396
398
  }
397
399
 
398
400
  static inline void big_free(void *ptr) {
@@ -21,6 +21,27 @@ Feel free to copy, use and enjoy according to the license provided.
21
21
 
22
22
  #include "fio_mem.h"
23
23
 
24
+ /* *****************************************************************************
25
+ Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
26
+ ***************************************************************************** */
27
+ #if defined(__MACH__) && !defined(CLOCK_REALTIME)
28
+ #include <sys/time.h>
29
+ #define CLOCK_REALTIME 0
30
+ #define clock_gettime patch_clock_gettime
31
+ // clock_gettime is not implemented on older versions of OS X (< 10.12).
32
+ // If implemented, CLOCK_REALTIME will have already been defined.
33
+ static inline int patch_clock_gettime(int clk_id, struct timespec *t) {
34
+ struct timeval now;
35
+ int rv = gettimeofday(&now, NULL);
36
+ if (rv)
37
+ return rv;
38
+ t->tv_sec = now.tv_sec;
39
+ t->tv_nsec = now.tv_usec * 1000;
40
+ return 0;
41
+ (void)clk_id;
42
+ }
43
+ #endif
44
+
24
45
  /* *****************************************************************************
25
46
  Small Helpers
26
47
  ***************************************************************************** */
@@ -217,20 +217,23 @@ static void *iodine_io_thread(void *arg) {
217
217
  }
218
218
  return NULL;
219
219
  }
220
- static void iodine_start_io_thread(void *a1, void *a2) {
220
+ void iodine_start_io_thread(void *a1, void *a2) {
221
221
  (void)a1;
222
222
  (void)a2;
223
223
  pthread_create(&sock_io_pthread, NULL, iodine_io_thread, NULL);
224
224
  }
225
225
  static void iodine_join_io_thread(void) {
226
226
  sock_io_thread = 0;
227
- pthread_join(sock_io_pthread, NULL);
227
+ if (sock_io_pthread) {
228
+ pthread_join(sock_io_pthread, NULL);
229
+ }
230
+ sock_io_pthread = NULL;
228
231
  }
229
232
 
230
233
  static void *srv_start_no_gvl(void *s_) {
231
234
  iodine_start_settings_s *s = s_;
232
235
  sock_io_thread = 1;
233
- defer(iodine_start_io_thread, NULL, NULL);
236
+ iodine_start_io_thread(NULL, NULL);
234
237
  fprintf(stderr, "\n");
235
238
  if (s->processes == 1 || (s->processes == 0 && s->threads > 0)) {
236
239
  /* single worker */
@@ -20,7 +20,6 @@ Feel free to copy, use and enjoy according to the license provided.
20
20
  /* *****************************************************************************
21
21
  Available Globals
22
22
  ***************************************************************************** */
23
- static VALUE IodineHTTP;
24
23
 
25
24
  typedef struct {
26
25
  VALUE app;
@@ -160,7 +159,8 @@ static inline VALUE copy2env(iodine_http_request_handle_s *handle) {
160
159
  case IODINE_UPGRADE_SSE:
161
160
  env = rb_hash_dup(env_template_sse);
162
161
  break;
163
- case IODINE_UPGRADE_NONE:
162
+ case IODINE_UPGRADE_NONE: /* fallthrough */
163
+ default:
164
164
  env = rb_hash_dup(env_template_no_upgrade);
165
165
  break;
166
166
  }
@@ -795,7 +795,6 @@ engine is used.
795
795
  */
796
796
  VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
797
797
  VALUE rb_ch, rb_msg, rb_engine = Qnil;
798
- uint8_t use_pattern = 0;
799
798
  const pubsub_engine_s *engine = NULL;
800
799
  switch (argc) {
801
800
  case 3:
@@ -810,8 +809,7 @@ VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
810
809
  Check_Type(argv[0], T_HASH);
811
810
  rb_ch = rb_hash_aref(argv[0], to_sym_id);
812
811
  if (rb_ch == Qnil || rb_ch == Qfalse) {
813
- use_pattern = 1;
814
- rb_ch = rb_hash_aref(argv[0], match_sym_id);
812
+ rb_ch = rb_hash_aref(argv[0], channel_sym_id);
815
813
  }
816
814
  rb_msg = rb_hash_aref(argv[0], message_sym_id);
817
815
  rb_engine = rb_hash_aref(argv[0], engine_varid);
@@ -826,7 +824,7 @@ VALUE iodine_publish(int argc, VALUE *argv, VALUE self) {
826
824
  Check_Type(rb_msg, T_STRING);
827
825
 
828
826
  if (rb_ch == Qnil || rb_ch == Qfalse)
829
- rb_raise(rb_eArgError, "channel is required .");
827
+ rb_raise(rb_eArgError, "target / channel is required .");
830
828
  if (TYPE(rb_ch) == T_SYMBOL)
831
829
  rb_ch = rb_sym2str(rb_ch);
832
830
  Check_Type(rb_ch, T_STRING);
@@ -209,6 +209,7 @@ static VALUE iodine_defer(int argc, VALUE *argv, VALUE self) {
209
209
  return block;
210
210
  }
211
211
 
212
+ #if 0 /* deprecated */
212
213
  /**
213
214
  Schedules a block of code to run for the specified websocket at a later time,
214
215
  (**if** the connection is open). The block will run within the connection's
@@ -240,6 +241,8 @@ static VALUE iodine_class_defer(VALUE self, VALUE ws_uuid) {
240
241
  return block;
241
242
  }
242
243
 
244
+ #endif
245
+
243
246
  /* *****************************************************************************
244
247
  Websocket Pub/Sub API
245
248
  ***************************************************************************** */
@@ -45,6 +45,7 @@ static VALUE iodine_ruby_caller_perform(VALUE tsk_) {
45
45
  return (VALUE)task->func(task->arg);
46
46
  }
47
47
  }
48
+ return Qnil;
48
49
  }
49
50
 
50
51
  ////////////////////////////////////////////////////////////////////////////
@@ -54,6 +54,9 @@ static void *create_ruby_thread_gvl(void *args) {
54
54
  return (void *)Registry.add(rb_thread_create(defer_thread_inGVL, args));
55
55
  }
56
56
 
57
+ /* used during fork */
58
+ void iodine_start_io_thread(void *a1, void *a2);
59
+
57
60
  static void *fork_using_ruby(void *ignr) {
58
61
  RubyCaller.call(Iodine, rb_intern("before_fork"));
59
62
  const VALUE ProcessClass = rb_const_get(rb_cObject, rb_intern("Process"));
@@ -68,6 +71,7 @@ static void *fork_using_ruby(void *ignr) {
68
71
  if (!pid) {
69
72
  Registry.on_fork();
70
73
  RubyCaller.call(Iodine, rb_intern("after_fork"));
74
+ iodine_start_io_thread(NULL, NULL);
71
75
  }
72
76
  return (void *)pid;
73
77
  (void)ignr;
@@ -28,9 +28,6 @@ static inline VALUE fiobj2rb(FIOBJ o, uint8_t str2sym) {
28
28
  case FIOBJ_T_NUMBER:
29
29
  rb = LONG2FIX(fiobj_obj2num(o));
30
30
  break;
31
- case FIOBJ_T_NULL:
32
- rb = Qnil;
33
- break;
34
31
  case FIOBJ_T_TRUE:
35
32
  rb = Qtrue;
36
33
  break;
@@ -58,6 +55,10 @@ static inline VALUE fiobj2rb(FIOBJ o, uint8_t str2sym) {
58
55
  case FIOBJ_T_HASH:
59
56
  rb = rb_hash_new();
60
57
  break;
58
+ case FIOBJ_T_NULL: /* fallthrough */
59
+ default:
60
+ rb = Qnil;
61
+ break;
61
62
  };
62
63
  return rb;
63
64
  }
@@ -27,7 +27,6 @@ Includes and state
27
27
  #include <sys/resource.h>
28
28
  #include <sys/socket.h>
29
29
  #include <sys/stat.h>
30
- #include <sys/sysctl.h>
31
30
  #include <sys/types.h>
32
31
  #include <sys/un.h>
33
32
 
@@ -190,6 +190,7 @@ module Iodine
190
190
 
191
191
 
192
192
  @after_fork_blocks = []
193
+ # Performs a block of code whenever a new worker process spins up (performed once per worker).
193
194
  def self.after_fork(*args, &block)
194
195
  if(block)
195
196
  @after_fork_blocks << [args, block]
@@ -199,6 +200,7 @@ module Iodine
199
200
  end
200
201
 
201
202
  @before_fork_blocks = []
203
+ # Performs a block of code just before a new worker process spins up (performed once per worker).
202
204
  def self.before_fork(*args, &block)
203
205
  if(block)
204
206
  @before_fork_blocks << [args, block]
@@ -211,16 +213,19 @@ module Iodine
211
213
  end
212
214
 
213
215
  if(!defined?(after_fork))
216
+ # Performs a block of code whenever a new worker process spins up (performed once per worker).
214
217
  def after_fork(*args, &block)
215
218
  Iodine.after_fork(*args, &block)
216
219
  end
217
220
  end
218
221
  if(!defined?(on_worker_boot))
222
+ # Performs a block of code whenever a new worker process spins up (performed once per worker).
219
223
  def on_worker_boot(*args, &block)
220
224
  Iodine.after_fork(*args, &block)
221
225
  end
222
226
  end
223
227
  if(!defined?(before_fork))
228
+ # Performs a block of code just before a new worker process spins up (performed once per worker).
224
229
  def before_fork(*args, &block)
225
230
  Iodine.before_fork(*args, &block)
226
231
  end
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = '0.5.0'.freeze
2
+ VERSION = '0.5.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-04-30 00:00:00.000000000 Z
11
+ date: 2018-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack