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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1727f338fb31c8ab46956d8e3b45af0d374ce100771305ba73f5b690467cff54
4
- data.tar.gz: ef706da6cd642d2de4a464e3a5b6b90c8afd5cec294456dde2fa841b625a222a
3
+ metadata.gz: d9304bf27335fe19b9c7d7ca9442fe994772c5489a70aa598cc045bda313c755
4
+ data.tar.gz: 8acee18f9da3f77a763fb7c93ac2c4328788c79298c5b792597e6b40ee1b14c5
5
5
  SHA512:
6
- metadata.gz: 3d114bf645e22f6bef700c782dcfa3daa263d94bcadac5ecb543a67abe593884c86ea6eb6b9c99fb8480385f8e8f9c211ce27901645bf776b84a2d75b7ba1c61
7
- data.tar.gz: f5029fd64683ffd485c8091686f5fc2e905abee7776d94c15c5d9b80cff3093a5147cffa502a45f1fe0d0d9de884909edc5ceac0c1a0cb565cb72d40dd5b994f
6
+ metadata.gz: aef5181c233342793d2c74a8d4ca6c398a357c36bc399dd133f796aa0c2e67ed881d99514b45c2e85da880e0a2b49844fa869afc28be696dc63675558b7dba2c
7
+ data.tar.gz: 6e6f11fd287cafbcc9eae4ef3df92fe4b4c543e9d930344745725c59cc4be587d24e8c226416ae65208516bd995afa90c210847f0e8faf9873dfe3913c4ef7dc
@@ -24,8 +24,8 @@ addons:
24
24
  script:
25
25
  - gem uninstall -x iodine
26
26
  - rake build
27
- - find pkg/iodine-*.gem -exec gem install {} +
27
+ - find pkg/iodine-*.gem -exec gem install -V {} +
28
28
  - gem uninstall -x iodine
29
- - CC=gcc find pkg/iodine-*.gem -exec gem install {} +
29
+ - CC=gcc find pkg/iodine-*.gem -exec gem install -V {} +
30
30
  - gem uninstall -x iodine
31
- - CC=gcc-5 find pkg/iodine-*.gem -exec gem install {} +
31
+ - CC=gcc-5 find pkg/iodine-*.gem -exec gem install -V {} +
@@ -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.2
10
+
11
+ **Updated**: updated the logging for HTTP services startup, to minimize log clutter.
12
+
13
+ **Feature**: (mustache) added features to `Iodine::Mustache`, to expose more of the functionality offered by facil.io.
14
+
15
+ **Fix**: (facil.io) updated from the facil.io edge (master) branch. This should fix some exposed symbols (that should have been private), minimize name-collision risks, and fix an unknown issue with the mime-type registry cleanup and other possible issues.
16
+
9
17
  #### Change log v.0.7.1
10
18
 
11
19
  **Fix**: Fixed compilation issues with older `gcc` compilers.
