iodine 0.7.43 → 0.7.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/iodine/fio.h CHANGED
@@ -215,8 +215,15 @@ Version and helper macros
215
215
 
216
216
  #include <fcntl.h>
217
217
  #include <sys/stat.h>
218
+ #ifndef __MINGW32__
218
219
  #include <sys/time.h>
220
+ #endif
219
221
  #include <unistd.h>
222
+ #ifdef __MINGW32__
223
+ #include <winsock2.h>
224
+ #include <winsock.h>
225
+ #include <ws2tcpip.h>
226
+ #endif
220
227
 
221
228
  #if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
222
229
  #define __attribute__(...)
@@ -243,6 +250,25 @@ Version and helper macros
243
250
  #include <sys/socket.h>
244
251
  #endif
245
252
 
253
+ #ifdef __MINGW32__
254
+ #define __S_IFMT 0170000
255
+ #define __S_IFLNK 0120000
256
+ #define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
257
+ #define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
258
+
259
+ #define SIGKILL 9
260
+ #define SIGTERM 15
261
+ #define SIGCONT 17
262
+
263
+ #define pipe(fds) _pipe(fds, 65536, _O_BINARY)
264
+
265
+ int fork(void);
266
+ int kill(int, int);
267
+ ssize_t pread(int, void*, size_t, off_t);
268
+ ssize_t pwrite(int, const void *, size_t, off_t);
269
+ int fio_osffd4fd(unsigned int);
270
+ #endif
271
+
246
272
  /* *****************************************************************************
247
273
  Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
248
274
  ***************************************************************************** */
@@ -2068,7 +2094,7 @@ FIO_FUNC inline int fio_trylock(fio_lock_i *lock);
2068
2094
  /**
2069
2095
  * Releases a spinlock. Releasing an unacquired lock will break it.
2070
2096
  *
2071
- * Returns a non-zero value on success, or 0 if the lock was in an unloacked
2097
+ * Returns a non-zero value on success, or 0 if the lock was in an unlocked
2072
2098
  * state.
2073
2099
  */
2074
2100
  FIO_FUNC inline int fio_unlock(fio_lock_i *lock);
