iodine 0.7.15 → 0.7.16

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: f1996d0474dc00ad0614035f36b703154b594415278cd18624cec94c8149150e
4
- data.tar.gz: 3060659e07df3fc734594584b407b5bf9156ae77fcdb8709f62a49d0f2f62296
3
+ metadata.gz: 4813b7d2deb5b0dede2e40d240e295f10cdcef94effb743eeb0293317e84fc3e
4
+ data.tar.gz: 4fb3632e530571ad598c50f42e3eca989aca0425c00df041d590ca26fdcc2b8e
5
5
  SHA512:
6
- metadata.gz: 2ab1733a97c6617232022405bd25d4f0c46d4a99c6751b5a8467e48fa17efc0dc815dc47ca329c7ca955d135c56e8a06c69d3fd168ead0b3510712e909711468
7
- data.tar.gz: 53be4c7971bca24fd484bfa4dd18d67a99ffba196a5908c76bf1a3001a957ef607c51ec8d90b3d4714d6297609bf4dde8077d24bd85eee081b875bf27faa5d8f
6
+ metadata.gz: d632268e49abf09a61e7eaa0d8905f9c4bef2f303784d4d3eca0fd9a6bc29952b28eb7c9709ab34d95324b0bdbdc866a98c0520d9df5cc560b3afba83f5e940f
7
+ data.tar.gz: 28c9fa08377cad5fba31cda50186598839abe336f85c882efea480c4bed467e1e10e0df5c18fe72ef48e97ed2b92c4bdf68264373169cfeeb82a82788ee6b966
@@ -6,6 +6,7 @@ before_install:
6
6
  - gem install bundler -v 1.10.6
7
7
  - bundle install
8
8
  rvm:
9
+ - 2.6.0
9
10
  - 2.5.0
10
11
  - 2.4.0
11
12
  - 2.3.1
@@ -6,6 +6,14 @@ 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.7.16
10
+
11
+ **Security**: (`fio`) security fixes from the facil.io core library (updated to 0.7.0.beta6).
12
+
13
+ **Update**: (`iodine`) better Redis support from CLI and environment (by setting the `IODINE_REDIS_URL` environment variable).
14
+
15
+ **Optimization**: (`Iodine::Mustache`) optimized worst case scenario seeking by seeking Symbols before Strings, which improved seeking times.
16
+
9
17
  #### Change log v.0.7.15
10
18
 
11
19
  **Fix**: (`fio`) fixed a minor memory leak in cluster mode, caused by the root process not freeing the hash map used for child process subscription monitoring (only effected hot restarts).
data/README.md CHANGED
@@ -7,9 +7,13 @@
7
7
 
8
8
  [![Logo](https://github.com/boazsegev/iodine/raw/master/logo.png)](https://github.com/boazsegev/iodine)
9
9
 
10
- Iodine is a fast concurrent web server for real-time Ruby applications, with native support for:
10
+ I believe that network concerns should be separated from application concerns - application developers really shouldn't need to worry about the transport layer.
11
11
 
12
- * Websockets and EventSource (SSE);
12
+ And I know that these network concerns are more than just about the web server. Which is why iodine is more than just an HTTP server.
13
+
14
+ Iodine is a fast concurrent web server for real-time Ruby applications, but it's also so much more. Iodine includes native support for:
15
+
16
+ * WebSockets and EventSource (SSE);
13
17
  * Pub/Sub (with optional Redis Pub/Sub scaling);
14
18
  * Static file service (with automatic `gzip` support for pre-compressed versions);
15
19
  * HTTP/1.1 keep-alive and pipelining;
@@ -25,9 +29,9 @@ Iodine is an **evented** framework with a simple API that ports much of the [C f
25
29
 
26
30
  * Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections on Linux)!
27
31
 
28
- * Iodine is ideal for **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).
32
+ * Iodine is ideal for **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 very different).
29
33
 
30
- 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.
34
+ 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 CI tests start at Ruby 2.2.2.
31
35
 
32
36
  ## Iodine - a fast & powerful HTTP + Websockets server with native Pub/Sub
33
37
 
@@ -63,13 +67,11 @@ bundler exec iodine -p $PORT -t 16 -w 1
63
67
 