@@ -25,6 +25,7 @@ def benchmark_mustache
25
25
  """
26
26
 
27
27
  IO.write "test_template.mustache", template
28
+ filename = "test_template.mustache"
28
29
 
29
30
  data_1 = {
30
31
  products: [ {
@@ -33,31 +34,6 @@ def benchmark_mustache
33
34
  :image=>"products/product.jpg"
34
35
  } ]
35
36
  }
36
-
37
- data_10 = {
38
- products: []
39
- }
40
-
41
- 10.times do
42
- data_10[:products] << {
43
- :external_index=>"product",
44
- :url=>"/products/7",
45
- :image=>"products/product.jpg"
46
- }
47
- end
48
-
49
- data_100 = {
50
- products: []
51
- }
52
-
53
- 100.times do
54
- data_100[:products] << {
55
- :external_index=>"product",
56
- :url=>"/products/7",
57
- :image=>"products/product.jpg"
58
- }
59
- end
60
-
61
37
  data_1000 = {
62
38
  products: []
63
39
  }
@@ -85,7 +61,7 @@ def benchmark_mustache
85
61
  view = Mustache.new
86
62
  view.template = template
87
63
  view.render # Call render once so the template will be compiled
88
- iodine_view = Iodine::Mustache.new("test_template")
64
+ iodine_view = Iodine::Mustache.new(filename)
89
65
 
90
66
  puts "Ruby Mustache rendering (and HTML escaping) results in:",
91
67
  view.render(data_1), "",
@@ -95,20 +71,6 @@ def benchmark_mustache
95
71
  # return;
96
72
 
97
73
  Benchmark.ips do |x|
98
- x.report("Ruby Mustache render list of 10") do |times|
99
- view.render(data_10)
100
- end
101
- x.report("Iodine::Mustache render list of 10") do |times|
102
- iodine_view.render(data_10)
103
- end
104
-
105
- x.report("Ruby Mustache render list of 100") do |times|
106
- view.render(data_100)
107
- end
108
- x.report("Iodine::Mustache render list of 100") do |times|
109
- iodine_view.render(data_100)
110
- end
111
-
112
74
  x.report("Ruby Mustache render list of 1000") do |times|
113
75
  view.render(data_1000)
114
76
  end
@@ -122,6 +84,16 @@ def benchmark_mustache
122
84
  x.report("Iodine::Mustache render list of 1000 with escaped data") do |times|
123
85
  iodine_view.render(data_1000_escaped)
124
86
  end
87
+
88
+ x.report("Ruby Mustache - no chaching - render list of 1000") do |times|
89
+ tmp = Mustache.new
90
+ tmp.template = template
91
+ tmp.render(data_1000)
92
+ end
93
+ x.report("Iodine::Mustache - no chaching - render list of 1000") do |times|
94
+ Iodine::Mustache.render(nil, data_1000, template)
95
+ end
96
+
125
97
  end
126
98
  end
127
99
 
@@ -69,6 +69,10 @@ Feel free to copy, use and enjoy according to the license provided.
69
69
  #define DEBUG_SPINLOCK 0
70
70
  #endif
71
71
 
72
+ #if !defined(__clang__) && !defined(__GNUC__)
73
+ #define __thread _Thread_value
74
+ #endif
75
+
72
76
  /* *****************************************************************************
73
77
  Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
74
78
  ***************************************************************************** */
@@ -218,7 +222,13 @@ typedef struct {
218
222
  fio_fd_data_s info[];
219
223
  } fio_data_s;
220
224
 
221
- fio_data_s *fio_data = NULL;
225
+ /** The logging level */
226
+ #if DEBUG
227
+ size_t FIO_LOG_LEVEL = FIO_LOG_LEVEL_DEBUG;
228
+ #else
229
+ size_t FIO_LOG_LEVEL = FIO_LOG_LEVEL_INFO;
230
+ #endif
231
+ static fio_data_s *fio_data = NULL;
222
232
 
223
233
  /* used for protocol locking by task type. */
224
234
  typedef struct {
@@ -294,11 +304,15 @@ static void fio_max_fd_shrink(void) {
294
304
  static inline int fio_clear_fd(intptr_t fd, uint8_t is_open) {
295
305
  fio_packet_s *packet;
296
306
  fio_protocol_s *protocol;
307
+ fio_rw_hook_s *rw_hooks;
308
+ void *rw_udata;
297
309
  fio_uuid_links_s links;
298
310
  fio_lock(&(fd_data(fd).sock_lock));
299
311
  links = fd_data(fd).links;
300
312
  packet = fd_data(fd).packet;
301
313
  protocol = fd_data(fd).protocol;
314
+ rw_hooks = fd_data(fd).rw_hooks;
315
+ rw_udata = fd_data(fd).rw_udata;
302
316
  fd_data(fd) = (fio_fd_data_s){
303
317
  .open = is_open,
304
318
  .sock_lock = fd_data(fd).sock_lock,
@@ -308,6 +322,8 @@ static inline int fio_clear_fd(intptr_t fd, uint8_t is_open) {
308
322
  .packet_last = &fd_data(fd).packet,
309
323
  };
310
324
  fio_unlock(&(fd_data(fd).sock_lock));
325
+ if (rw_hooks && rw_hooks->cleanup)
326
+ rw_hooks->cleanup(rw_udata);
311
327
  while (packet) {
312
328
  fio_packet_s *tmp = packet;
313
329
  packet = packet->next;
@@ -319,6 +335,7 @@ static inline int fio_clear_fd(intptr_t fd, uint8_t is_open) {
319
335
  pos->obj((void *)pos->hash);
320
336
  }
321
337
  }
338
+ fio_uuid_links_free(&links);
322
339
  if (protocol && protocol->on_close) {
323
340
  fio_defer(deferred_on_close, (void *)fd2uuid(fd), protocol);
324
341
  }
@@ -365,12 +382,10 @@ inline static void protocol_unlock(fio_protocol_s *pr,
365
382
  }
366
383
 
367
384
  /** returns 1 if the UUID is valid and 0 if it isn't. */
368
- inline static size_t uuid_is_valid(uintptr_t uuid) {
369
- if (uuid == (uintptr_t)-1 || (uintptr_t)fio_uuid2fd(uuid) >= fio_data->capa ||
370
- (uuid & 0xFF) != uuid_data(uuid).counter)
371
- return 0;
372
- return 1;
373
- }
385
+ #define uuid_is_valid(uuid) \
386
+ ((intptr_t)(uuid) != -1 && \
387
+ ((uint32_t)fio_uuid2fd((uuid))) < fio_data->capa && \
388
+ ((uintptr_t)(uuid)&0xFF) == uuid_data((uuid)).counter)
374
389
 
375
390
  /* public API. */
376
391
  fio_protocol_s *fio_protocol_try_lock(intptr_t uuid,
@@ -516,7 +531,7 @@ typedef struct {
516
531
  void (*on_finish)(void *);
517
532
  } fio_timer_s;
518
533
 
519
- fio_ls_embd_s fio_timers = FIO_LS_INIT(fio_timers);
534
+ static fio_ls_embd_s fio_timers = FIO_LS_INIT(fio_timers);
520
535
 
521
536
  static fio_lock_i fio_timer_lock = FIO_LOCK_INIT;
522
537
 
@@ -961,8 +976,7 @@ static fio_defer_thread_pool_s *fio_defer_thread_pool_new(size_t count) {
961
976
  }
962
977
  return pool;
963
978
  error:
964
- fprintf(stderr, "CRITICAL ERROR: couldn't spawn threads for thread pool, "
965
- "attempting shutdown.\n");
979
+ FIO_LOG_FATAL("couldn't spawn threads for thread pool, attempting shutdown.");
966
980
  fio_stop();
967
981
  fio_defer_thread_pool_join(pool);
968
982
  return NULL;
@@ -1209,11 +1223,11 @@ static inline size_t fio_detect_cpu_cores(void) {
1209
1223
  #ifdef _SC_NPROCESSORS_ONLN
1210
1224
  cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
1211
1225
  if (cpu_count < 0) {
1212
- FIO_LOG_STATE("WARNING: CPU core count auto-detection failed.\n");
1226
+ FIO_LOG_WARNING("CPU core count auto-detection failed.");
1213
1227
  return 0;
1214
1228
  }
1215
1229
  #else
1216
- FIO_LOG_STATE("WARNING: CPU core count auto-detection failed.\n");
1230
+ FIO_LOG_WARNING("CPU core count auto-detection failed.");
1217
1231
  #endif
1218
1232
  return cpu_count;
1219
1233
  }
@@ -1236,13 +1250,11 @@ void fio_expected_concurrency(int16_t *threads, int16_t *processes) {
1236
1250
  if (cpu_count > FIO_CPU_CORES_LIMIT) {
1237
1251
  static int print_cores_warning = 1;
1238
1252
  if (print_cores_warning) {
1239
- fprintf(
1240
- stderr,
1241
- "INFO: Detected %zu cores. Capping auto-detection of cores "
1242
- "to %zu.\n"
1253
+ FIO_LOG_WARNING(
1254
+ "Detected %zu cores. Capping auto-detection of cores to %zu.\n"
1243
1255
  " Avoid this message by setting threads / workers manually.\n"
1244
1256
  " To increase auto-detection limit, recompile with:\n"
1245
- " -DFIO_CPU_CORES_LIMIT=%zu \n",
1257
+ " -DFIO_CPU_CORES_LIMIT=%zu",
1246
1258
  (size_t)cpu_count, (size_t)FIO_CPU_CORES_LIMIT, (size_t)cpu_count);
1247
1259
  print_cores_warning = 0;
1248
1260
  }
@@ -1500,7 +1512,7 @@ static void fio_poll_init(void) {
1500
1512
  fio_poll_close();
1501
1513
  evio_fd = kqueue();
1502
1514
  if (evio_fd == -1) {
1503
- fprintf(stderr, "FATAL ERROR: couldn't open kqueue.\n");
1515
+ FIO_LOG_FATAL("couldn't open kqueue.\n");
1504
1516
  exit(errno);
1505
1517
  }
1506
1518
  }
@@ -1580,6 +1592,7 @@ static size_t fio_poll(void) {
1580
1592
  // (events[i].flags & EV_EOF)
1581
1593
  // ? "EV_EOF"
1582
1594
  // : (events[i].flags & EV_ERROR) ? "EV_ERROR" : "WTF?");
1595
+ // uuid_data(events[i].udata).open = 0;
1583
1596
  fio_force_close(fd2uuid(events[i].udata));
1584
1597
  } else if (events[i].filter == EVFILT_WRITE) {
1585
1598
  // we can only write if there's no error in the socket
@@ -1715,22 +1728,22 @@ static size_t fio_poll(void) {
1715
1728
  touchfd(i);
1716
1729
  ++count;
1717
1730
  if (list[i].revents & FIO_POLL_READ_EVENTS) {
1718
- // fprintf(stderr, "Poll Read %zu => %p\n", i, (void *)fd2uuid(i));
1731
+ // FIO_LOG_DEBUG("Poll Read %zu => %p", i, (void *)fd2uuid(i));
1719
1732
  fio_poll_remove_read(i);
1720
1733
  fio_defer(deferred_on_data, (void *)fd2uuid(i), NULL);
1721
1734
  }
1722
1735
  if (list[i].revents & FIO_POLL_WRITE_EVENTS) {
1723
- // fprintf(stderr, "Poll Write %zu => %p\n", i, (void *)fd2uuid(i));
1736
+ // FIO_LOG_DEBUG("Poll Write %zu => %p", i, (void *)fd2uuid(i));
1724
1737
  fio_poll_remove_write(i);
1725
1738
  fio_defer(deferred_on_ready, (void *)fd2uuid(i), NULL);
1726
1739
  }
1727
1740
  if (list[i].revents & (POLLHUP | POLLERR)) {
1728
- // fprintf(stderr, "Poll Hangup %zu => %p\n", i, (void *)fd2uuid(i));
1741
+ // FIO_LOG_DEBUG("Poll Hangup %zu => %p", i, (void *)fd2uuid(i));
1729
1742
  fio_poll_remove_fd(i);
1730
1743
  fio_force_close(fd2uuid(i));
1731
1744
  }
1732
1745
  if (list[i].revents & POLLNVAL) {
1733
- // fprintf(stderr, "Poll Invalid %zu => %p\n", i, (void *)fd2uuid(i));
1746
+ // FIO_LOG_DEBUG("Poll Invalid %zu => %p", i, (void *)fd2uuid(i));
1734
1747
  fio_poll_remove_fd(i);
1735
1748
  fio_lock(&fd_data(i).protocol_lock);
1736
1749
  fio_clear_fd(i, 0);
@@ -2104,15 +2117,15 @@ static intptr_t fio_unix_socket(const char *address, uint8_t server) {
2104
2117
  /* Unix socket */
2105
2118
  if (!address) {
2106
2119
  errno = EINVAL;
2107
- fprintf(stderr,
2108
- "ERROR: (fio) a Unix socket requires a valid address."
2109
- " Specify port for TCP/IP socket or change address.\n");
2120
+ FIO_LOG_ERROR(
2121
+ "(fio) a Unix socket requires a valid address.\n"
2122
+ " Specify port for TCP/IP socket or change address.");
2110
2123
  return -1;
2111
2124
  }
2112
2125
  struct sockaddr_un addr = {0};
2113
2126
  size_t addr_len = strlen(address);
2114
2127
  if (addr_len >= sizeof(addr.sun_path)) {
2115
- fprintf(stderr, "ERROR: (fio) a Unix socket address too long.\n");
2128
+ FIO_LOG_ERROR("(fio) a Unix socket address too long.");
2116
2129
  errno = ENAMETOOLONG;
2117
2130
  return -1;
2118
2131
  }
@@ -2563,7 +2576,7 @@ void fio_force_close(intptr_t uuid) {
2563
2576
  errno = EBADF;
2564
2577
  return;
2565
2578
  }
2566
- /* clear away any packets in case we want to cut the connection short */
2579
+ /* clear away any packets in case we want to cut the connection short. */
2567
2580
  fio_packet_s *packet;
2568
2581
  fio_lock(&uuid_data(uuid).sock_lock);
2569
2582
  packet = uuid_data(uuid).packet;
@@ -2702,12 +2715,16 @@ static ssize_t fio_hooks_default_flush(intptr_t uuid, void *udata) {
2702
2715
  (void)(udata);
2703
2716
  }
2704
2717
 
2718
+ static void fio_hooks_default_cleanup(void *udata) { (void)(udata); }
2719
+
2705
2720
  const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS = {
2706
2721
  .read = fio_hooks_default_read,
2707
2722
  .write = fio_hooks_default_write,
2708
2723
  .flush = fio_hooks_default_flush,
2709
2724
  .close = fio_hooks_default_close,
2725
+ .cleanup = fio_hooks_default_cleanup,
2710
2726
  };
2727
+
2711
2728
  /** Sets a socket hook state (a pointer to the struct). */
2712
2729
  int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata) {
2713
2730
  if (fio_is_closed(uuid))
@@ -2720,11 +2737,19 @@ int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata) {
2720
2737
  rw_hooks->flush = fio_hooks_default_flush;
2721
2738
  if (!rw_hooks->close)
2722
2739
  rw_hooks->close = fio_hooks_default_close;
2740
+ if (!rw_hooks->cleanup)
2741
+ rw_hooks->cleanup = fio_hooks_default_cleanup;
2723
2742
  uuid = fio_uuid2fd(uuid);
2743
+ fio_rw_hook_s *old_rw_hooks;
2744
+ void *old_udata;
2724
2745
  fio_lock(&fd_data(uuid).sock_lock);
2746
+ old_rw_hooks = fd_data(uuid).rw_hooks;
2747
+ old_udata = fd_data(uuid).rw_udata;
2725
2748
  fd_data(uuid).rw_hooks = rw_hooks;
2726
2749
  fd_data(uuid).rw_udata = udata;
2727
2750
  fio_unlock(&fd_data(uuid).sock_lock);
2751
+ if (old_rw_hooks && old_rw_hooks->cleanup)
2752
+ old_rw_hooks->cleanup(old_udata);
2728
2753
  return 0;
2729
2754
  }
2730
2755
 
@@ -2852,6 +2877,10 @@ typedef struct {
2852
2877
 
2853
2878
  static callback_collection_s callback_collection[FIO_CALL_NEVER + 1];
2854
2879
 
2880
+ static void fio_state_on_idle_perform(void *task, void *arg) {
2881
+ ((void (*)(void *))(uintptr_t)task)(arg);
2882
+ }
2883
+
2855
2884
  static inline void fio_state_callback_ensure(callback_collection_s *c) {
2856
2885
  if (c->callbacks.next)
2857
2886
  return;
@@ -2905,12 +2934,46 @@ void fio_state_callback_force(callback_type_e c_type) {
2905
2934
  fio_ls_embd_s copy = FIO_LS_INIT(copy);
2906
2935
  fio_lock(&callback_collection[c_type].lock);
2907
2936
  fio_state_callback_ensure(&callback_collection[c_type]);
2908
- FIO_LS_EMBD_FOR(&callback_collection[c_type].callbacks, pos) {
2909
- callback_data_s *tmp = fio_malloc(sizeof(*tmp));
2910
- FIO_ASSERT_ALLOC(tmp);
2911
- *tmp = *(FIO_LS_EMBD_OBJ(callback_data_s, node, pos));
2912
- fio_ls_embd_push(&copy, &tmp->node);
2937
+ switch (c_type) { /* the difference between `unshift` and `push` */
2938
+ case FIO_CALL_ON_INITIALIZE: /* overflow */
2939
+ case FIO_CALL_PRE_START: /* overflow */
2940
+ case FIO_CALL_BEFORE_FORK: /* overflow */
2941
+ case FIO_CALL_AFTER_FORK: /* overflow */
2942
+ case FIO_CALL_IN_CHILD: /* overflow */
2943
+ case FIO_CALL_IN_MASTER: /* overflow */
2944
+ case FIO_CALL_ON_START: /* overflow */
2945
+ FIO_LS_EMBD_FOR(&callback_collection[c_type].callbacks, pos) {
2946
+ callback_data_s *tmp = fio_malloc(sizeof(*tmp));
2947
+ FIO_ASSERT_ALLOC(tmp);
2948
+ *tmp = *(FIO_LS_EMBD_OBJ(callback_data_s, node, pos));
2949
+ fio_ls_embd_unshift(&copy, &tmp->node);
2950
+ }
2951
+ break;
2952
+
2953
+ case FIO_CALL_ON_IDLE: /* idle callbacks are orderless and evented */
2954
+ FIO_LS_EMBD_FOR(&callback_collection[c_type].callbacks, pos) {
2955
+ callback_data_s *tmp = FIO_LS_EMBD_OBJ(callback_data_s, node, pos);
2956
+ fio_defer(fio_state_on_idle_perform, (void *)(uintptr_t)tmp->func,
2957
+ tmp->arg);
2958
+ }
2959
+ break;
2960
+
2961
+ case FIO_CALL_ON_SHUTDOWN: /* overflow */
2962
+ case FIO_CALL_ON_FINISH: /* overflow */
2963
+ case FIO_CALL_ON_PARENT_CRUSH: /* overflow */
2964
+ case FIO_CALL_ON_CHILD_CRUSH: /* overflow */
2965
+ case FIO_CALL_AT_EXIT: /* overflow */
2966
+ case FIO_CALL_NEVER: /* overflow */
2967
+ default:
2968
+ FIO_LS_EMBD_FOR(&callback_collection[c_type].callbacks, pos) {
2969
+ callback_data_s *tmp = fio_malloc(sizeof(*tmp));
2970
+ FIO_ASSERT_ALLOC(tmp);
2971
+ *tmp = *(FIO_LS_EMBD_OBJ(callback_data_s, node, pos));
2972
+ fio_ls_embd_push(&copy, &tmp->node);
2973
+ }
2974
+ break;
2913
2975
  }
2976
+
2914
2977
  fio_unlock(&callback_collection[c_type].lock);
2915
2978
  /* run callbacks + free data */
2916
2979
  while (fio_ls_embd_any(&copy)) {
@@ -3004,7 +3067,6 @@ void fio_defer_io_task FIO_IGNORE_MACRO(intptr_t uuid,
3004
3067
  Initialize the library
3005
3068
  ***************************************************************************** */
3006
3069
 
3007
- static void fio_malloc_after_fork(void);
3008
3070
  static void fio_pubsub_on_fork(void);
3009
3071
 
3010
3072
  static void fio_mem_destroy(void);
@@ -3018,10 +3080,8 @@ static void __attribute__((destructor)) fio_lib_destroy(void) {
3018
3080
  fio_free(fio_data);
3019
3081
  /* memory library destruction must be last */
3020
3082
  fio_mem_destroy();
3021
- #if DEBUG
3022
- FIO_LOG_STATE("* (%d) facil.io resources released, exit complete.\n",
3023
- getpid());
3024
- #endif
3083
+ FIO_LOG_DEBUG("(%d) facil.io resources released, exit complete.", getpid());
3084
+ fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
3025
3085
  }
3026
3086
 
3027
3087
  /* Called within a child process after it starts. */
@@ -3071,7 +3131,7 @@ static void __attribute__((constructor)) fio_lib_init(void) {
3071
3131
  // try to maximize limits - collect max and set to max
3072
3132
  struct rlimit rlim = {.rlim_max = 0};
3073
3133
  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1) {
3074
- fprintf(stderr, "WARNING: `getrlimit` failed in `sock_max_capacity`.\n");
3134
+ FIO_LOG_WARNING("`getrlimit` failed in `sock_max_capacity`.");
3075
3135
  } else {
3076
3136
  // #if defined(__APPLE__) /* Apple's getrlimit is broken. */
3077
3137
  // rlim.rlim_cur = rlim.rlim_max >= FOPEN_MAX ? FOPEN_MAX :
@@ -3092,7 +3152,7 @@ static void __attribute__((constructor)) fio_lib_init(void) {
3092
3152
  FIO_LOG_STATE("facil.io " FIO_VERSION_STRING " capacity initialization:\n"
3093
3153
  "* Meximum open files %zu out of %zu\n"
3094
3154
  "* Allocating %zu bytes for state handling.\n"
3095
- "* %zu bytes per connection + %zu for state handling.\n",
3155
+ "* %zu bytes per connection + %zu for state handling.",
3096
3156
  capa, (size_t)rlim.rlim_max,
3097
3157
  (sizeof(*fio_data) + (capa * (sizeof(*fio_data->poll))) +
3098
3158
  (capa * (sizeof(*fio_data->info)))),
@@ -3102,7 +3162,7 @@ static void __attribute__((constructor)) fio_lib_init(void) {
3102
3162
  FIO_LOG_STATE("facil.io " FIO_VERSION_STRING " capacity initialization:\n"
3103
3163
  "* Meximum open files %zu out of %zu\n"
3104
3164
  "* Allocating %zu bytes for state handling.\n"
3105
- "* %zu bytes per connection + %zu for state handling.\n",
3165
+ "* %zu bytes per connection + %zu for state handling.",
3106
3166
  capa, (size_t)rlim.rlim_max,
3107
3167
  (sizeof(*fio_data) + (capa * (sizeof(*fio_data->info)))),
3108
3168
  (sizeof(*fio_data->info)), sizeof(*fio_data));
@@ -3277,7 +3337,7 @@ static void fio_worker_startup(void) {
3277
3337
  fio_data->is_worker = 1;
3278
3338
  } else if (fio_data->is_worker) {
3279
3339
  /* Worker Process */
3280
- FIO_LOG_STATE("* %d is running.\n", getpid());
3340
+ FIO_LOG_INFO("%d is running.", getpid());
3281
3341
  } else {
3282
3342
  /* Root Process should run in single thread mode */
3283
3343
  fio_data->threads = 1;
@@ -3298,9 +3358,9 @@ static void fio_worker_startup(void) {
3298
3358
  static void fio_worker_cleanup(void) {
3299
3359
  /* switch to winding down */
3300
3360
  if (fio_data->is_worker)
3301
- FIO_LOG_STATE("* (%d) detected exit signal.\n", getpid());
3361
+ FIO_LOG_INFO("(%d) detected exit signal.", getpid());
3302
3362
  else
3303
- FIO_LOG_STATE("* Server Detected exit signal.\n");
3363
+ FIO_LOG_INFO("Server Detected exit signal.");
3304
3364
  fio_state_callback_force(FIO_CALL_ON_SHUTDOWN);
3305
3365
  for (size_t i = 0; i <= fio_data->max_protocol_fd; ++i) {
3306
3366
  if (fd_data(i).protocol) {
@@ -3325,9 +3385,9 @@ static void fio_worker_cleanup(void) {
3325
3385
  fio_defer_perform();
3326
3386
  fio_signal_handler_reset();
3327
3387
  if (fio_data->parent == getpid()) {
3328
- FIO_LOG_STATE("\n --- Shutdown Complete ---\n");
3388
+ FIO_LOG_INFO(" --- Shutdown Complete ---\n");
3329
3389
  } else {
3330
- FIO_LOG_STATE("* (%d) cleanup complete.\n", getpid());
3390
+ FIO_LOG_INFO("(%d) cleanup complete.", getpid());
3331
3391
  }
3332
3392
  }
3333
3393
 
@@ -3338,7 +3398,8 @@ static void *fio_sentinel_worker_thread(void *arg) {
3338
3398
  /* release fork lock. */
3339
3399
  fio_unlock(&fio_fork_lock);
3340
3400
  if (child == -1) {
3341
- perror("FATAL ERROR: couldn't spawn worker.");
3401
+ FIO_LOG_FATAL("couldn't spawn worker.");
3402
+ perror("\n errno");
3342
3403
  kill(fio_parent_pid(), SIGINT);
3343
3404
  fio_stop();
3344
3405
  return NULL;
@@ -3348,17 +3409,10 @@ static void *fio_sentinel_worker_thread(void *arg) {
3348
3409
  #if DEBUG
3349
3410
  if (fio_data->active) { /* !WIFEXITED(status) || WEXITSTATUS(status) */
3350
3411
  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
3351
- FIO_LOG_STATE(
3352
- "FATAL ERROR: Child worker (%d) crashed. Stopping services in "
3353
- "DEBUG mode.\n",
3354
- child);
3412
+ FIO_LOG_FATAL("Child worker (%d) crashed. Stopping services.", child);
3355
3413
  fio_state_callback_force(FIO_CALL_ON_CHILD_CRUSH);
3356
3414
  } else {
3357
- fprintf(
3358
- stderr,
3359
- "INFO (FATAL): Child worker (%d) shutdown. Stopping services in "
3360
- "DEBUG mode.\n",
3361
- child);
3415
+ FIO_LOG_FATAL("Child worker (%d) shutdown. Stopping services.", child);
3362
3416
  }
3363
3417
  kill(0, SIGINT);
3364
3418
  }
@@ -3367,13 +3421,11 @@ static void *fio_sentinel_worker_thread(void *arg) {
3367
3421
  /* don't call any functions while forking. */
3368
3422
  fio_lock(&fio_fork_lock);
3369
3423
  if (!WIFEXITED(status) || WEXITSTATUS(status)) {
3370
- fprintf(stderr,
3371
- "ERROR: Child worker (%d) crashed. Respawning worker.\n",
3372
- child);
3424
+ FIO_LOG_ERROR("Child worker (%d) crashed. Respawning worker.", child);
3373
3425
  fio_state_callback_force(FIO_CALL_ON_CHILD_CRUSH);
3374
3426
  } else {
3375
- FIO_LOG_STATE("INFO: Child worker (%d) shutdown. Respawning worker.\n",
3376
- child);
3427
+ FIO_LOG_WARNING("Child worker (%d) shutdown. Respawning worker.",
3428
+ child);
3377
3429
  }
3378
3430
  fio_defer(fio_sentinel_task, NULL, NULL);
3379
3431
  fio_unlock(&fio_fork_lock);
@@ -3402,6 +3454,7 @@ static void fio_sentinel_task(void *arg1, void *arg2) {
3402
3454
  fio_lock(&fio_fork_lock); /* will wait for worker thread to release lock. */
3403
3455
  fio_unlock(&fio_fork_lock); /* release lock for next fork. */
3404
3456
  fio_state_callback_force(FIO_CALL_AFTER_FORK);
3457
+ fio_state_callback_force(FIO_CALL_IN_MASTER);
3405
3458
  (void)arg1;
3406
3459
  (void)arg2;
3407
3460
  }
@@ -3846,10 +3899,10 @@ static void fio_listen_on_startup(void *pr_) {
3846
3899
  fio_listen_protocol_s *pr = pr_;
3847
3900
  fio_attach(pr->uuid, &pr->pr);
3848
3901
  if (pr->port_len)
3849
- FIO_LOG_STATE("* (%d) started listening on port %s\n", getpid(), pr->port);
3902
+ FIO_LOG_INFO("(%d) started listening on port %s", getpid(), pr->port);
3850
3903
  else
3851
- FIO_LOG_STATE("* (%d) started listening on Unix Socket at %s\n", getpid(),
3852
- pr->addr);
3904
+ FIO_LOG_INFO("(%d) started listening on Unix Socket at %s", getpid(),
3905
+ pr->addr);
3853
3906
  }
3854
3907
 
3855
3908
  static void fio_listen_on_close(intptr_t uuid, fio_protocol_s *pr_) {
@@ -3867,6 +3920,8 @@ static void fio_listen_on_data(intptr_t uuid, fio_protocol_s *pr_) {
3867
3920
  }
3868
3921
  }
3869
3922
 
3923
+ /* stub for editor - unused */
3924
+ void fio_listen____(void);
3870
3925
  /**
3871
3926
  * Schedule a network service on a listening socket.
3872
3927
  *
@@ -3922,9 +3977,9 @@ intptr_t fio_listen FIO_IGNORE_MACRO(struct fio_listen_args args) {
3922
3977
  }
3923
3978
 
3924
3979
  if (args.port)
3925
- FIO_LOG_STATE("* Listening on port %s\n", args.port);
3980
+ FIO_LOG_INFO("Listening on port %s", args.port);
3926
3981
  else
3927
- FIO_LOG_STATE("* Listening on Unix Socket at %s\n", args.address);
3982
+ FIO_LOG_INFO("Listening on Unix Socket at %s", args.address);
3928
3983
 
3929
3984
  return uuid;
3930
3985
  error:
@@ -4160,7 +4215,7 @@ struct fio_collection_s {
4160
4215
  #define COLLECTION_INIT \
4161
4216
  { .channels = FIO_SET_INIT, .lock = FIO_LOCK_INIT }
4162
4217
 
4163
- struct {
4218
+ static struct {
4164
4219
  fio_collection_s filters;
4165
4220
  fio_collection_s pubsub;
4166
4221
  fio_collection_s patterns;
@@ -4281,7 +4336,7 @@ static channel_s *fio_channel_dup_lock(fio_str_info_s name) {
4281
4336
  .lock = FIO_LOCK_INIT,
4282
4337
  };
4283
4338
  fio_str_write(&ch->id, name.data, name.len);
4284
- // fio_str_freeze(&ch->id);
4339
+ fio_str_freeze(&ch->id);
4285
4340
  uint64_t hashed_name = fio_str_hash(&ch->id);
4286
4341
  ch = fio_filter_dup_lock_internal(ch, hashed_name, &fio_postoffice.pubsub);
4287
4342
  if (fio_ls_embd_is_empty(&ch->subscriptions)) {
@@ -4331,7 +4386,7 @@ static inline void fio_subscription_free(subscription_s *s) {
4331
4386
  /** Subscribes to a filter, pub/sub channle or patten */
4332
4387
  subscription_s *fio_subscribe FIO_IGNORE_MACRO(subscribe_args_s args) {
4333
4388
  if (!args.on_message)
4334
- return NULL;
4389
+ goto error;
4335
4390
  channel_s *ch;
4336
4391
  subscription_s *s = fio_malloc(sizeof(*s));
4337
4392
  FIO_ASSERT_ALLOC(s);
@@ -4354,6 +4409,10 @@ subscription_s *fio_subscribe FIO_IGNORE_MACRO(subscribe_args_s args) {
4354
4409
  fio_ls_embd_push(&ch->subscriptions, &s->node);
4355
4410
  fio_unlock((&ch->lock));
4356
4411
  return s;
4412
+ error:
4413
+ if (args.on_unsubscribe)
4414
+ args.on_unsubscribe(args.udata1, args.udata2);
4415
+ return NULL;
4357
4416
  }
4358
4417
 
4359
4418
  /** Unsubscribes from a filter, pub/sub channle or patten */
@@ -4375,6 +4434,7 @@ void fio_unsubscribe(subscription_s *s) {
4375
4434
  if (c == &fio_postoffice.patterns) {
4376
4435
  pattern_s *pat = (pattern_s *)ch;
4377
4436
  hashed ^= ((uintptr_t)pat->match);
4437
+ match = ((pattern_s *)(ch))->match;
4378
4438
  }
4379
4439
  /* lock collection */
4380
4440
  fio_lock(&c->lock);
@@ -4387,9 +4447,6 @@ void fio_unsubscribe(subscription_s *s) {
4387
4447
  }
4388
4448
  fio_unlock(&ch->lock);
4389
4449
  if (removed) {
4390
- if (ch->parent == &fio_postoffice.patterns) {
4391
- match = ((pattern_s *)(ch))->match;
4392
- }
4393
4450
  pubsub_on_channel_destroy(ch, match);
4394
4451
  }
4395
4452
 
@@ -4678,9 +4735,6 @@ static void fio_perform_subscription_callback(void *s_, void *msg_) {
4678
4735
 
4679
4736
  /** UNSAFE! publishes a message to a channel, managing the reference counts */
4680
4737
  static void fio_publish2channel(channel_s *ch, fio_msg_internal_s *msg) {
4681
- if (!ch || !msg) {
4682
- return;
4683
- }
4684
4738
  FIO_LS_EMBD_FOR(&ch->subscriptions, pos) {
4685
4739
  subscription_s *s = FIO_LS_EMBD_OBJ(subscription_s, node, pos);
4686
4740
  if (!s) {
@@ -4694,12 +4748,18 @@ static void fio_publish2channel(channel_s *ch, fio_msg_internal_s *msg) {
4694
4748
  }
4695
4749
  static void fio_publish2channel_task(void *ch_, void *msg) {
4696
4750
  channel_s *ch = ch_;
4751
+ if (!ch_)
4752
+ return;
4753
+ if (!msg)
4754
+ goto finish;
4697
4755
  if (fio_trylock(&ch->lock)) {
4698
4756
  fio_defer(fio_publish2channel_task, ch, msg);
4699
4757
  return;
4700
4758
  }
4701
4759
  fio_publish2channel(ch, msg);
4702
4760
  fio_unlock(&ch->lock);
4761
+ finish:
4762
+ fio_str_free(&ch->id);
4703
4763
  }
4704
4764
 
4705
4765
  /** Publishes the message to the current process and frees the strings. */
@@ -4718,7 +4778,8 @@ static void fio_publish2process(fio_msg_internal_s *m) {
4718
4778
  }
4719
4779
  /* exact match */
4720
4780
  if (ch) {
4721
- fio_defer(fio_publish2channel_task, ch, fio_msg_internal_dup(m));
4781
+ fio_defer(fio_publish2channel_task, fio_str_dup(&ch->id),
4782
+ fio_msg_internal_dup(m));
4722
4783
  }
4723
4784
  if (m->filter == 0) {
4724
4785
  /* pattern matching match */
@@ -4729,7 +4790,7 @@ static void fio_publish2process(fio_msg_internal_s *m) {
4729
4790
  }
4730
4791
  pattern_s *pattern = (pattern_s *)p->obj;
4731
4792
  if (pattern->match(fio_str_info(&pattern->ch.id), m->channel)) {
4732
- fio_defer(fio_publish2channel_task, &pattern->ch,
4793
+ fio_defer(fio_publish2channel_task, fio_str_dup(&pattern->ch.id),
4733
4794
  fio_msg_internal_dup(m));
4734
4795
  }
4735
4796
  }
@@ -4750,6 +4811,7 @@ static void fio_publish2process(fio_msg_internal_s *m) {
4750
4811
  #define FIO_SET_KEY_COPY(k1, k2) \
4751
4812
  (k1) = FIO_STR_INIT; \
4752
4813
  fio_str_concat(&(k1), &(k2))
4814
+ #define FIO_SET_KEY_COMPARE(k1, k2) fio_str_iseq(&(k1), &(k2))
4753
4815
  #define FIO_SET_KEY_DESTROY(key) fio_str_free(&(key))
4754
4816
  #define FIO_SET_OBJ_DESTROY(obj) fio_unsubscribe(obj)
4755
4817
  #include <fio.h>
@@ -4771,7 +4833,7 @@ typedef struct cluster_pr_s {
4771
4833
  uint8_t buffer[CLUSTER_READ_BUFFER];
4772
4834
  } cluster_pr_s;
4773
4835
 
4774
- struct cluster_data_s {
4836
+ static struct cluster_data_s {
4775
4837
  intptr_t uuid;
4776
4838
  fio_ls_s clients;
4777
4839
  fio_lock_i lock;
@@ -4782,7 +4844,7 @@ struct cluster_data_s {
4782
4844
  static void fio_cluster_data_cleanup(int delete_file) {
4783
4845
  if (delete_file && cluster_data.name[0]) {
4784
4846
  #if DEBUG
4785
- FIO_LOG_STATE("* INFO: (%d) unlinking cluster's Unix socket.\n", getpid());
4847
+ FIO_LOG_DEBUG("(%d) unlinking cluster's Unix socket.", getpid());
4786
4848
  #endif
4787
4849
  unlink(cluster_data.name);
4788
4850
  }
@@ -4896,20 +4958,16 @@ static void fio_cluster_on_data(intptr_t uuid, fio_protocol_s *pr_) {
4896
4958
  c->filter = (int32_t)fio_str2u32(c->buffer + i + 12);
4897
4959
  if (c->exp_channel) {
4898
4960
  if (c->exp_channel >= (1024 * 1024 * 16)) {
4899
- fprintf(stderr,
4900
- "FATAL ERROR: (%d) cluster message name too long (16Mb "
4901
- "limit): %u\n",
4902
- getpid(), (unsigned int)c->exp_channel);
4961
+ FIO_LOG_FATAL("(%d) cluster message name too long (16Mb limit): %u\n",
4962
+ getpid(), (unsigned int)c->exp_channel);
4903
4963
  exit(1);
4904
4964
  return;
4905
4965
  }
4906
4966
  }
4907
4967
  if (c->exp_msg) {
4908
4968
  if (c->exp_msg >= (1024 * 1024 * 64)) {
4909
- fprintf(stderr,
4910
- "FATAL ERROR: (%d) cluster message data too long (64Mb "
4911
- "limit): %u\n",
4912
- getpid(), (unsigned int)c->exp_msg);
4969
+ FIO_LOG_FATAL("(%d) cluster message data too long (64Mb limit): %u\n",
4970
+ getpid(), (unsigned int)c->exp_msg);
4913
4971
  exit(1);
4914
4972
  return;
4915
4973
  }
@@ -4988,8 +5046,7 @@ static void fio_cluster_on_close(intptr_t uuid, fio_protocol_s *pr_) {
4988
5046
  } else if (fio_data->active) {
4989
5047
  /* no shutdown message received - parent crashed. */
4990
5048
  if (c->type != FIO_CLUSTER_MSG_SHUTDOWN && fio_is_running()) {
4991
- FIO_LOG_STATE("* FATAL ERROR: (%d) Parent Process crash detected!\n",
4992
- getpid());
5049
+ FIO_LOG_FATAL("(%d) Parent Process crash detected!", getpid());
4993
5050
  fio_state_callback_force(FIO_CALL_ON_PARENT_CRUSH);
4994
5051
  fio_state_callback_clear(FIO_CALL_ON_PARENT_CRUSH);
4995
5052
  fio_cluster_data_cleanup(1);
@@ -5009,7 +5066,7 @@ fio_cluster_protocol_alloc(intptr_t uuid,
5009
5066
  void (*sender)(fio_str_s *data, intptr_t auuid)) {
5010
5067
  cluster_pr_s *p = fio_mmap(sizeof(*p));
5011
5068
  if (!p) {
5012
- FIO_LOG_STATE("FATAL ERROR: Cluster protocol allocation failed");
5069
+ FIO_LOG_FATAL("Cluster protocol allocation failed.");
5013
5070
  exit(errno);
5014
5071
  }
5015
5072
  p->protocol = (fio_protocol_s){
@@ -5142,8 +5199,7 @@ static void fio_cluster_listen_on_close(intptr_t uuid,
5142
5199
  cluster_data.uuid = -1;
5143
5200
  if (fio_parent_pid() == getpid()) {
5144
5201
  #if DEBUG
5145
- FIO_LOG_STATE("* INFO: (%d) stopped listening for cluster connections\n",
5146
- getpid());
5202
+ FIO_LOG_DEBUG("(%d) stopped listening for cluster connections", getpid());
5147
5203
  #endif
5148
5204
  if (fio_data->active)
5149
5205
  kill(0, SIGINT);
@@ -5158,8 +5214,8 @@ static void fio_listen2cluster(void *ignore) {
5158
5214
  cluster_data.uuid = fio_socket(cluster_data.name, NULL, 1);
5159
5215
  fio_unlock(&cluster_data.lock);
5160
5216
  if (cluster_data.uuid < 0) {
5161
- perror("FATAL ERROR: (facil.io cluster) failed to open cluster socket.\n"
5162
- " check file permissions");
5217
+ FIO_LOG_FATAL("(facil.io cluster) failed to open cluster socket.");
5218
+ perror(" check file permissions. errno:");
5163
5219
  exit(errno);
5164
5220
  }
5165
5221
  fio_protocol_s *p = malloc(sizeof(*p));
@@ -5171,8 +5227,7 @@ static void fio_listen2cluster(void *ignore) {
5171
5227
  .on_close = fio_cluster_listen_on_close,
5172
5228
  };
5173
5229
  #if DEBUG
5174
- FIO_LOG_STATE("* INFO: (%d) Listening to cluster: %s\n", getpid(),
5175
- cluster_data.name);
5230
+ FIO_LOG_DEBUG("(%d) Listening to cluster: %s", getpid(), cluster_data.name);
5176
5231
  #endif
5177
5232
  fio_attach(cluster_data.uuid, p);
5178
5233
  (void)ignore;
@@ -5226,7 +5281,7 @@ static void fio_cluster_client_sender(fio_str_s *data, intptr_t ignr_) {
5226
5281
  *
5227
5282
  * Should either call `facil_attach` or close the connection.
5228
5283
  */
5229
- void fio_cluster_on_connect(intptr_t uuid, void *udata) {
5284
+ static void fio_cluster_on_connect(intptr_t uuid, void *udata) {
5230
5285
  cluster_data.uuid = uuid;
5231
5286
 
5232
5287
  /* inform root about all existing channels */
@@ -5256,8 +5311,9 @@ void fio_cluster_on_connect(intptr_t uuid, void *udata) {
5256
5311
  * The `on_fail` is called when a socket fails to connect. The old sock UUID
5257
5312
  * is passed along.
5258
5313
  */
5259
- void fio_cluster_on_fail(intptr_t uuid, void *udata) {
5260
- perror("FATAL ERROR: (facil.io) unknown cluster connection error");
5314
+ static void fio_cluster_on_fail(intptr_t uuid, void *udata) {
5315
+ FIO_LOG_FATAL("(facil.io) unknown cluster connection error");
5316
+ perror(" errno");
5261
5317
  kill(fio_parent_pid(), SIGINT);
5262
5318
  fio_stop();
5263
5319
  // exit(errno ? errno : 1);
@@ -5276,7 +5332,7 @@ static void fio_connect2cluster(void *ignore) {
5276
5332
  static void fio_send2cluster(int32_t filter, fio_str_info_s ch,
5277
5333
  fio_str_info_s msg, uint8_t is_json) {
5278
5334
  if (!fio_is_running()) {
5279
- FIO_LOG_STATE("ERROR: cluster inactive, can't send message.\n");
5335
+ FIO_LOG_ERROR("facio.io cluster inactive, can't send message.");
5280
5336
  return;
5281
5337
  }
5282
5338
  if (fio_data->workers == 1) {
@@ -5313,7 +5369,7 @@ static inline void fio_cluster_inform_root_about_channel(channel_s *ch,
5313
5369
  fio_str_info_s ch_name = fio_str_info(&ch->id);
5314
5370
  fio_str_info_s msg = {.data = NULL, .len = 0};
5315
5371
  #if DEBUG
5316
- FIO_LOG_STATE("* (%d) informing root about: %s (%zu) msg type %d\n", getpid(),
5372
+ FIO_LOG_DEBUG("(%d) informing root about: %s (%zu) msg type %d", getpid(),
5317
5373
  ch_name.data, ch_name.len,
5318
5374
  (match ? (add ? FIO_CLUSTER_MSG_PATTERN_SUB
5319
5375
  : FIO_CLUSTER_MSG_PATTERN_UNSUB)
@@ -5494,8 +5550,8 @@ void fio_publish FIO_IGNORE_MACRO(fio_publish_args_s args) {
5494
5550
  break;
5495
5551
  default:
5496
5552
  if (args.filter != 0) {
5497
- fprintf(stderr, "ERROR: (pub/sub) pub/sub engines can only be used for "
5498
- "pub/sub messages (no filter).\n");
5553
+ FIO_LOG_ERROR("(pub/sub) pub/sub engines can only be used for "
5554
+ "pub/sub messages (no filter).");
5499
5555
  return;
5500
5556
  }
5501
5557
  args.engine->publish(args.engine, args.channel, args.message, args.is_json);
@@ -5663,57 +5719,32 @@ Section Start Marker
5663
5719
 
5664
5720
  ***************************************************************************** */
5665
5721
 
5666
- /* *****************************************************************************
5667
- If FIO_FORCE_MALLOC is set, use glibc / library malloc
5668
- ***************************************************************************** */
5669
5722
  #if FIO_FORCE_MALLOC
5670
-
5671
- void *fio_malloc(size_t size) { return malloc(size); }
5672
-
5673
- void *fio_calloc(size_t size, size_t count) { return calloc(size, count); }
5674
-
5675
- void fio_free(void *ptr) { free(ptr); }
5676
-
5677
- void *fio_realloc(void *ptr, size_t new_size) { return realloc(ptr, new_size); }
5678
- void *fio_realloc2(void *ptr, size_t new_size, size_t valid_len) {
5679
- return realloc(ptr, new_size);
5680
- (void)valid_len;
5681
- }
5682
- /** Clears any memory locks, in case of a system call to `fork`. */
5683
- static void fio_malloc_after_fork(void) {}
5723
+ void fio_mem_destroy(void) {}
5724
+ void fio_mem_init(void) {}
5684
5725
 
5685
5726
  #else
5686
- /* *****************************************************************************
5687
- facil.io malloc implementation
5688
- ***************************************************************************** */
5689
-
5690
- #if !defined(__clang__) && !defined(__GNUC__)
5691
- #define __thread _Thread_value
5692
- #endif
5693
-
5694
- #undef malloc
5695
- #undef calloc
5696
- #undef free
5697
- #undef realloc
5698
5727
 
5699
5728
  /* *****************************************************************************
5700
5729
  Memory Copying by 16 byte units
5701
5730
  ***************************************************************************** */
5702
5731
 
5732
+ static inline void fio_memcpy(void *__restrict dest_, void *__restrict src_,
5733
+ size_t units) {
5703
5734
  #if __SIZEOF_INT128__ == 9 /* a 128bit type exists... but tests favor 64bit */
5704
- static inline void fio_memcpy(__uint128_t *__restrict dest,
5705
- __uint128_t *__restrict src, size_t units) {
5735
+ register __uint128_t *dest = dest_;
5736
+ register __uint128_t *src = src_;
5706
5737
  #elif SIZE_MAX == 0xFFFFFFFFFFFFFFFF /* 64 bit size_t */
5707
- static inline void fio_memcpy(size_t *__restrict dest, size_t *__restrict src,
5708
- size_t units) {
5738
+ register size_t *dest = dest_;
5739
+ register size_t *src = src_;
5709
5740
  units = units << 1;
5710
5741
  #elif SIZE_MAX == 0xFFFFFFFF /* 32 bit size_t */
5711
- static inline void fio_memcpy(size_t *__restrict dest, size_t *__restrict src,
5712
- size_t units) {
5742
+ register size_t *dest = dest_;
5743
+ register size_t *src = src_;
5713
5744
  units = units << 2;
5714
5745
  #else /* unknow... assume 16 bit? */
5715
- static inline void fio_memcpy(uint16_t *__restrict dest,
5716
- uint16_t *__restrict src, size_t units) {
5746
+ register size_t *dest = dest_;
5747
+ register size_t *src = src_;
5717
5748
  units = units << 3;
5718
5749
  #endif
5719
5750
  while (units >= 16) { /* unroll loop */
@@ -5926,7 +5957,7 @@ static void arena_enter(void) { arena_last_used = arena_lock(arena_last_used); }
5926
5957
  static inline void arena_exit(void) { fio_unlock(&arena_last_used->lock); }
5927
5958
 
5928
5959
  /** Clears any memory locks, in case of a system call to `fork`. */
5929
- static void fio_malloc_after_fork(void) {
5960
+ void fio_malloc_after_fork(void) {
5930
5961
  arena_last_used = NULL;
5931
5962
  if (!arenas) {
5932
5963
  return;
@@ -5972,7 +6003,7 @@ static inline void block_free(block_s *blk) {
5972
6003
  }
5973
6004
  memset(blk, 0, FIO_MEMORY_BLOCK_SIZE);
5974
6005
  fio_lock(&memory.lock);
5975
- *(block_s **)blk = memory.available;
6006
+ ((block_s **)blk)[0] = memory.available;
5976
6007
  memory.available = (block_s *)blk;
5977
6008
  fio_unlock(&memory.lock);
5978
6009
  }
@@ -5983,13 +6014,15 @@ static inline block_s *block_new(void) {
5983
6014
 
5984
6015
  if (memory.available) {
5985
6016
  fio_lock(&memory.lock);
5986
- blk = (block_s *)memory.available;
6017
+ blk = memory.available;
5987
6018
  if (blk) {
5988
6019
  memory.available = ((block_s **)blk)[0];
5989
6020
  }
5990
6021
  fio_unlock(&memory.lock);
5991
6022
  }
5992
6023
  if (blk) {
6024
+ FIO_ASSERT(((uintptr_t)blk & FIO_MEMORY_BLOCK_MASK) == 0,
6025
+ "Memory allocator error! double `fio_free`?\n");
5993
6026
  fio_atomic_sub(&memory.count, 1);
5994
6027
  ((block_s **)blk)[0] = NULL;
5995
6028
  ((block_s **)blk)[1] = NULL;
@@ -6003,6 +6036,7 @@ static inline block_s *block_new(void) {
6003
6036
  ;
6004
6037
  }
6005
6038
 
6039
+ /* allocates memory from within a block - called within an arena's lock */
6006
6040
  static inline void *block_slice(uint16_t units) {
6007
6041
  block_s *blk = arena_last_used->block;
6008
6042
  if (!blk) {
@@ -6025,7 +6059,6 @@ static inline void *block_slice(uint16_t units) {
6025
6059
  fio_atomic_add(&blk->ref, 1);
6026
6060
  blk->pos += units;
6027
6061
  if (blk->pos >= blk->max) {
6028
- /* it's true that a 16 bytes slice remains, but statistically... */
6029
6062
  /* ... the block was fully utilized, clear arena */
6030
6063
  block_free(blk);
6031
6064
  arena_last_used->block = NULL;
@@ -6033,6 +6066,7 @@ static inline void *block_slice(uint16_t units) {
6033
6066
  return (void *)mem;
6034
6067
  }
6035
6068
 
6069
+ /* handle's a bock's reference count - called without a lock */
6036
6070
  static inline void block_slice_free(void *mem) {
6037
6071
  /* locate block boundary */
6038
6072
  block_s *blk = (block_s *)((uintptr_t)mem & (~FIO_MEMORY_BLOCK_MASK));
@@ -6043,6 +6077,7 @@ static inline void block_slice_free(void *mem) {
6043
6077
  Non-Block allocations (direct from the system)
6044
6078
  ***************************************************************************** */
6045
6079
 
6080
+ /* allocates directly from the system adding size header - no lock required. */
6046
6081
  static inline void *big_alloc(size_t size) {
6047
6082
  size = sys_round_size(size + 16);
6048
6083
  size_t *mem = sys_alloc(size, 1);
@@ -6054,11 +6089,13 @@ error:
6054
6089
  return NULL;
6055
6090
  }
6056
6091
 
6092
+ /* reads size header and frees memory back to the system */
6057
6093
  static inline void big_free(void *ptr) {
6058
6094
  size_t *mem = (void *)(((uintptr_t)ptr) - 16);
6059
6095
  sys_free(mem, *mem);
6060
6096
  }
6061
6097
 
6098
+ /* reallocates memory using the system, resetting the size header */
6062
6099
  static inline void *big_realloc(void *ptr, size_t new_size) {
6063
6100
  size_t *mem = (void *)(((uintptr_t)ptr) - 16);
6064
6101
  new_size = sys_round_size(new_size + 16);
@@ -6088,10 +6125,7 @@ static void fio_mem_init(void) {
6088
6125
  memory.cores = cpu_count;
6089
6126
  memory.count = 0 - (intptr_t)cpu_count;
6090
6127
  arenas = big_alloc(sizeof(*arenas) * cpu_count);
6091
- if (!arenas) {
6092
- perror("FATAL ERROR: Couldn't initialize memory allocator");
6093
- exit(errno);
6094
- }
6128
+ FIO_ASSERT_ALLOC(arenas);
6095
6129
  size_t pre_pool = cpu_count > 32 ? 32 : cpu_count;
6096
6130
  for (size_t i = 0; i < pre_pool; ++i) {
6097
6131
  void *block = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
@@ -6107,16 +6141,14 @@ static void fio_mem_destroy(void) {
6107
6141
  if (!arenas)
6108
6142
  return;
6109
6143
 
6110
- arena_s *arena = arenas;
6111
6144
  for (size_t i = 0; i < memory.cores; ++i) {
6112
- if (arena->block)
6113
- block_free(arena->block);
6114
- arena->block = NULL;
6115
- ++arena;
6145
+ if (arenas[i].block)
6146
+ block_free(arenas[i].block);
6147
+ arenas[i].block = NULL;
6116
6148
  }
6117
6149
  while (memory.available) {
6118
6150
  block_s *b = memory.available;
6119
- memory.available = *(block_s **)b;
6151
+ memory.available = ((block_s **)b)[0];
6120
6152
  sys_free(b, FIO_MEMORY_BLOCK_SIZE);
6121
6153
  }
6122
6154
  big_free(arenas);
@@ -6980,7 +7012,7 @@ fio_sha2_s fio_sha2_init(fio_sha2_variant_e variant) {
6980
7012
  .digest.i64[7] = 0x0eb72ddc81c52ca2,
6981
7013
  };
6982
7014
  }
6983
- fprintf(stderr, "FATAL ERROR: SHA-2 ERROR - variant unknown\n");
7015
+ FIO_LOG_FATAL("SHA-2 ERROR - variant unknown");
6984
7016
  exit(2);
6985
7017
  }
6986
7018
 
@@ -7609,6 +7641,15 @@ Testing Strings
7609
7641
  #define fio_str_test()
7610
7642
  #else
7611
7643
 
7644
+ static int fio_str_test_dealloc_counter = 0;
7645
+
7646
+ FIO_FUNC void fio_str_test_dealloc(void *s) {
7647
+ FIO_ASSERT(!fio_str_test_dealloc_counter,
7648
+ "fio_str_s reference count error!\n");
7649
+ fio_free(s);
7650
+ fprintf(stderr, "* reference counting `fio_str_free2` pass.\n");
7651
+ }
7652
+
7612
7653
  /**
7613
7654
  * Tests the fio_str functionality.
7614
7655
  */
@@ -7764,12 +7805,16 @@ FIO_FUNC inline void fio_str_test(void) {
7764
7805
  "`fio_str_new2` error, string not initialized (%p)!", (void *)s);
7765
7806
  fio_str_s *s2 = fio_str_dup(s);
7766
7807
 
7808
+ ++fio_str_test_dealloc_counter;
7809
+
7767
7810
  FIO_ASSERT(s2 == s, "`fio_str_dup` error, should return self!");
7768
7811
  FIO_ASSERT(s->ref == 1,
7769
7812
  "`fio_str_dup` error, reference counter not incremented!");
7770
7813
 
7771
7814
  fprintf(stderr, "* reading a file.\n");
7772
7815
  fio_str_info_s state = fio_str_readfile(s, __FILE__, 0, 0);
7816
+ if (!s->small) /* attach deallocation test */
7817
+ s->dealloc = fio_str_test_dealloc;
7773
7818
 
7774
7819
  FIO_ASSERT(state.data,
7775
7820
  "`fio_str_readfile` error, no data was read for file %s!",
@@ -7793,6 +7838,7 @@ FIO_FUNC inline void fio_str_test(void) {
7793
7838
 
7794
7839
  fprintf(stderr, "* reviewing reference counting `fio_str_free2` (1/2).\n");
7795
7840
  fio_str_free2(s2);
7841
+ --fio_str_test_dealloc_counter;
7796
7842
  FIO_ASSERT(s->ref == 0,
7797
7843
  "`fio_str_free2` error, reference counter not subtracted!");
7798
7844
  FIO_ASSERT(s->small == 0, "`fio_str_free2` error, strring reinitialized!");
@@ -7885,11 +7931,11 @@ FIO_FUNC inline void fio_str_test(void) {
7885
7931
  "Static string length should be automatically calculated.");
7886
7932
  FIO_ASSERT(str.dealloc == NULL,
7887
7933
  "Static string deallocation function should be NULL.");
7888
- fio_free(&str);
7934
+ fio_str_free(&str);
7889
7935
  str = FIO_STR_INIT_STATIC("Welcome");
7890
7936
  fio_str_info_s state = fio_str_write(&str, " Home", 5);
7891
7937
  FIO_ASSERT(state.capa > 0, "Static string not converted to non-static.");
7892
- fio_free(&str);
7938
+ fio_str_free(&str);
7893
7939
  }
7894
7940
  fprintf(stderr, "* passed.\n");
7895
7941
  }
@@ -7899,6 +7945,9 @@ FIO_FUNC inline void fio_str_test(void) {
7899
7945
  Testing Memory Allocator
7900
7946
  ***************************************************************************** */
7901
7947
 
7948
+ #if FIO_FORCE_MALLOC
7949
+ #define fio_malloc_test()
7950
+ #else
7902
7951
  void fio_malloc_test(void) {
7903
7952
  fprintf(stderr, "=== Testing facil.io memory allocator's system calls\n");
7904
7953
  char *mem = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
@@ -7929,8 +7978,18 @@ void fio_malloc_test(void) {
7929
7978
  FIO_ASSERT(mem[0] == 'a', "fio_realloc memory wasn't copied!\n");
7930
7979
  FIO_ASSERT(arena_last_used, "arena_last_used wasn't initialized!\n");
7931
7980
  block_s *b = arena_last_used->block;
7932
- size_t count = 2;
7933
- intptr_t old_memory_pool_count = memory.count;
7981
+
7982
+ /* move arena to block's start */
7983
+ while (arena_last_used->block == b) {
7984
+ mem = fio_malloc(1);
7985
+ FIO_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
7986
+ fio_free(mem);
7987
+ }
7988
+ /* make sure a block is assigned */
7989
+ fio_free(fio_malloc(1));
7990
+ b = arena_last_used->block;
7991
+ size_t count = 1;
7992
+ /* count allocations within block */
7934
7993
  do {
7935
7994
  FIO_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
7936
7995
  FIO_ASSERT(!((uintptr_t)mem & 15),
@@ -7947,18 +8006,21 @@ void fio_malloc_test(void) {
7947
8006
  ++count;
7948
8007
  } while (arena_last_used->block == b);
7949
8008
  {
8009
+ fprintf(stderr, "* Confirm block address: %p, last allocation was %p\n",
8010
+ (void *)arena_last_used->block, (void *)mem);
7950
8011
  fprintf(
7951
8012
  stderr,
7952
8013
  "* Performed %zu allocations out of expected %zu allocations per "
7953
8014
  "block.\n",
7954
8015
  count,
7955
8016
  (size_t)((FIO_MEMORY_BLOCK_SLICES - 2) - (sizeof(block_s) >> 4) - 1));
8017
+ intptr_t old_memory_pool_count = memory.count;
8018
+ fio_free(mem);
7956
8019
  FIO_ASSERT(memory.available,
7957
8020
  "memory pool empty (memory block wasn't freed)!\n");
7958
- FIO_ASSERT(old_memory_pool_count == memory.count,
7959
- "memory.count == %ld (memory block not counted)!\n",
7960
- (long)old_memory_pool_count);
7961
- fio_free(mem);
8021
+ FIO_ASSERT(old_memory_pool_count + 1 == memory.count,
8022
+ "memory.count == %ld , was %ld (memory block counting error)!\n",
8023
+ (long)memory.count, (long)old_memory_pool_count);
7962
8024
  }
7963
8025
  /* rotate block again */
7964
8026
  b = arena_last_used->block;
@@ -8019,6 +8081,7 @@ void fio_malloc_test(void) {
8019
8081
 
8020
8082
  fprintf(stderr, "* passed.\n");
8021
8083
  }
8084
+ #endif
8022
8085
 
8023
8086
  /* *****************************************************************************
8024
8087
  Testing Core Callback add / remove / ensure
@@ -8346,114 +8409,159 @@ Set data-structure Testing
8346
8409
 
8347
8410
  #define FIO_SET_TEXT_COUNT 524288UL
8348
8411
 
8349
- #define FIO_SET_NAME fio_hashmap_test
8412
+ #define FIO_SET_NAME fio_set_test
8350
8413
  #define FIO_SET_OBJ_TYPE uintptr_t
8414
+ #include <fio.h>
8351
8415
 
8416
+ #define FIO_SET_NAME fio_hash_test
8417
+ #define FIO_SET_KEY_TYPE uintptr_t
8418
+ #define FIO_SET_OBJ_TYPE uintptr_t
8352
8419
  #include <fio.h>
8353
- #define FIO_SET_NAME(s) fio_hashmap_test_##s
8354
8420
 
8355
8421
  FIO_FUNC void fio_set_test(void) {
8356
- FIO_SET_NAME(s) s = FIO_SET_INIT;
8422
+ fio_set_test_s s = FIO_SET_INIT;
8423
+ fio_hash_test_s h = FIO_SET_INIT;
8357
8424
  fprintf(
8358
8425
  stderr,
8359
8426
  "=== Testing Core ordered Set (re-including fio.h with FIO_SET_NAME)\n");
8360
8427
  fprintf(stderr, "* Inserting %lu items\n", FIO_SET_TEXT_COUNT);
8361
- union {
8362
- uintptr_t obj;
8363
- uintptr_t i;
8364
- } obj_mem;
8365
- memset(&obj_mem, 0, sizeof(obj_mem));
8366
-
8367
- FIO_ASSERT(FIO_SET_NAME(count)(&s) == 0,
8368
- "empty set should have zero objects");
8369
- FIO_ASSERT(FIO_SET_NAME(capa)(&s) == 0, "empty set should have no capacity");
8370
- FIO_ASSERT(!FIO_SET_NAME(is_fragmented)(&s),
8428
+
8429
+ FIO_ASSERT(fio_set_test_count(&s) == 0, "empty set should have zero objects");
8430
+ FIO_ASSERT(fio_set_test_capa(&s) == 0, "empty set should have no capacity");
8431
+ FIO_ASSERT(fio_hash_test_capa(&h) == 0, "empty hash should have no capacity");
8432
+ FIO_ASSERT(!fio_set_test_is_fragmented(&s),
8371
8433
  "empty set shouldn't be considered fragmented");
8372
- FIO_ASSERT(!FIO_SET_NAME(last)(&s), "empty set shouldn't have a last object");
8434
+ FIO_ASSERT(!fio_hash_test_is_fragmented(&h),
8435
+ "empty hash shouldn't be considered fragmented");
8436
+ FIO_ASSERT(!fio_set_test_last(&s), "empty set shouldn't have a last object");
8437
+ FIO_ASSERT(!fio_hash_test_last(&h),
8438
+ "empty hash shouldn't have a last object");
8373
8439
 
8374
8440
  for (uintptr_t i = 1; i < FIO_SET_TEXT_COUNT; ++i) {
8375
- obj_mem.i = i;
8376
- FIO_SET_NAME(insert)(&s, i, obj_mem.obj);
8377
- FIO_ASSERT(FIO_SET_NAME(find)(&s, i, obj_mem.obj),
8378
- "find failed after insert");
8379
- obj_mem.obj = *FIO_SET_NAME(find)(&s, i, obj_mem.obj);
8380
- FIO_ASSERT(i == obj_mem.i, "insertion != find");
8441
+ fio_set_test_insert(&s, i, i);
8442
+ fio_hash_test_insert(&h, i, i, i + 1);
8443
+ FIO_ASSERT(fio_set_test_find(&s, i, i), "set find failed after insert");
8444
+ FIO_ASSERT(fio_hash_test_find(&h, i, i), "hash find failed after insert");
8445
+ FIO_ASSERT(i == *fio_set_test_find(&s, i, i), "set insertion != find");
8446
+ FIO_ASSERT(i + 1 == *fio_hash_test_find(&h, i, i),
8447
+ "hash insertion != find");
8381
8448
  }
8382
8449
  fprintf(stderr, "* Seeking %lu items\n", FIO_SET_TEXT_COUNT);
8383
8450
  for (unsigned long i = 1; i < FIO_SET_TEXT_COUNT; ++i) {
8384
- obj_mem.i = i;
8385
- obj_mem.obj = *FIO_SET_NAME(find)(&s, i, obj_mem.obj);
8386
- FIO_ASSERT((i == obj_mem.i), "insertion != find (seek)");
8451
+ FIO_ASSERT((i == *fio_set_test_find(&s, i, i)),
8452
+ "set insertion != find (seek)");
8453
+ FIO_ASSERT((i + 1 == *fio_hash_test_find(&h, i, i)),
8454
+ "hash insertion != find (seek)");
8387
8455
  }
8388
8456
  {
8389
- fprintf(stderr, "* Testing order for %lu items\n", FIO_SET_TEXT_COUNT);
8457
+ fprintf(stderr, "* Testing order for %lu items in set\n",
8458
+ FIO_SET_TEXT_COUNT);
8390
8459
  uintptr_t i = 1;
8391
8460
  FIO_SET_FOR_LOOP(&s, pos) {
8392
- obj_mem.obj = pos->obj;
8393
- FIO_ASSERT(obj_mem.i == i, "object order mismatch %lu != %lu.",
8394
- (unsigned long)i, (unsigned long)obj_mem.i);
8461
+ FIO_ASSERT(pos->obj == i, "object order mismatch %lu != %lu.",
8462
+ (unsigned long)i, (unsigned long)pos->obj);
8463
+ ++i;
8464
+ }
8465
+ }
8466
+ {
8467
+ fprintf(stderr, "* Testing order for %lu items in hash\n",
8468
+ FIO_SET_TEXT_COUNT);
8469
+ uintptr_t i = 1;
8470
+ FIO_SET_FOR_LOOP(&h, pos) {
8471
+ FIO_ASSERT(pos->obj.obj == i + 1 && pos->obj.key == i,
8472
+ "object order mismatch %lu != %lu.", (unsigned long)i,
8473
+ (unsigned long)pos->obj.key);
8395
8474
  ++i;
8396
8475
  }
8397
8476
  }
8398
8477
 
8399
8478
  fprintf(stderr, "* Removing odd items from %lu items\n", FIO_SET_TEXT_COUNT);
8400
8479
  for (unsigned long i = 1; i < FIO_SET_TEXT_COUNT; i += 2) {
8401
- obj_mem.i = i;
8402
- FIO_SET_NAME(remove)(&s, i, obj_mem.obj);
8403
- FIO_ASSERT(!(FIO_SET_NAME(find)(&s, i, obj_mem.obj)),
8404
- "Removal failed (still exists).");
8480
+ fio_set_test_remove(&s, i, i);
8481
+ fio_hash_test_remove(&h, i, i);
8482
+ FIO_ASSERT(!(fio_set_test_find(&s, i, i)),
8483
+ "Removal failed in set (still exists).");
8484
+ FIO_ASSERT(!(fio_hash_test_find(&h, i, i)),
8485
+ "Removal failed in hash (still exists).");
8405
8486
  }
8406
8487
  {
8407
8488
  fprintf(stderr, "* Testing for %lu / 2 holes\n", FIO_SET_TEXT_COUNT);
8408
8489
  uintptr_t i = 1;
8409
8490
  FIO_SET_FOR_LOOP(&s, pos) {
8410
- obj_mem.obj = pos->obj;
8411
8491
  if (pos->hash == 0) {
8412
8492
  FIO_ASSERT((i & 1) == 1, "deleted object wasn't odd");
8413
8493
  } else {
8414
- FIO_ASSERT(obj_mem.i == i, "deleted object value mismatch %lu != %lu",
8415
- (unsigned long)i, (unsigned long)obj_mem.i);
8494
+ FIO_ASSERT(pos->obj == i, "deleted object value mismatch %lu != %lu",
8495
+ (unsigned long)i, (unsigned long)pos->obj);
8496
+ }
8497
+ ++i;
8498
+ }
8499
+ i = 1;
8500
+ FIO_SET_FOR_LOOP(&h, pos) {
8501
+ if (pos->hash == 0) {
8502
+ FIO_ASSERT((i & 1) == 1, "deleted object wasn't odd");
8503
+ } else {
8504
+ FIO_ASSERT(pos->obj.key == i,
8505
+ "deleted object value mismatch %lu != %lu", (unsigned long)i,
8506
+ (unsigned long)pos->obj.key);
8416
8507
  }
8417
8508
  ++i;
8418
8509
  }
8419
8510
  {
8420
8511
  fprintf(stderr, "* Poping two elements (testing pop through holes)\n");
8421
- FIO_ASSERT(FIO_SET_NAME(last)(&s),
8422
- "Pop `last` 1 failed - no last object");
8423
- obj_mem.obj = *FIO_SET_NAME(last)(&s);
8424
- uintptr_t tmp_i = obj_mem.i;
8425
- FIO_ASSERT(obj_mem.obj, "Pop `last` 1 failed to collect object");
8426
- FIO_SET_NAME(pop)(&s);
8427
- FIO_ASSERT(FIO_SET_NAME(last)(&s),
8428
- "Pop `last` 2 failed - no last object");
8429
- obj_mem.obj = *FIO_SET_NAME(last)(&s);
8430
- FIO_ASSERT(obj_mem.i != tmp_i,
8431
- "Pop `last` 2 same as `last` 1 - failed to collect object");
8432
- FIO_SET_NAME(pop)(&s);
8512
+ FIO_ASSERT(fio_set_test_last(&s), "Pop `last` 1 failed - no last object");
8513
+ uintptr_t tmp = *fio_set_test_last(&s);
8514
+ FIO_ASSERT(tmp, "Pop set `last` 1 failed to collect object");
8515
+ fio_set_test_pop(&s);
8516
+ FIO_ASSERT(
8517
+ *fio_set_test_last(&s) != tmp,
8518
+ "Pop `last` 2 in set same as `last` 1 - failed to collect object");
8519
+ tmp = fio_hash_test_last(&h)->key;
8520
+ FIO_ASSERT(tmp, "Pop hash `last` 1 failed to collect object");
8521
+ fio_hash_test_pop(&h);
8522
+ FIO_ASSERT(
8523
+ fio_hash_test_last(&h)->key != tmp,
8524
+ "Pop `last` 2 in hash same as `last` 1 - failed to collect object");
8525
+ FIO_ASSERT(fio_set_test_last(&s), "Pop `last` 2 failed - no last object");
8526
+ FIO_ASSERT(fio_hash_test_last(&h),
8527
+ "Pop `last` 2 failed in hash - no last object");
8528
+ fio_set_test_pop(&s);
8529
+ fio_hash_test_pop(&h);
8433
8530
  }
8434
8531
  if (1) {
8435
- obj_mem.i = 1;
8436
- FIO_SET_NAME(remove)(&s, obj_mem.i, obj_mem.obj);
8532
+ uintptr_t tmp = 1;
8533
+ fio_set_test_remove(&s, tmp, tmp);
8534
+ fio_hash_test_remove(&h, tmp, tmp);
8437
8535
  size_t count = s.count;
8438
- FIO_SET_NAME(overwrite)(&s, obj_mem.i, obj_mem.obj);
8439
- FIO_ASSERT(count + 1 == s.count,
8440
- "Re-adding a removed item should increase count by 1 (%zu + "
8441
- "1 != %zu).",
8442
- count, (size_t)s.count);
8443
- obj_mem.obj = *FIO_SET_NAME(find)(&s, obj_mem.i, obj_mem.obj);
8444
- FIO_ASSERT(obj_mem.i == 1,
8445
- "Re-adding a removed item should update the item (%p != 1)!",
8446
- (void *)FIO_SET_NAME(find)(&s, obj_mem.i, obj_mem.obj));
8447
- FIO_SET_NAME(remove)(&s, obj_mem.i, obj_mem.obj);
8448
- FIO_ASSERT(count == s.count,
8536
+ fio_set_test_overwrite(&s, tmp, tmp);
8537
+ FIO_ASSERT(
8538
+ count + 1 == s.count,
8539
+ "Re-adding a removed item in set should increase count by 1 (%zu + "
8540
+ "1 != %zu).",
8541
+ count, (size_t)s.count);
8542
+ count = h.count;
8543
+ fio_hash_test_insert(&h, tmp, tmp, tmp);
8544
+ FIO_ASSERT(
8545
+ count + 1 == h.count,
8546
+ "Re-adding a removed item in hash should increase count by 1 (%zu + "
8547
+ "1 != %zu).",
8548
+ count, (size_t)s.count);
8549
+ tmp = *fio_set_test_find(&s, tmp, tmp);
8550
+ FIO_ASSERT(tmp == 1,
8551
+ "Re-adding a removed item should update the item in the set "
8552
+ "(%lu != 1)!",
8553
+ (unsigned long)*fio_set_test_find(&s, tmp, tmp));
8554
+ fio_set_test_remove(&s, tmp, tmp);
8555
+ fio_hash_test_remove(&h, tmp, tmp);
8556
+ FIO_ASSERT(count == h.count,
8449
8557
  "Re-removing an item should decrease count (%zu != %zu).",
8450
8558
  count, (size_t)s.count);
8451
- FIO_ASSERT(!FIO_SET_NAME(find)(&s, obj_mem.i, obj_mem.obj),
8559
+ FIO_ASSERT(!fio_set_test_find(&s, tmp, tmp),
8452
8560
  "Re-removing a re-added item should update the item!");
8453
8561
  }
8454
8562
  }
8455
8563
  fprintf(stderr, "* Compacting HashMap to %lu\n", FIO_SET_TEXT_COUNT >> 1);
8456
- FIO_SET_NAME(compact)(&s);
8564
+ fio_set_test_compact(&s);
8457
8565
  {
8458
8566
  fprintf(stderr, "* Testing that %lu items are continuous\n",
8459
8567
  FIO_SET_TEXT_COUNT >> 1);
@@ -8465,11 +8573,12 @@ FIO_FUNC void fio_set_test(void) {
8465
8573
  FIO_ASSERT(i == s.count, "count error (%lu != %lu).", i, s.count);
8466
8574
  }
8467
8575
 
8468
- FIO_SET_NAME(free)(&s);
8576
+ fio_set_test_free(&s);
8577
+ fio_hash_test_free(&h);
8469
8578
  FIO_ASSERT(!s.map && !s.ordered && !s.pos && !s.capa,
8470
8579
  "HashMap not re-initialized after free.");
8471
8580
 
8472
- FIO_SET_NAME(capa_require)(&s, FIO_SET_TEXT_COUNT);
8581
+ fio_set_test_capa_require(&s, FIO_SET_TEXT_COUNT);
8473
8582
 
8474
8583
  FIO_ASSERT(
8475
8584
  s.map && s.ordered && !s.pos && s.capa >= FIO_SET_TEXT_COUNT,
@@ -8477,16 +8586,15 @@ FIO_FUNC void fio_set_test(void) {
8477
8586
  (void *)s.map, (void *)s.ordered, s.pos, s.capa, FIO_SET_TEXT_COUNT);
8478
8587
 
8479
8588
  for (unsigned long i = 1; i < FIO_SET_TEXT_COUNT; ++i) {
8480
- obj_mem.i = i;
8481
- FIO_SET_NAME(insert)(&s, obj_mem.i, obj_mem.obj);
8482
- FIO_ASSERT(FIO_SET_NAME(find)(&s, obj_mem.i, obj_mem.obj),
8589
+ fio_set_test_insert(&s, i, i);
8590
+ FIO_ASSERT(fio_set_test_find(&s, i, i),
8483
8591
  "find failed after insert (2nd round)");
8484
- obj_mem.obj = *FIO_SET_NAME(find)(&s, obj_mem.i, obj_mem.obj);
8485
- FIO_ASSERT(i == obj_mem.i, "insertion (2nd round) != find");
8592
+ FIO_ASSERT(i == *fio_set_test_find(&s, i, i),
8593
+ "insertion (2nd round) != find");
8486
8594
  FIO_ASSERT(i == s.count, "count error (%lu != %lu) post insertion.", i,
8487
8595
  s.count);
8488
8596
  }
8489
- FIO_SET_NAME(free)(&s);
8597
+ fio_set_test_free(&s);
8490
8598
  }
8491
8599
  #undef FIO_SET_NAME
8492
8600
 
@@ -8561,14 +8669,14 @@ SHA-1 tests
8561
8669
  static void fio_sha1_speed_test(void) {
8562
8670
  /* test based on code from BearSSL with credit to Thomas Pornin */
8563
8671
  uint8_t buffer[8192];
8564
- uint8_t result[65];
8672
+ uint8_t result[21];
8565
8673
  fio_sha1_s sha1;
8566
8674
  memset(buffer, 'T', sizeof(buffer));
8567
8675
  /* warmup */
8568
8676
  for (size_t i = 0; i < 4; i++) {
8569
8677
  sha1 = fio_sha1_init();
8570
8678
  fio_sha1_write(&sha1, buffer, sizeof(buffer));
8571
- memcpy(result, fio_sha1_result(&sha1), 65);
8679
+ memcpy(result, fio_sha1_result(&sha1), 21);
8572
8680
  }
8573
8681
  /* loop until test runs for more than 2 seconds */
8574
8682
  for (size_t cycles = 8192;;) {
@@ -8595,7 +8703,7 @@ static void fio_sha1_speed_test(void) {
8595
8703
  static void fio_sha1_open_ssl_speed_test(void) {
8596
8704
  /* test based on code from BearSSL with credit to Thomas Pornin */
8597
8705
  uint8_t buffer[8192];
8598
- uint8_t result[65];
8706
+ uint8_t result[21];
8599
8707
  SHA_CTX o_sh1;
8600
8708
  memset(buffer, 'T', sizeof(buffer));
8601
8709
  /* warmup */
@@ -8993,8 +9101,7 @@ void fio_base64_test(void) {
8993
9101
  {"foob", "Zm9vYg=="},
8994
9102
  {"fooba", "Zm9vYmE="},
8995
9103
  {"foobar", "Zm9vYmFy"},
8996
- { NULL,
8997
- NULL } // Stop
9104
+ {NULL, NULL} // Stop
8998
9105
  };
8999
9106
  int i = 0;
9000
9107
  char buffer[1024];