@@ -2539,8 +2565,9 @@ FIO_FUNC inline uint64_t fio_risky_hash(const void *data_, size_t len,
2539
2565
  uint64_t result = fio_lrot64(v0, 17) + fio_lrot64(v1, 13) +
2540
2566
  fio_lrot64(v2, 47) + fio_lrot64(v3, 57);
2541
2567
 
2542
- len ^= (len << 33);
2543
- result += len;
2568
+ uint64_t len64 = len;
2569
+ len64 ^= (len64 << 33);
2570
+ result += len64;
2544
2571
 
2545
2572
  result += v0 * RISKY_PRIME_1;
2546
2573
  result ^= fio_lrot64(result, 13);
@@ -2931,9 +2958,9 @@ C++ extern end
2931
2958
  /**
2932
2959
  * The logarithmic value for a memory block, 15 == 32Kb, 16 == 64Kb, etc'
2933
2960
  *
2934
- * By default, a block of memory is 32Kb silce from an 8Mb allocation.
2961
+ * By default, a block of memory is a 32Kb slice from an 8Mb allocation.
2935
2962
  *
2936
- * A value of 16 will make this a 64Kb silce from a 16Mb allocation.
2963
+ * A value of 16 will make this a 64Kb slice from a 16Mb allocation.
2937
2964
  */
2938
2965
  #define FIO_MEMORY_BLOCK_SIZE_LOG (15)
2939
2966
  #endif
@@ -3000,7 +3027,7 @@ FIO_FUNC inline int fio_trylock(fio_lock_i *lock) {
3000
3027
  /**
3001
3028
  * Releases a spinlock. Releasing an unacquired lock will break it.
3002
3029
  *
3003
- * Returns a non-zero value on success, or 0 if the lock was in an unloacked
3030
+ * Returns a non-zero value on success, or 0 if the lock was in an unlocked
3004
3031
  * state.
3005
3032
  */
3006
3033
  FIO_FUNC inline int fio_unlock(fio_lock_i *lock) {
@@ -3864,6 +3891,7 @@ FIO_FUNC char *fio_str_detach(fio_str_s *s) {
3864
3891
  }
3865
3892
  /* make a copy */
3866
3893
  void *tmp = FIO_MALLOC(i.len + 1);
3894
+ FIO_ASSERT_ALLOC(tmp);
3867
3895
  memcpy(tmp, i.data, i.len + 1);
3868
3896
  i.data = tmp;
3869
3897
  } else {
@@ -3874,6 +3902,7 @@ FIO_FUNC char *fio_str_detach(fio_str_s *s) {
3874
3902
  } else if (s->dealloc != FIO_FREE) {
3875
3903
  /* make a copy */
3876
3904
  void *tmp = FIO_MALLOC(i.len + 1);
3905
+ FIO_ASSERT_ALLOC(tmp);
3877
3906
  memcpy(tmp, i.data, i.len + 1);
3878
3907
  i.data = tmp;
3879
3908
  if (s->dealloc)
@@ -4338,7 +4367,7 @@ inline FIO_FUNC fio_str_info_s fio_str_write_i(fio_str_s *s, int64_t num) {
4338
4367
  fio_str_info_s i;
4339
4368
  if (!num)
4340
4369
  goto zero;
4341
- char buf[22];
4370
+ char buf[22] = {0};
4342
4371
  uint64_t l = 0;
4343
4372
  uint8_t neg;
4344
4373
  if ((neg = (num < 0))) {
@@ -4472,7 +4501,7 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
4472
4501
  intptr_t start_at, intptr_t limit) {
4473
4502
  fio_str_info_s state = {.data = NULL};
4474
4503
  #if defined(__unix__) || defined(__linux__) || defined(__APPLE__) || \
4475
- defined(__CYGWIN__)
4504
+ defined(__CYGWIN__) || defined(__MINGW32__)
4476
4505
  /* POSIX implementations. */
4477
4506
  if (filename == NULL || !s)
4478
4507
  return state;
@@ -4502,7 +4531,7 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
4502
4531
  }
4503
4532
  }
4504
4533
 
4505
- if (stat(filename, &f_data)) {
4534
+ if (stat(filename, &f_data) == -1) {
4506
4535
  goto finish;
4507
4536
  }
4508
4537
 
@@ -4510,9 +4539,12 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
4510
4539
  state = fio_str_info(s);
4511
4540
  goto finish;
4512
4541
  }
4513
-
4542
+ #ifdef __MINGW32__
4543
+ file = _open(filename, O_RDONLY);
4544
+ #else
4514
4545
  file = open(filename, O_RDONLY);
4515
- if (-1 == file)
4546
+ #endif
4547
+ if (file == -1)
4516
4548
  goto finish;
4517
4549
 
4518
4550
  if (start_at < 0) {
@@ -4531,7 +4563,11 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
4531
4563
  state.data = NULL;
4532
4564
  state.len = state.capa = 0;
4533
4565
  }
4566
+ #ifdef __MINGW32__
4567
+ _close(file);
4568
+ #else
4534
4569
  close(file);
4570
+ #endif
4535
4571
  finish:
4536
4572
  FIO_FREE(path);
4537
4573
  return state;
@@ -6012,7 +6048,7 @@ FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set, FIO_SET_HASH_TYPE hash_value,
6012
6048
  pos->hash = hash_value;
6013
6049
  pos->pos->hash = hash_value;
6014
6050
  FIO_SET_COPY(pos->pos->obj, obj);
6015
-
6051
+
6016
6052
  return pos->pos->obj;
6017
6053
  }
6018
6054
 
@@ -6282,7 +6318,7 @@ restart:
6282
6318
  FIO_LOG_FATAL(
6283
6319
  "facil.io Set / Hash Map has too many collisions (%zu/%zu)."
6284
6320
  "\n\t\tthis is a fatal implementation error,"
6285
- "please report this issue at facio.io's open source project"
6321
+ "please report this issue at facil.io's open source project"
6286
6322
  "\n\t\tNote: hash maps and sets should never reach this point."
6287
6323
  "\n\t\tThey should be guarded against collision attacks.",
6288
6324
  set->pos, set->capa);
data/ext/iodine/fio_cli.c CHANGED
@@ -50,7 +50,7 @@ typedef struct {
50
50
  #define AVOID_MACRO
51
51
 
52
52
  #define FIO_CLI_HASH_VAL(s) \
53
- fio_risky_hash((s).data, (s).len, (uint64_t)fio_cli_start)
53
+ fio_risky_hash((s).data, (s).len, (uintptr_t)fio_cli_start)
54
54
 
55
55
  /* *****************************************************************************
56
56
  CLI Parsing
@@ -4,6 +4,13 @@ License: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
+ #ifdef __MINGW32__
8
+ // make pedantic compiler happy
9
+ typedef struct {
10
+ int bogus;
11
+ } bogus_s;
12
+
13
+ #else
7
14
  #include <fio.h>
8
15
 
9
16
  /**
@@ -639,3 +646,4 @@ void FIO_TLS_WEAK fio_tls_destroy(fio_tls_s *tls) {
639
646
  }
640
647
 
641
648
  #endif /* Library compiler flags */
649
+ #endif
@@ -4,6 +4,13 @@ License: MIT
4
4
 
5
5
  Feel free to copy, use and enjoy according to the license provided.
6
6
  */
7
+ #ifdef __MINGW32__
8
+ // make pedantic compiler happy
9
+ typedef struct {
10
+ int bogus;
11
+ } bogus_s;
12
+
13
+ #else
7
14
  #include <fio.h>
8
15
 
9
16
  /**
@@ -1046,3 +1053,4 @@ void FIO_TLS_WEAK fio_tls_destroy(fio_tls_s *tls) {
1046
1053
  }
1047
1054
 
1048
1055
  #endif /* Library compiler flags */
1056
+ #endif
@@ -18,10 +18,22 @@ License: MIT
18
18
  #include <sys/types.h>
19
19
  #include <unistd.h>
20
20
 
21
+ #ifdef __MINGW32__
22
+ #include <fileapi.h>
23
+ #endif
24
+
21
25
  static inline int fio_tmpfile(void) {
22
26
  // create a temporary file to contain the data.
23
27
  int fd = 0;
24
- #ifdef P_tmpdir
28
+ #ifdef __MINGW32__
29
+ char name_template[] = "fio";
30
+ TCHAR temp_path[(MAX_PATH-14)];
31
+ TCHAR temp_filename[MAX_PATH];
32
+ GetTempPath(MAX_PATH - 14, temp_path);
33
+ GetTempFileNameA(temp_path, name_template, 0, temp_filename);
34
+ fd = _open(temp_filename, _O_CREAT | _O_RDWR);
35
+ _chmod(temp_filename, _S_IREAD | _S_IWRITE);
36
+ #elif defined(P_tmpdir)
25
37
  if (P_tmpdir[sizeof(P_tmpdir) - 1] == '/') {
26
38
  char name_template[] = P_tmpdir "facil_io_tmpfile_XXXXXXXX";
27
39
  fd = mkstemp(name_template);
@@ -1,5 +1,5 @@
1
1
  #if defined(__unix__) || defined(__APPLE__) || defined(__linux__) || \
2
- defined(__CYGWIN__) /* require POSIX */
2
+ defined(__CYGWIN__) || defined(__MINGW32__) /* require POSIX */
3
3
  /*
4
4
  Copyright: Boaz Segev, 2017-2019
5
5
  License: MIT
@@ -78,6 +78,7 @@ static void fiobj_data_copy_parent(FIOBJ o) {
78
78
  switch (obj2io(obj2io(o)->source.parent)->fd) {
79
79
  case -1:
80
80
  obj2io(o)->buffer = fio_malloc(obj2io(o)->len + 1);
81
+ FIO_ASSERT_ALLOC(obj2io(o)->buffer);
81
82
  memcpy(obj2io(o)->buffer,
82
83
  obj2io(obj2io(o)->source.parent)->buffer + obj2io(o)->capa,
83
84
  obj2io(o)->len);
@@ -102,7 +103,11 @@ static void fiobj_data_copy_parent(FIOBJ o) {
102
103
  if (data.len + pos > obj2io(o)->len)
103
104
  data.len = obj2io(o)->len - pos;
104
105
  retry_int:
106
+ #ifdef __MINGW32__
107
+ written = pwrite(obj2io(o)->fd, data.data, data.len, 0);
108
+ #else
105
109
  written = write(obj2io(o)->fd, data.data, data.len);
110
+ #endif
106
111
  if (written < 0) {
107
112
  if (errno == EINTR)
108
113
  goto retry_int;
@@ -958,7 +963,6 @@ intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length) {
958
963
  /* Unslice slices */
959
964
  if (obj2io(io)->fd == -2)
960
965
  fiobj_data_assert_dynamic(io);
961
-
962
966
  if (obj2io(io)->fd == -1) {
963
967
  /* String Code */
964
968
  fiobj_data_pre_write(io, length + 1);
@@ -967,7 +971,6 @@ intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length) {
967
971
  obj2io(io)->buffer[obj2io(io)->len] = 0;
968
972
  return length;
969
973
  }
970
-
971
974
  /* File Code */
972
975
  return pwrite(obj2io(io)->fd, buffer, length, fiobj_data_get_fd_size(io));
973
976
  }
@@ -1046,7 +1049,6 @@ void fiobj_data_test(void) {
1046
1049
  fprintf(stderr, "* `fiobj_data_read` operation overflow - FAILED!\n");
1047
1050
  exit(-1);
1048
1051
  }
1049
-
1050
1052
  if (fiobj_obj2cstr(strio).len != fiobj_obj2cstr(text).len ||
1051
1053
  fiobj_obj2cstr(fdio).len != fiobj_obj2cstr(text).len) {
1052
1054
  fprintf(stderr, "* `write` operation FAILED!\n");
@@ -3,7 +3,8 @@ Copyright: Boaz Segev, 2017-2019
3
3
  License: MIT
4
4
  */
5
5
  #if !defined(H_FIOBJ_IO_H) && (defined(__unix__) || defined(__APPLE__) || \
6
- defined(__linux__) || defined(__CYGWIN__))
6
+ defined(__linux__) || defined(__CYGWIN__) || \
7
+ defined(__MINGW32__))
7
8
 
8
9
  /**
9
10
  * A dynamic type for reading / writing to a local file, a temporary file or an
@@ -36,6 +36,8 @@ License: MIT
36
36
 
37
37
  #include <errno.h>
38
38
 
39
+ #include <pthread.h>
40
+
39
41
  /* *****************************************************************************
40
42
  Hash types
41
43
  ***************************************************************************** */
@@ -69,18 +71,34 @@ static void fiobj_hash_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
69
71
  fio_free(FIOBJ2PTR(o));
70
72
  }
71
73
 
72
- static __thread FIOBJ each_at_key = FIOBJ_INVALID;
74
+ static pthread_key_t each_at_key;
75
+ static pthread_once_t each_at_key_once = PTHREAD_ONCE_INIT;
76
+ static void init_each_at_key(void) {
77
+ pthread_key_create(&each_at_key, free);
78
+ }
79
+ static void init_each_at_key_ptr(void) {
80
+ FIOBJ *eak = malloc(sizeof(FIOBJ));
81
+ FIO_ASSERT_ALLOC(eak);
82
+ *eak = FIOBJ_INVALID;
83
+ pthread_setspecific(each_at_key, eak);
84
+ }
73
85
 
74
86
  static size_t fiobj_hash_each1(FIOBJ o, size_t start_at,
75
87
  int (*task)(FIOBJ obj, void *arg), void *arg) {
76
88
  assert(o && FIOBJ_TYPE_IS(o, FIOBJ_T_HASH));
77
- FIOBJ old_each_at_key = each_at_key;
89
+ pthread_once(&each_at_key_once, init_each_at_key);
90
+ FIOBJ *each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
91
+ if (!each_at_key_ptr) {
92
+ init_each_at_key_ptr();
93
+ each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
94
+ }
95
+ FIOBJ old_each_at_key = *each_at_key_ptr;
78
96
  fio_hash___s *hash = &obj2hash(o)->hash;
79
97
  size_t count = 0;
80
98
  if (hash->count == hash->pos) {
81
99
  /* no holes in the hash, we can work as we please. */
82
100
  for (count = start_at; count < hash->count; ++count) {
83
- each_at_key = hash->ordered[count].obj.key;
101
+ *each_at_key_ptr = hash->ordered[count].obj.key;
84
102
  if (task((FIOBJ)hash->ordered[count].obj.obj, arg) == -1) {
85
103
  ++count;
86
104
  goto end;
@@ -100,17 +118,25 @@ static size_t fiobj_hash_each1(FIOBJ o, size_t start_at,
100
118
  if (hash->ordered[pos].obj.key == FIOBJ_INVALID)
101
119
  continue;
102
120
  ++count;
103
- each_at_key = hash->ordered[pos].obj.key;
121
+ *each_at_key_ptr = hash->ordered[pos].obj.key;
104
122
  if (task((FIOBJ)hash->ordered[pos].obj.obj, arg) == -1)
105
123
  break;
106
124
  }
107
125
  }
108
126
  end:
109
- each_at_key = old_each_at_key;
127
+ *each_at_key_ptr = old_each_at_key;
110
128
  return count;
111
129
  }
112
130
 
113
- FIOBJ fiobj_hash_key_in_loop(void) { return each_at_key; }
131
+ FIOBJ fiobj_hash_key_in_loop(void) {
132
+ pthread_once(&each_at_key_once, init_each_at_key);
133
+ FIOBJ *each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
134
+ if (!each_at_key_ptr) {
135
+ init_each_at_key_ptr();
136
+ each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
137
+ }
138
+ return *each_at_key_ptr;
139
+ }
114
140
 
115
141
  static size_t fiobj_hash_is_eq(const FIOBJ self, const FIOBJ other) {
116
142
  if (fio_hash___count(&obj2hash(self)->hash) !=
@@ -240,12 +240,20 @@ Testing
240
240
  #if DEBUG
241
241
  static inline void mustache_save2file(char const *filename, char const *data,
242
242
  size_t length) {
243
+ #ifdef __MINGW32__
244
+ int fd = _open(filename, _O_CREAT | _O_RDWR);
245
+ #else
243
246
  int fd = open(filename, O_CREAT | O_RDWR, 0);
247
+ #endif
244
248
  if (fd == -1) {
245
249
  perror("Couldn't open / create file for template testing");
246
250
  exit(-1);
247
251
  }
252
+ #ifdef __MINGW32__
253
+ _chmod(filename, _S_IREAD | _S_IWRITE);
254
+ #else
248
255
  fchmod(fd, 0777);
256
+ #endif
249
257
  if (pwrite(fd, data, length, 0) != (ssize_t)length) {
250
258
  perror("Mustache template write error");
251
259
  exit(-1);
@@ -265,6 +273,7 @@ void fiobj_mustache_test(void) {
265
273
  "{{=<< >>=}}* Users:\r\n<<#users>><<id>>. <<& name>> "
266
274
  "(<<name>>)\r\n<</users>>\r\nNested: <<& nested.item >>.";
267
275
  char const *template_name = "mustache_test_template.mustache";
276
+ fprintf(stderr, "mustache test saving template %s\n", template_name);
268
277
  mustache_save2file(template_name, template, strlen(template));
269
278
  mustache_s *m =
270
279
  fiobj_mustache_load((fio_str_info_s){.data = (char *)template_name});
@@ -12,6 +12,8 @@ License: MIT
12
12
  #include <errno.h>
13
13
  #include <math.h>
14
14
 
15
+ #include <pthread.h>
16
+
15
17
  /* *****************************************************************************
16
18
  Numbers Type
17
19
  ***************************************************************************** */
@@ -33,7 +35,17 @@ typedef struct {
33
35
  Numbers VTable
34
36
  ***************************************************************************** */
35
37
 
36
- static __thread char num_buffer[512];
38
+ static pthread_key_t num_vt_buffer_key;
39
+ static pthread_once_t num_vt_buffer_once = PTHREAD_ONCE_INIT;
40
+ static void init_num_vt_buffer_key(void) {
41
+ pthread_key_create(&num_vt_buffer_key, free);
42
+ }
43
+ static void init_num_vt_buffer_ptr(void) {
44
+ char *num_vt_buffer = malloc(sizeof(char)*512);
45
+ FIO_ASSERT_ALLOC(num_vt_buffer);
46
+ memset(num_vt_buffer, 0, sizeof(char)*512);
47
+ pthread_setspecific(num_vt_buffer_key, num_vt_buffer);
48
+ }
37
49
 
38
50
  static intptr_t fio_i2i(const FIOBJ o) { return obj2num(o)->i; }
39
51
  static intptr_t fio_f2i(const FIOBJ o) {
@@ -46,6 +58,12 @@ static size_t fio_itrue(const FIOBJ o) { return (obj2num(o)->i != 0); }
46
58
  static size_t fio_ftrue(const FIOBJ o) { return (obj2float(o)->f != 0); }
47
59
 
48
60
  static fio_str_info_s fio_i2str(const FIOBJ o) {
61
+ pthread_once(&num_vt_buffer_once, init_num_vt_buffer_key);
62
+ char *num_buffer = pthread_getspecific(num_vt_buffer_key);
63
+ if (!num_buffer) {
64
+ init_num_vt_buffer_ptr();
65
+ num_buffer = pthread_getspecific(num_vt_buffer_key);
66
+ }
49
67
  return (fio_str_info_s){
50
68
  .data = num_buffer,
51
69
  .len = fio_ltoa(num_buffer, obj2num(o)->i, 10),
@@ -60,6 +78,12 @@ static fio_str_info_s fio_f2str(const FIOBJ o) {
60
78
  else
61
79
  return (fio_str_info_s){.data = (char *)"-Infinity", .len = 9};
62
80
  }
81
+ pthread_once(&num_vt_buffer_once, init_num_vt_buffer_key);
82
+ char *num_buffer = pthread_getspecific(num_vt_buffer_key);
83
+ if (!num_buffer) {
84
+ init_num_vt_buffer_ptr();
85
+ num_buffer = pthread_getspecific(num_vt_buffer_key);
86
+ }
63
87
  return (fio_str_info_s){
64
88
  .data = num_buffer,
65
89
  .len = fio_ftoa(num_buffer, obj2float(o)->f, 10),
@@ -126,14 +150,30 @@ FIOBJ fiobj_num_new_bignum(intptr_t num) {
126
150
  // FIOBJ_IS_ALLOCATED(target)); obj2num(target)->i = num;
127
151
  // }
128
152
 
153
+ static pthread_key_t num_ret_key;
154
+ static pthread_once_t num_ret_once = PTHREAD_ONCE_INIT;
155
+ static void init_num_ret_key(void) {
156
+ pthread_key_create(&num_ret_key, free);
157
+ }
158
+ static void init_num_ret_ptr(void) {
159
+ fiobj_num_s *ret = malloc(sizeof(fiobj_num_s));
160
+ FIO_ASSERT_ALLOC(ret);
161
+ memset(ret, 0, sizeof(fiobj_num_s));
162
+ pthread_setspecific(num_ret_key, ret);
163
+ }
129
164
  /** Creates a temporary Number object. This ignores `fiobj_free`. */
130
165
  FIOBJ fiobj_num_tmp(intptr_t num) {
131
- static __thread fiobj_num_s ret;
132
- ret = (fiobj_num_s){
166
+ pthread_once(&num_ret_once, init_num_ret_key);
167
+ fiobj_num_s *ret = pthread_getspecific(num_ret_key);
168
+ if (!ret) {
169
+ init_num_ret_ptr();
170
+ ret = pthread_getspecific(num_ret_key);
171
+ }
172
+ *ret = (fiobj_num_s){
133
173
  .head = {.type = FIOBJ_T_NUMBER, .ref = ((~(uint32_t)0) >> 4)},
134
174
  .i = num,
135
175
  };
136
- return (FIOBJ)&ret;
176
+ return (FIOBJ)ret;
137
177
  }
138
178
 
139
179
  /* *****************************************************************************
@@ -164,10 +204,26 @@ void fiobj_float_set(FIOBJ obj, double num) {
164
204
  obj2float(obj)->f = num;
165
205
  }
166
206
 
207
+ static pthread_key_t float_ret_key;
208
+ static pthread_once_t float_ret_once = PTHREAD_ONCE_INIT;
209
+ static void init_float_ret_key(void) {
210
+ pthread_key_create(&float_ret_key, free);
211
+ }
212
+ static void init_float_ret_ptr(void) {
213
+ fiobj_float_s *ret = malloc(sizeof(fiobj_float_s));
214
+ FIO_ASSERT_ALLOC(ret);
215
+ memset(ret, 0, sizeof(fiobj_float_s));
216
+ pthread_setspecific(float_ret_key, ret);
217
+ }
167
218
  /** Creates a temporary Number object. This ignores `fiobj_free`. */
168
219
  FIOBJ fiobj_float_tmp(double num) {
169
- static __thread fiobj_float_s ret;
170
- ret = (fiobj_float_s){
220
+ pthread_once(&float_ret_once, init_float_ret_key);
221
+ fiobj_float_s *ret = pthread_getspecific(float_ret_key);
222
+ if (!ret) {
223
+ init_float_ret_ptr();
224
+ ret = pthread_getspecific(float_ret_key);
225
+ }
226
+ *ret = (fiobj_float_s){
171
227
  .head =
172
228
  {
173
229
  .type = FIOBJ_T_FLOAT,
@@ -175,20 +231,42 @@ FIOBJ fiobj_float_tmp(double num) {
175
231
  },
176
232
  .f = num,
177
233
  };
178
- return (FIOBJ)&ret;
234
+ return (FIOBJ)ret;
179
235
  }
180
236
 
181
237
  /* *****************************************************************************
182
238
  Numbers to Strings - Buffered
183
239
  ***************************************************************************** */
184
240
 
185
- static __thread char num_buffer[512];
241
+ static pthread_key_t num_str_buffer_key;
242
+ static pthread_once_t num_str_buffer_once = PTHREAD_ONCE_INIT;
243
+ static void init_num_str_buffer_key(void) {
244
+ pthread_key_create(&num_str_buffer_key, free);
245
+ }
246
+ static void init_num_str_buffer_ptr(void) {
247
+ char *num_str_buffer = malloc(sizeof(char)*512);
248
+ FIO_ASSERT_ALLOC(num_str_buffer);
249
+ memset(num_str_buffer, 0, sizeof(char)*512);
250
+ pthread_setspecific(num_str_buffer_key, num_str_buffer);
251
+ }
186
252
 
187
253
  fio_str_info_s fio_ltocstr(long i) {
254
+ pthread_once(&num_str_buffer_once, init_num_str_buffer_key);
255
+ char *num_buffer = pthread_getspecific(num_str_buffer_key);
256
+ if (!num_buffer) {
257
+ init_num_str_buffer_ptr();
258
+ num_buffer = pthread_getspecific(num_str_buffer_key);
259
+ }
188
260
  return (fio_str_info_s){.data = num_buffer,
189
261
  .len = fio_ltoa(num_buffer, i, 10)};
190
262
  }
191
263
  fio_str_info_s fio_ftocstr(double f) {
264
+ pthread_once(&num_str_buffer_once, init_num_str_buffer_key);
265
+ char *num_buffer = pthread_getspecific(num_str_buffer_key);
266
+ if (!num_buffer) {
267
+ init_num_str_buffer_ptr();
268
+ num_buffer = pthread_getspecific(num_str_buffer_key);
269
+ }
192
270
  return (fio_str_info_s){.data = num_buffer,
193
271
  .len = fio_ftoa(num_buffer, f, 10)};
194
272
  }
@@ -37,6 +37,8 @@ License: MIT
37
37
  #define PATH_MAX PAGE_SIZE
38
38
  #endif
39
39
 
40
+ #include <pthread.h>
41
+
40
42
  /* *****************************************************************************
41
43
  String Type
42
44
  ***************************************************************************** */
@@ -176,22 +178,33 @@ FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
176
178
  return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
177
179
  }
178
180
 
181
+ static pthread_key_t str_tmp_key;
182
+ static pthread_once_t str_tmp_once = PTHREAD_ONCE_INIT;
183
+ static void init_str_tmp_key(void) {
184
+ pthread_key_create(&str_tmp_key, free);
185
+ }
186
+ static void init_str_tmp_key_ptr(void) {
187
+ fiobj_str_s *tmp = malloc(sizeof(fiobj_str_s));
188
+ FIO_ASSERT_ALLOC(tmp);
189
+ tmp->head.ref = ((~(uint32_t)0) >> 4);
190
+ tmp->head.type = FIOBJ_T_STRING;
191
+ tmp->str.small = 1;
192
+ pthread_setspecific(str_tmp_key, tmp);
193
+ }
179
194
  /**
180
195
  * Returns a thread-static temporary string. Avoid calling `fiobj_dup` or
181
196
  * `fiobj_free`.
182
197
  */
183
198
  FIOBJ fiobj_str_tmp(void) {
184
- static __thread fiobj_str_s tmp = {
185
- .head =
186
- {
187
- .ref = ((~(uint32_t)0) >> 4),
188
- .type = FIOBJ_T_STRING,
189
- },
190
- .str = {.small = 1},
191
- };
192
- tmp.str.frozen = 0;
193
- fio_str_resize(&tmp.str, 0);
194
- return ((uintptr_t)&tmp | FIOBJECT_STRING_FLAG);
199
+ pthread_once(&str_tmp_once, init_str_tmp_key);
200
+ fiobj_str_s *tmp = (fiobj_str_s *)pthread_getspecific(str_tmp_key);
201
+ if (!tmp) {
202
+ init_str_tmp_key_ptr();
203
+ tmp = (fiobj_str_s *)pthread_getspecific(str_tmp_key);
204
+ }
205
+ tmp->str.frozen = 0;
206
+ fio_str_resize(&tmp->str, 0);
207
+ return ((uintptr_t)tmp | FIOBJECT_STRING_FLAG);
195
208
  }
196
209
 
197
210
  /** Prevents the String object from being changed. */
@@ -102,7 +102,7 @@ size_t __attribute__((weak)) fio_ltoa(char *dest, int64_t num, uint8_t base) {
102
102
  '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
103
103
 
104
104
  size_t len = 0;
105
- char buf[48]; /* we only need up to 20 for base 10, but base 3 needs 41... */
105
+ char buf[48] = {0}; /* we only need up to 20 for base 10, but base 3 needs 41... */
106
106
 
107
107
  if (!num)
108
108
  goto zero;
@@ -502,7 +502,7 @@ fio_str_info_s fio_ftocstr(double);
502
502
  /**
503
503
  * Returns a C String (NUL terminated) using the `fio_str_info_s` data type.
504
504
  *
505
- * The Sting in binary safe and might contain NUL bytes in the middle as well as
505
+ * The String is binary safe and might contain NUL bytes in the middle as well as
506
506
  * a terminating NUL.
507
507
  *
508
508
  * If a a Number or a Float are passed to the function, they
@@ -554,11 +554,13 @@ FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o) {
554
554
  if (!FIOBJ_IS_ALLOCATED(o))
555
555
  return (uint64_t)o;
556
556
  fio_str_info_s s = fiobj_obj2cstr(o);
557
- return FIO_HASH_FN(s.data, s.len, &fiobj_each2, &fiobj_free_complex_object);
557
+ return FIO_HASH_FN(s.data, s.len, (uintptr_t)&fiobj_each2,
558
+ (uintptr_t)&fiobj_free_complex_object);
558
559
  }
559
560
 
560
561
  FIO_INLINE uint64_t fiobj_hash_string(const void *data, size_t len) {
561
- return FIO_HASH_FN(data, len, &fiobj_each2, &fiobj_free_complex_object);
562
+ return FIO_HASH_FN(data, len, (uintptr_t)&fiobj_each2,
563
+ (uintptr_t)&fiobj_free_complex_object);
562
564
  }
563
565
 
564
566
  /**