64
68
  ### Heap Fragmentation Protection
65
69
 
66
- Iodine includes a network oriented custom memory allocator, with very high performance.
67
-
68
- This allows the heap to be divided, naturally, into long-living objects (allocated normally) and short living objects (allocated using the iodine allocator).
70
+ Iodine includes a fast, network oriented, custom memory allocator, optimizing away some of the work usually placed on the Ruby Garbage Collector (GC).
69
71
 
70
- This approach helps to minimize heap fragmentation for long running processes.
72
+ This approach helps to minimize heap fragmentation for long running processes, by grouping many short-lived objects into a common memory space.
71
73
 
72
- It's still recommended to consider [jemalloc](http://jemalloc.net) or other allocators to mitigate the heap fragmentation that would be caused by Ruby's internal memory management.
74
+ It's still recommended to consider [jemalloc](http://jemalloc.net) or other allocators that also help mitigate heap fragmentation issues.
73
75
 
74
76
  ### Static file serving support
75
77
 
@@ -301,9 +303,9 @@ bundler exec iodine -p $PORT -v 2>&1
301
303
 
302
304
  ### Built-in support for Sequel and ActiveRecord
303
305
 
304
- It's a well known fact that Database connections require special attention when using `fork`-ing servers (multi-process servers) such as Puma, Passenger and iodine.
306
+ It's a well known fact that [Database connections require special attention when using `fork`-ing servers (multi-process servers)](https://devcenter.heroku.com/articles/concurrency-and-database-connections#multi-process-servers) such as Puma, Passenger (Pro) and iodine.
305
307
 
306
- However, it's also true that these issues go unnoticed by many developers, since application developers are (rightfully) focused on the application rather than the infrastructure.
308
+ However, it's also true that [these issues go unnoticed by many developers](https://stackoverflow.com/a/45570999/4025095), since application developers are (rightfully) focused on the application rather than the infrastructure.
307
309
 
308
310
  With iodine, there's no need to worry.
309
311
 
@@ -1,14 +1,19 @@
1
1
  # This example implements a Redis pub/sub engine according to the Iodine::PubSub::Engine specifications.
2
2
  #
3
- # Run this applications on two ports, in two terminals to see the synchronization is action
3
+ # Run this applications on two ports, in two terminals to see the synchronization is action:
4
4
  #
5
- # REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3000 redis.ru
6
- # REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3030 redis.ru
5
+ # IODINE_REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3000 redis.ru
6
+ # IODINE_REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3030 redis.ru
7
+ #
8
+ # Or:
9
+ #
10
+ # iodine -t 1 -p 3000 redis.ru -redis redis://localhost:6379/0
11
+ # iodine -t 1 -p 3030 redis.ru -redis redis://localhost:6379/0
7
12
  #
8
13
  require 'iodine'
9
14
  # initialize the Redis engine for each Iodine process.
10
- if ENV["REDIS_URL"]
11
- Iodine::PubSub.default = Iodine::PubSub::Redis.new(ENV["REDIS_URL"], ping: 10)
15
+ if Iodine::DEFAULT_HTTP_ARGS[:redis_]
16
+ puts "* Redis support automatically detected."
12
17
  else
13
18
  puts "* No Redis, it's okay, pub/sub will support the process cluster."
14
19
  end
@@ -47,7 +52,7 @@ class WS_RedisPubSub
47
52
  client.publish "chat", "#{@name} entered the chat."
48
53
  end
49
54
  # send a message, letting the client know the server is suggunt down.
50
- def on_shutdown client
55
+ def on_shutdown client
51
56
  client.write "Server shutting down. Goodbye."
52
57
  end
53
58
  # perform the echo
data/exe/iodine CHANGED
@@ -1,5 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
- require 'rack'
2
+ begin
3
+ require 'rack'
4
+ rescue LoadError
5
+ puts "ERROR: the iodine command-line utility requires the gem: rack."
6
+ exit(0)
7
+ end
3
8
  require 'iodine'
4
9
 
5
10
  module Iodine
@@ -5,9 +5,13 @@ License: MIT
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  ***************************************************************************** */
7
7
 
8
+ #include <fio.h>
9
+
8
10
  #define FIO_INCLUDE_STR
9
- #define FIO_INCLUDE_LINKED_LIST
11
+ #include <fio.h>
10
12
 
13
+ #define FIO_FORCE_MALLOC_TMP 1
14
+ #define FIO_INCLUDE_LINKED_LIST
11
15
  #include <fio.h>
12
16
 
13
17
  #include <ctype.h>
@@ -2109,9 +2113,11 @@ static void deferred_on_ready(void *arg, void *arg2) {
2109
2113
  }
2110
2114
 
2111
2115
  static void deferred_on_data(void *uuid, void *arg2) {
2112
- if (!uuid_data(uuid).protocol || fio_is_closed((intptr_t)uuid)) {
2116
+ if (fio_is_closed((intptr_t)uuid)) {
2113
2117
  return;
2114
2118
  }
2119
+ if (!uuid_data(uuid).protocol)
2120
+ goto no_protocol;
2115
2121
  fio_protocol_s *pr = protocol_try_lock(fio_uuid2fd(uuid), FIO_PR_LOCK_TASK);
2116
2122
  if (!pr) {
2117
2123
  if (errno == EBADF) {
@@ -2126,6 +2132,7 @@ static void deferred_on_data(void *uuid, void *arg2) {
2126
2132
  fio_poll_add_read(fio_uuid2fd((intptr_t)uuid));
2127
2133
  }
2128
2134
  return;
2135
+
2129
2136
  postpone:
2130
2137
  if (arg2) {
2131
2138
  /* the event is being forced, so force rescheduling */
@@ -2135,6 +2142,11 @@ postpone:
2135
2142
  fio_poll_add_read(fio_uuid2fd((intptr_t)uuid));
2136
2143
  }
2137
2144
  return;
2145
+
2146
+ no_protocol:
2147
+ /* a missing protocol might still want to invoke the RW hook flush */
2148
+ deferred_on_ready(uuid, arg2);
2149
+ return;
2138
2150
  }
2139
2151
 
2140
2152
  static void deferred_ping(void *arg, void *arg2) {
@@ -2537,8 +2549,9 @@ static int fio_sock_write_buffer(int fd, fio_packet_s *packet) {
2537
2549
  if (written > 0) {
2538
2550
  packet->length -= written;
2539
2551
  packet->offset += written;
2540
- if (!packet->length)
2552
+ if (!packet->length) {
2541
2553
  fio_sock_packet_rotate_unsafe(fd);
2554
+ }
2542
2555
  }
2543
2556
  return written;
2544
2557
  }
@@ -2552,10 +2565,11 @@ static int fio_sock_write_from_fd(int fd, fio_packet_s *packet) {
2552
2565
  packet->offset += sent;
2553
2566
  packet->length -= sent;
2554
2567
  retry:
2555
- asked = (packet->length < BUFFER_FILE_READ_SIZE)
2556
- ? pread(packet->data.fd, buff, packet->length, packet->offset)
2557
- : pread(packet->data.fd, buff, BUFFER_FILE_READ_SIZE,
2558
- packet->offset);
2568
+ asked = pread(packet->data.fd, buff,
2569
+ ((packet->length < BUFFER_FILE_READ_SIZE)
2570
+ ? packet->length
2571
+ : BUFFER_FILE_READ_SIZE),
2572
+ packet->offset);
2559
2573
  if (asked <= 0)
2560
2574
  goto read_error;
2561
2575
  sent = fd_data(fd).rw_hooks->write(fd2uuid(fd), fd_data(fd).rw_udata, buff,
@@ -2784,7 +2798,7 @@ void fio_close(intptr_t uuid) {
2784
2798
  errno = EBADF;
2785
2799
  return;
2786
2800
  }
2787
- if (uuid_data(uuid).packet) {
2801
+ if (uuid_data(uuid).packet || uuid_data(uuid).sock_lock) {
2788
2802
  uuid_data(uuid).close = 1;
2789
2803
  fio_poll_add_write(fio_uuid2fd(uuid));
2790
2804
  return;
@@ -2914,7 +2928,7 @@ size_t fio_flush_all(void) {
2914
2928
  if (!fio_data)
2915
2929
  return 0;
2916
2930
  size_t count = 0;
2917
- for (uintptr_t i = 0; i < fio_data->max_protocol_fd; ++i) {
2931
+ for (uintptr_t i = 0; i <= fio_data->max_protocol_fd; ++i) {
2918
2932
  if ((fd_data(i).open || fd_data(i).packet) && fio_flush(fd2uuid(i)) > 0)
2919
2933
  ++count;
2920
2934
  }
@@ -2958,6 +2972,41 @@ const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS = {
2958
2972
  .cleanup = fio_hooks_default_cleanup,
2959
2973
  };
2960
2974
 
2975
+ /**
2976
+ * Replaces an existing read/write hook with another from within a read/write
2977
+ * hook callback.
2978
+ *
2979
+ * Does NOT call any cleanup callbacks.
2980
+ *
2981
+ * Returns -1 on error, 0 on success.
2982
+ */
2983
+ int fio_rw_hook_replace_unsafe(intptr_t uuid, fio_rw_hook_s *rw_hooks,
2984
+ void *udata) {
2985
+ int replaced = -1;
2986
+ uint8_t was_locked;
2987
+ intptr_t fd = fio_uuid2fd(uuid);
2988
+ if (!rw_hooks->read)
2989
+ rw_hooks->read = fio_hooks_default_read;
2990
+ if (!rw_hooks->write)
2991
+ rw_hooks->write = fio_hooks_default_write;
2992
+ if (!rw_hooks->flush)
2993
+ rw_hooks->flush = fio_hooks_default_flush;
2994
+ if (!rw_hooks->before_close)
2995
+ rw_hooks->before_close = fio_hooks_default_before_close;
2996
+ if (!rw_hooks->cleanup)
2997
+ rw_hooks->cleanup = fio_hooks_default_cleanup;
2998
+ /* protect against some fulishness... but not all of it. */
2999
+ was_locked = fio_trylock(&fd_data(fd).sock_lock);
3000
+ if (fd2uuid(fd) == uuid) {
3001
+ fd_data(fd).rw_hooks = rw_hooks;
3002
+ fd_data(fd).rw_udata = udata;
3003
+ replaced = 0;
3004
+ }
3005
+ if (!was_locked)
3006
+ fio_unlock(&fd_data(fd).sock_lock);
3007
+ return replaced;
3008
+ }
3009
+
2961
3010
  /** Sets a socket hook state (a pointer to the struct). */
2962
3011
  int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata) {
2963
3012
  if (fio_is_closed(uuid))
@@ -3060,10 +3109,18 @@ static int fio_attach__internal(void *uuid_, void *protocol_) {
3060
3109
  touchfd(fio_uuid2fd(uuid));
3061
3110
  fio_unlock(&uuid_data(uuid).protocol_lock);
3062
3111
  if (old_pr) {
3112
+ /* protocol replacement */
3063
3113
  fio_defer_push_task(deferred_on_close, (void *)uuid, old_pr);
3114
+ if (!protocol) {
3115
+ /* hijacking */
3116
+ fio_poll_remove_fd(fio_uuid2fd(uuid));
3117
+ fio_poll_add_write(fio_uuid2fd(uuid));
3118
+ }
3064
3119
  } else if (protocol) {
3120
+ /* adding a new uuid to the reactor */
3065
3121
  fio_poll_add(fio_uuid2fd(uuid));
3066
3122
  }
3123
+ fio_max_fd_min(fio_uuid2fd(uuid));
3067
3124
  return 0;
3068
3125
 
3069
3126
  invalid_uuid:
@@ -3313,23 +3370,6 @@ Initialize the library
3313
3370
 
3314
3371
  static void fio_pubsub_on_fork(void);
3315
3372
 
3316
- static void fio_mem_destroy(void);
3317
- static void __attribute__((destructor)) fio_lib_destroy(void) {
3318
- uint8_t add_eol = fio_is_master();
3319
- fio_data->active = 0;
3320
- fio_state_callback_force(FIO_CALL_AT_EXIT);
3321
- fio_state_callback_clear_all();
3322
- fio_defer_perform();
3323
- fio_poll_close();
3324
- fio_timer_clear_all();
3325
- fio_free(fio_data);
3326
- /* memory library destruction must be last */
3327
- fio_mem_destroy();
3328
- FIO_LOG_DEBUG("(%d) facil.io resources released, exit complete.", getpid());
3329
- if (add_eol)
3330
- fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
3331
- }
3332
-
3333
3373
  /* Called within a child process after it starts. */
3334
3374
  static void fio_on_fork(void) {
3335
3375
  fio_data->lock = FIO_LOCK_INIT;
@@ -3356,6 +3396,25 @@ static void fio_on_fork(void) {
3356
3396
  fio_data->is_worker = 1;
3357
3397
  }
3358
3398
 
3399
+ static void fio_mem_destroy(void);
3400
+ static void __attribute__((destructor)) fio_lib_destroy(void) {
3401
+ uint8_t add_eol = fio_is_master();
3402
+ fio_data->active = 0;
3403
+ fio_on_fork();
3404
+ fio_defer_perform();
3405
+ fio_state_callback_force(FIO_CALL_AT_EXIT);
3406
+ fio_state_callback_clear_all();
3407
+ fio_defer_perform();
3408
+ fio_poll_close();
3409
+ fio_timer_clear_all();
3410
+ fio_free(fio_data);
3411
+ /* memory library destruction must be last */
3412
+ fio_mem_destroy();
3413
+ FIO_LOG_DEBUG("(%d) facil.io resources released, exit complete.", getpid());
3414
+ if (add_eol)
3415
+ fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
3416
+ }
3417
+
3359
3418
  static void fio_mem_init(void);
3360
3419
  static void fio_cluster_init(void);
3361
3420
  static void fio_pubsub_initialize(void);
@@ -4548,11 +4607,7 @@ static int fio_channel_cmp(channel_s *ch1, channel_s *ch2) {
4548
4607
  !memcmp(ch1->name, ch2->name, ch1->name_len);
4549
4608
  }
4550
4609
  /* pub/sub channels and core data sets have a long life, so avoid fio_malloc */
4551
- #if !FIO_FORCE_MALLOC
4552
- #define FIO_FORCE_MALLOC 1
4553
- #define FIO_FORCE_MALLOC_IS_TMP 1
4554
- #endif
4555
-
4610
+ #define FIO_FORCE_MALLOC_TMP 1
4556
4611
  #define FIO_SET_NAME fio_ch_set
4557
4612
  #define FIO_SET_OBJ_TYPE channel_s *
4558
4613
  #define FIO_SET_OBJ_COMPARE(o1, o2) fio_channel_cmp((o1), (o2))
@@ -4560,19 +4615,17 @@ static int fio_channel_cmp(channel_s *ch1, channel_s *ch2) {
4560
4615
  #define FIO_SET_OBJ_COPY(dest, src) ((dest) = fio_channel_copy((src)))
4561
4616
  #include <fio.h>
4562
4617
 
4618
+ #define FIO_FORCE_MALLOC_TMP 1
4563
4619
  #define FIO_ARY_NAME fio_meta_ary
4564
4620
  #define FIO_ARY_TYPE fio_msg_metadata_fn
4565
4621
  #include <fio.h>
4566
4622
 
4623
+ #define FIO_FORCE_MALLOC_TMP 1
4567
4624
  #define FIO_SET_NAME fio_engine_set
4568
4625
  #define FIO_SET_OBJ_TYPE fio_pubsub_engine_s *
4569
4626
  #define FIO_SET_OBJ_COMPARE(k1, k2) ((k1) == (k2))
4570
4627
  #include <fio.h>
4571
4628
 
4572
- #if FIO_FORCE_MALLOC_IS_TMP
4573
- #undef FIO_FORCE_MALLOC
4574
- #endif
4575
-
4576
4629
  struct fio_collection_s {
4577
4630
  fio_ch_set_s channels;
4578
4631
  fio_lock_i lock;
@@ -6823,9 +6876,8 @@ void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length) {
6823
6876
  return NULL;
6824
6877
  new_size = ((new_size >> 4) + (!!(new_size & 15)));
6825
6878
  copy_length = ((copy_length >> 4) + (!!(copy_length & 15)));
6826
- // memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length) <<
6827
- // 4);
6828
- fio_memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length));
6879
+ fio_memcpy(new_mem, ptr, copy_length > new_size ? new_size : copy_length);
6880
+
6829
6881
  block_slice_free(ptr);
6830
6882
  return new_mem;
6831
6883
  zero_size:
@@ -36,6 +36,7 @@ Feel free to copy, use and enjoy according to the license provided.
36
36
  * Cluster / Pub/Sub Middleware and Extensions ("Engines")
37
37
  *
38
38
  * Atomic Operations and Spin Locking Helper Functions
39
+ * Simple Constant Time Operations
39
40
  * Byte Swapping and Network Order
40
41
  *
41
42
  * Converting Numbers to Strings (and back)
@@ -109,7 +110,7 @@ Version and helper macros
109
110
  #define FIO_VERSION_MAJOR 0
110
111
  #define FIO_VERSION_MINOR 7
111
112
  #define FIO_VERSION_PATCH 0
112
- #define FIO_VERSION_BETA 4
113
+ #define FIO_VERSION_BETA 6
113
114
 
114
115
  /* Automatically convert version data to a string constant - ignore these two */
115
116
  #define FIO_MACRO2STR_STEP2(macro) #macro
@@ -323,16 +324,16 @@ Memory pool / custom allocator for short lived objects
323
324
  * Allocates memory using a per-CPU core block memory pool.
324
325
  * Memory is zeroed out.
325
326
  *
326
- * Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
327
- * blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
327
+ * Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (16Kb when using 32Kb blocks)
328
+ * will be redirected to `mmap`, as if `fio_mmap` was called.
328
329
  */
329
330
  void *FIO_ALIGN_NEW fio_malloc(size_t size);
330
331
 
331
332
  /**
332
333
  * same as calling `fio_malloc(size_per_unit * unit_count)`;
333
334
  *
334
- * Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (12,288 bytes when using 32Kb
335
- * blocks) will be redirected to `mmap`, as if `fio_mmap` was called.
335
+ * Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (16Kb when using 32Kb blocks)
336
+ * will be redirected to `mmap`, as if `fio_mmap` was called.
336
337
  */
337
338
  void *FIO_ALIGN_NEW fio_calloc(size_t size_per_unit, size_t unit_count);
338
339
 
@@ -372,22 +373,6 @@ void fio_malloc_after_fork(void);
372
373
 
373
374
  #undef FIO_ALIGN
374
375
 
375
- #if FIO_FORCE_MALLOC
376
- #define FIO_MALLOC(size) calloc((size), 1)
377
- #define FIO_CALLOC(size, units) calloc((size), (units))
378
- #define FIO_REALLOC(ptr, new_length, existing_data_length) \
379
- realloc((ptr), (new_length))
380
- #define FIO_FREE free
381
-
382
- #else
383
- #define FIO_MALLOC(size) fio_malloc((size))
384
- #define FIO_CALLOC(size, units) fio_calloc((size), (units))
385
- #define FIO_REALLOC(ptr, new_length, existing_data_length) \
386
- fio_realloc2((ptr), (new_length), (existing_data_length))
387
- #define FIO_FREE fio_free
388
-
389
- #endif
390
-
391
376
  /* *****************************************************************************
392
377
 
393
378
 
@@ -1128,12 +1113,12 @@ inline FIO_FUNC ssize_t fio_write(const intptr_t uuid, const void *buffer,
1128
1113
  const size_t length) {
1129
1114
  if (!length || !buffer)
1130
1115
  return 0;
1131
- void *cpy = FIO_MALLOC(length);
1116
+ void *cpy = fio_malloc(length);
1132
1117
  if (!cpy)
1133
1118
  return -1;
1134
1119
  memcpy(cpy, buffer, length);
1135
1120
  return fio_write2(uuid, .data.buffer = cpy, .length = length,
1136
- .after.dealloc = FIO_FREE);
1121
+ .after.dealloc = fio_free);
1137
1122
  }
1138
1123
 
1139
1124
  /**
@@ -1322,6 +1307,23 @@ typedef struct fio_rw_hook_s {
1322
1307
  /** Sets a socket hook state (a pointer to the struct). */
1323
1308
  int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata);
1324
1309
 
1310
+ /**
1311
+ * Replaces an existing read/write hook with another from within a read/write
1312
+ * hook callback.
1313
+ *
1314
+ * Does NOT call any cleanup callbacks.
1315
+ *
1316
+ * Replaces existing udata. Call with the existing udata to keep it.
1317
+ *
1318
+ * Returns -1 on error, 0 on success.
1319
+ *
1320
+ * Note: this function is marked as unsafe, since it should only be called from
1321
+ * within an existing read/write hook callback. Otherwise, data corruption
1322
+ * might occur.
1323
+ */
1324
+ int fio_rw_hook_replace_unsafe(intptr_t uuid, fio_rw_hook_s *rw_hooks,
1325
+ void *udata);
1326
+
1325
1327
  /** The default Read/Write hooks used for system Read/Write (udata == NULL). */
1326
1328
  extern const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS;
1327
1329
 
@@ -1983,6 +1985,56 @@ FIO_FUNC inline void fio_throttle_thread(size_t nano_sec);
1983
1985
 
1984
1986
 
1985
1987
 
1988
+ Simple Constant Time Operations
1989
+ ( boolean true / false and if )
1990
+
1991
+
1992
+
1993
+
1994
+
1995
+
1996
+
1997
+
1998
+
1999
+
2000
+
2001
+ ***************************************************************************** */
2002
+
2003
+ /** Returns 1 if the expression is true (input isn't zero). */
2004
+ FIO_FUNC inline uintptr_t fio_ct_true(uintptr_t cond) {
2005
+ // promise that the highest bit is set if any bits are set, than shift.
2006
+ return ((cond | (0 - cond)) >> ((sizeof(cond) << 3) - 1));
2007
+ }
2008
+
2009
+ /** Returns 1 if the expression is false (input is zero). */
2010
+ FIO_FUNC inline uintptr_t fio_ct_false(uintptr_t cond) {
2011
+ // fio_ct_true returns only one bit, XOR will inverse that bit.
2012
+ return fio_ct_true(cond) ^ 1;
2013
+ }
2014
+
2015
+ /** Returns `a` if `cond` is boolean and true, returns b otherwise. */
2016
+ FIO_FUNC inline uintptr_t fio_ct_if(uint8_t cond, uintptr_t a, uintptr_t b) {
2017
+ // b^(a^b) cancels b out. 0-1 => sets all bits.
2018
+ return (b ^ ((0 - (cond & 1)) & (a ^ b)));
2019
+ }
2020
+
2021
+ /** Returns `a` if `cond` isn't zero (uses fio_ct_true), returns b otherwise. */
2022
+ FIO_FUNC inline uintptr_t fio_ct_if2(uintptr_t cond, uintptr_t a, uintptr_t b) {
2023
+ // b^(a^b) cancels b out. 0-1 => sets all bits.
2024
+ return fio_ct_if(fio_ct_true(cond), a, b);
2025
+ }
2026
+
2027
+ /* *****************************************************************************
2028
+
2029
+
2030
+
2031
+
2032
+
2033
+
2034
+
2035
+
2036
+
2037
+
1986
2038
  Byte Swapping and Network Order
1987
2039
  (Big Endian v.s Little Endian etc')
1988
2040
 
@@ -2768,6 +2820,42 @@ FIO_FUNC inline int fio_trylock_dbg(fio_lock_i *lock, const char *file,
2768
2820
 
2769
2821
 
2770
2822
 
2823
+ Memory allocation macros for helper types
2824
+
2825
+
2826
+
2827
+
2828
+
2829
+
2830
+ ***************************************************************************** */
2831
+
2832
+ #undef FIO_MALLOC
2833
+ #undef FIO_CALLOC
2834
+ #undef FIO_REALLOC
2835
+ #undef FIO_FREE
2836
+
2837
+ #if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
2838
+ #define FIO_MALLOC(size) calloc((size), 1)
2839
+ #define FIO_CALLOC(size, units) calloc((size), (units))
2840
+ #define FIO_REALLOC(ptr, new_length, existing_data_length) \
2841
+ realloc((ptr), (new_length))
2842
+ #define FIO_FREE free
2843
+
2844
+ #else
2845
+ #define FIO_MALLOC(size) fio_malloc((size))
2846
+ #define FIO_CALLOC(size, units) fio_calloc((size), (units))
2847
+ #define FIO_REALLOC(ptr, new_length, existing_data_length) \
2848
+ fio_realloc2((ptr), (new_length), (existing_data_length))
2849
+ #define FIO_FREE fio_free
2850
+ #endif /* FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP */
2851
+
2852
+ /* *****************************************************************************
2853
+
2854
+
2855
+
2856
+
2857
+
2858
+
2771
2859
  Linked List Helpers
2772
2860
 
2773
2861
  exposes internally used inline helpers for linked lists
@@ -2960,7 +3048,7 @@ FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node) {
2960
3048
  const void *ret = node->obj;
2961
3049
  node->next->prev = node->prev;
2962
3050
  node->prev->next = node->next;
2963
- free(node);
3051
+ FIO_FREE(node);
2964
3052
  return (void *)ret;
2965
3053
  }
2966
3054
 
@@ -2969,11 +3057,8 @@ FIO_FUNC inline fio_ls_s *fio_ls_push(fio_ls_s *pos, const void *obj) {
2969
3057
  if (!pos)
2970
3058
  return NULL;
2971
3059
  /* prepare item */
2972
- fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
2973
- if (!item) {
2974
- perror("ERROR: simple list couldn't allocate memory");
2975
- exit(errno);
2976
- }
3060
+ fio_ls_s *item = (fio_ls_s *)FIO_MALLOC(sizeof(*item));
3061
+ FIO_ASSERT_ALLOC(item);
2977
3062
  *item = (fio_ls_s){.prev = pos->prev, .next = pos, .obj = obj};
2978
3063
  /* inject item */
2979
3064
  pos->prev->next = item;
@@ -3105,15 +3190,20 @@ typedef struct {
3105
3190
  .dealloc = FIO_FREE})
3106
3191
 
3107
3192
  /**
3108
- * This macro allows the container to be initialized with existing data, as long
3109
- * as it's memory was allocated using `fio_malloc`.
3110
- *
3111
- * The `capacity` value should exclude the NUL character (if exists).
3193
+ * This macro allows the container to be initialized with existing static data,
3194
+ * that shouldn't be freed.
3112
3195
  */
3113
3196
  #define FIO_STR_INIT_STATIC(buffer) \
3114
3197
  ((fio_str_s){ \
3115
3198
  .data = (char *)(buffer), .len = strlen((buffer)), .dealloc = NULL})
3116
3199
 
3200
+ /**
3201
+ * This macro allows the container to be initialized with existing static data,
3202
+ * that shouldn't be freed.
3203
+ */
3204
+ #define FIO_STR_INIT_STATIC2(buffer, length) \
3205
+ ((fio_str_s){.data = (char *)(buffer), .len = (length), .dealloc = NULL})
3206
+
3117
3207
  /**
3118
3208
  * Allocates a new fio_str_s object on the heap and initializes it.
3119
3209
  *
@@ -3629,10 +3719,6 @@ String Implementation - Memory management
3629
3719
  * directly to `mmap` (due to their size, usually over 12KB).
3630
3720
  */
3631
3721
  #define ROUND_UP_CAPA2WORDS(num) (((num) + 1) | (sizeof(long double) - 1))
3632
- // Smaller might be:
3633
- // ((((num) + 1) & (sizeof(long double) - 1))
3634
- // ? (((num) + 1) | (sizeof(long double) - 1))
3635
- // : (num))
3636
3722
 
3637
3723
  /**
3638
3724
  * Requires the String to have at least `needed` capacity. Returns the current
@@ -5908,5 +5994,6 @@ restart:
5908
5994
  #undef FIO_NAME_FROM_MACRO_STEP3
5909
5995
  #undef FIO_NAME_FREE
5910
5996
  #undef FIO_SET_NAME
5997
+ #undef FIO_FORCE_MALLOC_TMP
5911
5998
 
5912
5999
  #endif