iodine 0.6.5 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +4 -4
  4. data/SPEC-Websocket-Draft.md +3 -6
  5. data/bin/mustache.rb +128 -0
  6. data/examples/test_template.mustache +16 -0
  7. data/ext/iodine/fio.c +9397 -0
  8. data/ext/iodine/fio.h +4723 -0
  9. data/ext/iodine/fio_ary.h +353 -54
  10. data/ext/iodine/fio_cli.c +351 -361
  11. data/ext/iodine/fio_cli.h +84 -105
  12. data/ext/iodine/fio_hashmap.h +70 -16
  13. data/ext/iodine/fio_json_parser.h +35 -24
  14. data/ext/iodine/fio_siphash.c +104 -4
  15. data/ext/iodine/fio_siphash.h +18 -2
  16. data/ext/iodine/fio_str.h +1218 -0
  17. data/ext/iodine/fio_tmpfile.h +1 -1
  18. data/ext/iodine/fiobj.h +13 -8
  19. data/ext/iodine/fiobj4sock.h +6 -8
  20. data/ext/iodine/fiobj_ary.c +107 -17
  21. data/ext/iodine/fiobj_ary.h +36 -4
  22. data/ext/iodine/fiobj_data.c +146 -127
  23. data/ext/iodine/fiobj_data.h +25 -23
  24. data/ext/iodine/fiobj_hash.c +7 -7
  25. data/ext/iodine/fiobj_hash.h +6 -5
  26. data/ext/iodine/fiobj_json.c +20 -17
  27. data/ext/iodine/fiobj_json.h +5 -5
  28. data/ext/iodine/fiobj_mem.h +71 -0
  29. data/ext/iodine/fiobj_mustache.c +310 -0
  30. data/ext/iodine/fiobj_mustache.h +40 -0
  31. data/ext/iodine/fiobj_numbers.c +199 -94
  32. data/ext/iodine/fiobj_numbers.h +7 -7
  33. data/ext/iodine/fiobj_str.c +142 -333
  34. data/ext/iodine/fiobj_str.h +65 -55
  35. data/ext/iodine/fiobject.c +49 -11
  36. data/ext/iodine/fiobject.h +40 -39
  37. data/ext/iodine/http.c +382 -190
  38. data/ext/iodine/http.h +124 -80
  39. data/ext/iodine/http1.c +99 -127
  40. data/ext/iodine/http1.h +5 -5
  41. data/ext/iodine/http1_parser.c +3 -2
  42. data/ext/iodine/http1_parser.h +2 -2
  43. data/ext/iodine/http_internal.c +14 -12
  44. data/ext/iodine/http_internal.h +25 -19
  45. data/ext/iodine/iodine.c +37 -18
  46. data/ext/iodine/iodine.h +4 -0
  47. data/ext/iodine/iodine_caller.c +9 -2
  48. data/ext/iodine/iodine_caller.h +2 -0
  49. data/ext/iodine/iodine_connection.c +82 -117
  50. data/ext/iodine/iodine_defer.c +57 -50
  51. data/ext/iodine/iodine_defer.h +0 -1
  52. data/ext/iodine/iodine_fiobj2rb.h +4 -2
  53. data/ext/iodine/iodine_helpers.c +4 -4
  54. data/ext/iodine/iodine_http.c +25 -32
  55. data/ext/iodine/iodine_json.c +2 -1
  56. data/ext/iodine/iodine_mustache.c +423 -0
  57. data/ext/iodine/iodine_mustache.h +6 -0
  58. data/ext/iodine/iodine_pubsub.c +48 -153
  59. data/ext/iodine/iodine_pubsub.h +5 -4
  60. data/ext/iodine/iodine_rack_io.c +7 -5
  61. data/ext/iodine/iodine_store.c +16 -13
  62. data/ext/iodine/iodine_tcp.c +26 -34
  63. data/ext/iodine/mustache_parser.h +1085 -0
  64. data/ext/iodine/redis_engine.c +740 -646
  65. data/ext/iodine/redis_engine.h +13 -15
  66. data/ext/iodine/resp_parser.h +11 -5
  67. data/ext/iodine/websocket_parser.h +13 -13
  68. data/ext/iodine/websockets.c +240 -393
  69. data/ext/iodine/websockets.h +52 -113
  70. data/lib/iodine.rb +1 -1
  71. data/lib/iodine/mustache.rb +140 -0
  72. data/lib/iodine/version.rb +1 -1
  73. metadata +15 -28
  74. data/ext/iodine/defer.c +0 -566
  75. data/ext/iodine/defer.h +0 -148
  76. data/ext/iodine/evio.c +0 -26
  77. data/ext/iodine/evio.h +0 -161
  78. data/ext/iodine/evio_callbacks.c +0 -26
  79. data/ext/iodine/evio_epoll.c +0 -251
  80. data/ext/iodine/evio_kqueue.c +0 -194
  81. data/ext/iodine/facil.c +0 -2325
  82. data/ext/iodine/facil.h +0 -616
  83. data/ext/iodine/fio_base64.c +0 -277
  84. data/ext/iodine/fio_base64.h +0 -71
  85. data/ext/iodine/fio_llist.h +0 -257
  86. data/ext/iodine/fio_mem.c +0 -675
  87. data/ext/iodine/fio_mem.h +0 -143
  88. data/ext/iodine/fio_random.c +0 -248
  89. data/ext/iodine/fio_random.h +0 -45
  90. data/ext/iodine/fio_sha1.c +0 -362
  91. data/ext/iodine/fio_sha1.h +0 -107
  92. data/ext/iodine/fio_sha2.c +0 -842
  93. data/ext/iodine/fio_sha2.h +0 -169
  94. data/ext/iodine/pubsub.c +0 -867
  95. data/ext/iodine/pubsub.h +0 -221
  96. data/ext/iodine/sock.c +0 -1366
  97. data/ext/iodine/sock.h +0 -566
  98. data/ext/iodine/spnlock.inc +0 -111
@@ -1,675 +0,0 @@
1
- /*
2
- Copyright: Boaz Segev, 2018
3
- License: MIT
4
-
5
- Feel free to copy, use and enjoy according to the license provided.
6
- */
7
-
8
- #include "spnlock.inc"
9
- #include <errno.h>
10
- #include <stdint.h>
11
- #include <stdio.h>
12
- #include <string.h>
13
- #include <sys/mman.h>
14
- #include <unistd.h>
15
-
16
- /* *****************************************************************************
17
- If FIO_FORCE_MALLOC is set, use glibc / library malloc
18
- ***************************************************************************** */
19
- #if FIO_FORCE_MALLOC
20
-
21
- void *fio_malloc(size_t size) { return malloc(size); }
22
-
23
- void *fio_calloc(size_t size, size_t count) { return calloc(size, count); }
24
-
25
- void fio_free(void *ptr) { free(ptr); }
26
-
27
- void *fio_realloc(void *ptr, size_t new_size) { return realloc(ptr, new_size); }
28
- void *fio_realloc2(void *ptr, size_t new_size, size_t valid_len) {
29
- return realloc(ptr, new_size);
30
- (void)valid_len;
31
- }
32
-
33
- void fio_malloc_after_fork(void) {}
34
-
35
- /* *****************************************************************************
36
- facil.io malloc implementation
37
- ***************************************************************************** */
38
- #else
39
-
40
- #include "fio_mem.h"
41
-
42
- #if !defined(__clang__) && !defined(__GNUC__)
43
- #define __thread _Thread_value
44
- #endif
45
-
46
- #undef malloc
47
- #undef calloc
48
- #undef free
49
- #undef realloc
50
-
51
- /* *****************************************************************************
52
- Memory Copying by 16 byte units
53
- ***************************************************************************** */
54
-
55
- #if __SIZEOF_INT128__ == 9 /* a 128bit type exists... but tests favor 64bit */
56
- static inline void fio_memcpy(__uint128_t *__restrict dest,
57
- __uint128_t *__restrict src, size_t units) {
58
- #elif SIZE_MAX == 0xFFFFFFFFFFFFFFFF /* 64 bit size_t */
59
- static inline void fio_memcpy(size_t *__restrict dest, size_t *__restrict src,
60
- size_t units) {
61
- units = units << 1;
62
- #elif SIZE_MAX == 0xFFFFFFFF /* 32 bit size_t */
63
- static inline void fio_memcpy(size_t *__restrict dest, size_t *__restrict src,
64
- size_t units) {
65
- units = units << 2;
66
- #else /* unknow... assume 16 bit? */
67
- static inline void fio_memcpy(uint16_t *__restrict dest,
68
- uint16_t *__restrict src, size_t units) {
69
- units = units << 3;
70
- #endif
71
- while (units >= 16) { /* unroll loop */
72
- dest[0] = src[0];
73
- dest[1] = src[1];
74
- dest[2] = src[2];
75
- dest[3] = src[3];
76
- dest[4] = src[4];
77
- dest[5] = src[5];
78
- dest[6] = src[6];
79
- dest[7] = src[7];
80
- dest[8] = src[8];
81
- dest[9] = src[9];
82
- dest[10] = src[10];
83
- dest[11] = src[11];
84
- dest[12] = src[12];
85
- dest[13] = src[13];
86
- dest[14] = src[14];
87
- dest[15] = src[15];
88
- dest += 16;
89
- src += 16;
90
- units -= 16;
91
- }
92
- switch (units) {
93
- case 15:
94
- *(dest++) = *(src++); /* fallthrough */
95
- case 14:
96
- *(dest++) = *(src++); /* fallthrough */
97
- case 13:
98
- *(dest++) = *(src++); /* fallthrough */
99
- case 12:
100
- *(dest++) = *(src++); /* fallthrough */
101
- case 11:
102
- *(dest++) = *(src++); /* fallthrough */
103
- case 10:
104
- *(dest++) = *(src++); /* fallthrough */
105
- case 9:
106
- *(dest++) = *(src++); /* fallthrough */
107
- case 8:
108
- *(dest++) = *(src++); /* fallthrough */
109
- case 7:
110
- *(dest++) = *(src++); /* fallthrough */
111
- case 6:
112
- *(dest++) = *(src++); /* fallthrough */
113
- case 5:
114
- *(dest++) = *(src++); /* fallthrough */
115
- case 4:
116
- *(dest++) = *(src++); /* fallthrough */
117
- case 3:
118
- *(dest++) = *(src++); /* fallthrough */
119
- case 2:
120
- *(dest++) = *(src++); /* fallthrough */
121
- case 1:
122
- *(dest++) = *(src++);
123
- }
124
- }
125
-
126
- /* *****************************************************************************
127
- System Memory wrappers
128
- ***************************************************************************** */
129
-
130
- /*
131
- * allocates memory using `mmap`, but enforces block size alignment.
132
- * requires page aligned `len`.
133
- *
134
- * `align_shift` is used to move the memory page alignment to allow for a single
135
- * page allocation header. align_shift MUST be either 0 (normal) or 1 (single
136
- * page header). Other values might cause errors.
137
- */
138
- static inline void *sys_alloc(size_t len, uint8_t is_indi) {
139
- void *result;
140
- static void *next_alloc = NULL;
141
- /* hope for the best? */
142
- #ifdef MAP_ALIGNED
143
- result =
144
- mmap(next_alloc, len, PROT_READ | PROT_WRITE,
145
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED(FIO_MEMORY_BLOCK_SIZE_LOG),
146
- -1, 0);
147
- #else
148
- result = mmap(next_alloc, len, PROT_READ | PROT_WRITE,
149
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
150
- #endif
151
- if (result == MAP_FAILED)
152
- return NULL;
153
- if (((uintptr_t)result & FIO_MEMORY_BLOCK_MASK)) {
154
- munmap(result, len);
155
- result = mmap(NULL, len + FIO_MEMORY_BLOCK_SIZE, PROT_READ | PROT_WRITE,
156
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
157
- if (result == MAP_FAILED)
158
- return NULL;
159
- const uintptr_t offset =
160
- (FIO_MEMORY_BLOCK_SIZE - ((uintptr_t)result & FIO_MEMORY_BLOCK_MASK));
161
- if (offset) {
162
- munmap(result, offset);
163
- result = (void *)((uintptr_t)result + offset);
164
- }
165
- munmap((void *)((uintptr_t)result + len), FIO_MEMORY_BLOCK_SIZE - offset);
166
- }
167
- next_alloc =
168
- (void *)((uintptr_t)result + FIO_MEMORY_BLOCK_SIZE +
169
- (is_indi * ((uintptr_t)1 << 30))); /* add 1TB for realloc */
170
- return result;
171
- }
172
-
173
- /* frees memory using `munmap`. requires exact, page aligned, `len` */
174
- static inline void sys_free(void *mem, size_t len) { munmap(mem, len); }
175
-
176
- static void *sys_realloc(void *mem, size_t prev_len, size_t new_len) {
177
- if (new_len > prev_len) {
178
- #if defined(__linux__) && defined(MREMAP_MAYMOVE)
179
- void *result = mremap(mem, prev_len, new_len, MREMAP_MAYMOVE);
180
- if (result == MAP_FAILED)
181
- return NULL;
182
- #else
183
- void *result =
184
- mmap((void *)((uintptr_t)mem + prev_len), new_len - prev_len,
185
- PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
186
- if (result == (void *)((uintptr_t)mem + prev_len)) {
187
- result = mem;
188
- } else {
189
- /* copy and free */
190
- munmap(result, new_len - prev_len); /* free the failed attempt */
191
- result = sys_alloc(new_len, 1); /* allocate new memory */
192
- if (!result)
193
- return NULL;
194
- fio_memcpy(result, mem, prev_len >> 4); /* copy data */
195
- // memcpy(result, mem, prev_len);
196
- munmap(mem, prev_len); /* free original memory */
197
- }
198
- #endif
199
- return result;
200
- }
201
- if (new_len + 4096 < prev_len) /* more than a single dangling page */
202
- munmap((void *)((uintptr_t)mem + new_len), prev_len - new_len);
203
- return mem;
204
- }
205
-
206
- /** Rounds up any size to the nearest page alignment (assumes 4096 bytes per
207
- * page) */
208
- static inline size_t sys_round_size(size_t size) {
209
- return (size & (~4095)) + (4096 * (!!(size & 4095)));
210
- }
211
-
212
- /* *****************************************************************************
213
- Data Types
214
- ***************************************************************************** */
215
-
216
- /* The basic block header. Starts a 64Kib memory block */
217
- typedef struct block_s {
218
- uint16_t ref; /* reference count (per memory page) */
219
- uint16_t pos; /* position into the block */
220
- uint16_t max; /* available memory count */
221
- uint16_t pad; /* memory padding */
222
- } block_s;
223
-
224
- /* a per-CPU core "arena" for memory allocations */
225
- typedef struct {
226
- block_s *block;
227
- spn_lock_i lock;
228
- } arena_s;
229
-
230
- /* The memory allocators persistent state */
231
- static struct {
232
- size_t active_size; /* active array size */
233
- block_s *available; /* free list for memory blocks */
234
- intptr_t count; /* free list counter */
235
- size_t cores; /* the number of detected CPU cores*/
236
- spn_lock_i lock; /* a global lock */
237
- } memory = {
238
- .cores = 1, .lock = SPN_LOCK_INIT,
239
- };
240
-
241
- /* The per-CPU arena array. */
242
- static arena_s *arenas;
243
-
244
- /* *****************************************************************************
245
- Per-CPU Arena management
246
- ***************************************************************************** */
247
-
248
- /* returned a locked arena. Attempts the preffered arena first. */
249
- static inline arena_s *arena_lock(arena_s *preffered) {
250
- if (!preffered)
251
- preffered = arenas;
252
- if (!spn_trylock(&preffered->lock))
253
- return preffered;
254
- do {
255
- arena_s *arena = preffered;
256
- for (size_t i = (size_t)(arena - arenas); i < memory.cores; ++i) {
257
- if ((preffered == arenas || arena != preffered) &&
258
- !spn_trylock(&arena->lock))
259
- return arena;
260
- ++arena;
261
- }
262
- if (preffered == arenas)
263
- reschedule_thread();
264
- preffered = arenas;
265
- } while (1);
266
- }
267
-
268
- static __thread arena_s *arena_last_used;
269
-
270
- static void arena_enter(void) { arena_last_used = arena_lock(arena_last_used); }
271
-
272
- static inline void arena_exit(void) { spn_unlock(&arena_last_used->lock); }
273
-
274
- /** Clears any memory locks, in case of a system call to `fork`. */
275
- void fio_malloc_after_fork(void) {
276
- arena_last_used = NULL;
277
- if (!arenas) {
278
- return;
279
- }
280
- memory.lock = SPN_LOCK_INIT;
281
- for (size_t i = 0; i < memory.cores; ++i) {
282
- arenas[i].lock = SPN_LOCK_INIT;
283
- }
284
- }
285
-
286
- /* *****************************************************************************
287
- Block management
288
- ***************************************************************************** */
289
-
290
- // static inline block_s **block_find(void *mem_) {
291
- // const uintptr_t mem = (uintptr_t)mem_;
292
- // block_s *blk = memory.active;
293
- // }
294
-
295
- /* intializes the block header for an available block of memory. */
296
- static inline block_s *block_init(void *blk_) {
297
- block_s *blk = blk_;
298
- *blk = (block_s){
299
- .ref = 1,
300
- .pos = (2 + (sizeof(block_s) >> 4)),
301
- .max = (FIO_MEMORY_BLOCK_SLICES - 1) -
302
- (sizeof(block_s) >> 4), /* count available units of 16 bytes */
303
- };
304
- return blk;
305
- }
306
-
307
- /* intializes the block header for an available block of memory. */
308
- static inline void block_free(block_s *blk) {
309
- if (spn_sub(&blk->ref, 1))
310
- return;
311
-
312
- if (spn_add(&memory.count, 1) >
313
- (intptr_t)(FIO_MEM_MAX_BLOCKS_PER_CORE * memory.cores)) {
314
- /* TODO: return memory to the system */
315
- spn_sub(&memory.count, 1);
316
- sys_free(blk, FIO_MEMORY_BLOCK_SIZE);
317
- return;
318
- }
319
- memset(blk, 0, FIO_MEMORY_BLOCK_SIZE);
320
- spn_lock(&memory.lock);
321
- *(block_s **)blk = memory.available;
322
- memory.available = (block_s *)blk;
323
- spn_unlock(&memory.lock);
324
- }
325
-
326
- /* intializes the block header for an available block of memory. */
327
- static inline block_s *block_new(void) {
328
- block_s *blk = NULL;
329
-
330
- if (memory.available) {
331
- spn_lock(&memory.lock);
332
- blk = (block_s *)memory.available;
333
- if (blk) {
334
- memory.available = ((block_s **)blk)[0];
335
- }
336
- spn_unlock(&memory.lock);
337
- }
338
- if (blk) {
339
- spn_sub(&memory.count, 1);
340
- ((block_s **)blk)[0] = NULL;
341
- ((block_s **)blk)[1] = NULL;
342
- return block_init(blk);
343
- }
344
- /* TODO: collect memory from the system */
345
- blk = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
346
- if (!blk)
347
- return NULL;
348
- return block_init(blk);
349
- ;
350
- }
351
-
352
- static inline void *block_slice(uint16_t units) {
353
- block_s *blk = arena_last_used->block;
354
- if (!blk) {
355
- /* arena is empty */
356
- blk = block_new();
357
- arena_last_used->block = blk;
358
- } else if (blk->pos + units > blk->max) {
359
- /* not enough memory in the block - rotate */
360
- block_free(blk);
361
- blk = block_new();
362
- arena_last_used->block = blk;
363
- }
364
- if (!blk) {
365
- /* no system memory available? */
366
- return NULL;
367
- }
368
- /* slice block starting at blk->pos and increase reference count */
369
- const void *mem = (void *)((uintptr_t)blk + ((uintptr_t)blk->pos << 4));
370
- spn_add(&blk->ref, 1);
371
- blk->pos += units;
372
- if (blk->pos >= blk->max) {
373
- /* it's true that a 16 bytes slice remains, but statistically... */
374
- /* ... the block was fully utilized, clear arena */
375
- block_free(blk);
376
- arena_last_used->block = NULL;
377
- }
378
- return (void *)mem;
379
- }
380
-
381
- static inline void block_slice_free(void *mem) {
382
- /* locate block boundary */
383
- block_s *blk = (block_s *)((uintptr_t)mem & (~FIO_MEMORY_BLOCK_MASK));
384
- block_free(blk);
385
- }
386
-
387
- /* *****************************************************************************
388
- Non-Block allocations (direct from the system)
389
- ***************************************************************************** */
390
-
391
- static inline void *big_alloc(size_t size) {
392
- size = sys_round_size(size + 16);
393
- size_t *mem = sys_alloc(size, 1);
394
- if (mem) { /* likely */
395
- *mem = size;
396
- return (void *)(((uintptr_t)mem) + 16);
397
- }
398
- return NULL;
399
- }
400
-
401
- static inline void big_free(void *ptr) {
402
- size_t *mem = (void *)(((uintptr_t)ptr) - 16);
403
- sys_free(mem, *mem);
404
- }
405
-
406
- static inline void *big_realloc(void *ptr, size_t new_size) {
407
- size_t *mem = (void *)(((uintptr_t)ptr) - 16);
408
- new_size = sys_round_size(new_size + 16);
409
- mem = sys_realloc(mem, *mem, new_size);
410
- if (!mem)
411
- return NULL;
412
- *mem = new_size;
413
- return (void *)(((uintptr_t)mem) + 16);
414
- }
415
-
416
- /* *****************************************************************************
417
- Library Initialization (initialize arenas and allocate a block for each CPU)
418
- ***************************************************************************** */
419
-
420
- static void __attribute__((constructor)) fio_mem_init(void) {
421
- if (arenas)
422
- return;
423
-
424
- #ifdef _SC_NPROCESSORS_ONLN
425
- ssize_t cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
426
- #else
427
- #warning Dynamic CPU core count is unavailable - assuming 8 cores for memory allocation pools.
428
- ssize_t cpu_count = 8; /* fallback */
429
- #endif
430
- memory.cores = cpu_count;
431
- memory.count = 0 - (intptr_t)cpu_count;
432
- arenas = big_alloc(sizeof(*arenas) * cpu_count);
433
- if (!arenas) {
434
- perror("FATAL ERROR: Couldn't initialize memory allocator");
435
- exit(errno);
436
- }
437
- size_t pre_pool = cpu_count > 32 ? 32 : cpu_count;
438
- for (size_t i = 0; i < pre_pool; ++i) {
439
- void *block = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
440
- if (block) {
441
- block_init(block);
442
- block_free(block);
443
- }
444
- }
445
- }
446
-
447
- static void __attribute__((destructor)) fio_mem_destroy(void) {
448
- if (!arenas)
449
- return;
450
-
451
- arena_s *arena = arenas;
452
- for (size_t i = 0; i < memory.cores; ++i) {
453
- if (arena->block)
454
- block_free(arena->block);
455
- arena->block = NULL;
456
- ++arena;
457
- }
458
- while (memory.available) {
459
- block_s *b = memory.available;
460
- memory.available = *(block_s **)b;
461
- sys_free(b, FIO_MEMORY_BLOCK_SIZE);
462
- }
463
- big_free(arenas);
464
- arenas = NULL;
465
- }
466
-
467
- /* *****************************************************************************
468
- Memory allocation / deacclocation API
469
- ***************************************************************************** */
470
-
471
- void *fio_malloc(size_t size) {
472
- if (!size)
473
- return NULL;
474
- if (size >= FIO_MEMORY_BLOCK_ALLOC_LIMIT) {
475
- /* system allocation - must be block aligned */
476
- return big_alloc(size);
477
- }
478
- /* ceiling for 16 byte alignement, translated to 16 byte units */
479
- size = (size >> 4) + (!!(size & 15));
480
- arena_enter();
481
- void *mem = block_slice(size);
482
- arena_exit();
483
- return mem;
484
- }
485
-
486
- void *fio_calloc(size_t size, size_t count) {
487
- return fio_malloc(size * count); // memory is pre-initialized by mmap or pool.
488
- }
489
-
490
- void fio_free(void *ptr) {
491
- if (!ptr)
492
- return;
493
- if (((uintptr_t)ptr & FIO_MEMORY_BLOCK_MASK) == 16) {
494
- /* big allocation - direct from the system */
495
- big_free(ptr);
496
- return;
497
- }
498
- /* allocated within block */
499
- block_slice_free(ptr);
500
- }
501
-
502
- /**
503
- * Re-allocates memory. An attept to avoid copying the data is made only for
504
- * memory allocations larger than 64Kb.
505
- *
506
- * This variation is slightly faster as it might copy less data
507
- */
508
- void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length) {
509
- if (!ptr)
510
- return fio_malloc(new_size);
511
- if (((uintptr_t)ptr & FIO_MEMORY_BLOCK_MASK) == 16) {
512
- /* big reallocation - direct from the system */
513
- return big_realloc(ptr, new_size);
514
- }
515
- /* allocated within block - don't even try to expand the allocation */
516
- /* ceiling for 16 byte alignement, translated to 16 byte units */
517
- void *new_mem = fio_malloc(new_size);
518
- if (!new_mem)
519
- return NULL;
520
- new_size = ((new_size >> 4) + (!!(new_size & 15)));
521
- copy_length = ((copy_length >> 4) + (!!(copy_length & 15)));
522
- // memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length) <<
523
- // 4);
524
- fio_memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length));
525
- block_slice_free(ptr);
526
- return new_mem;
527
- }
528
-
529
- void *fio_realloc(void *ptr, size_t new_size) {
530
- const size_t max_old =
531
- FIO_MEMORY_BLOCK_SIZE - ((uintptr_t)ptr & FIO_MEMORY_BLOCK_MASK);
532
- return fio_realloc2(ptr, new_size, max_old);
533
- }
534
-
535
- /* *****************************************************************************
536
- FIO_OVERRIDE_MALLOC - override glibc / library malloc
537
- ***************************************************************************** */
538
- #if FIO_OVERRIDE_MALLOC
539
- void *malloc(size_t size) { return fio_malloc(size); }
540
- void *calloc(size_t size, size_t count) { return fio_calloc(size, count); }
541
- void free(void *ptr) { fio_free(ptr); }
542
- void *realloc(void *ptr, size_t new_size) { return fio_realloc(ptr, new_size); }
543
- #endif
544
-
545
- #endif
546
-
547
- /* *****************************************************************************
548
- Some Tests
549
- ***************************************************************************** */
550
-
551
- #if DEBUG && !FIO_FORCE_MALLOC
552
-
553
- void fio_malloc_test(void) {
554
- #define TEST_ASSERT(cond, ...) \
555
- if (!(cond)) { \
556
- fprintf(stderr, "* " __VA_ARGS__); \
557
- fprintf(stderr, "\nTesting failed.\n"); \
558
- exit(-1); \
559
- }
560
-
561
- fprintf(stderr, "=== Testing facil.io memory allocator's system calls\n");
562
- char *mem = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
563
- TEST_ASSERT(mem, "sys_alloc failed to allocate memory!\n");
564
- TEST_ASSERT(!((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK),
565
- "Memory allocation not aligned to FIO_MEMORY_BLOCK_SIZE!");
566
- mem[0] = 'a';
567
- mem[FIO_MEMORY_BLOCK_SIZE - 1] = 'z';
568
- fprintf(stderr, "* Testing reallocation from %p\n", (void *)mem);
569
- char *mem2 =
570
- sys_realloc(mem, FIO_MEMORY_BLOCK_SIZE, FIO_MEMORY_BLOCK_SIZE * 2);
571
- if (mem == mem2)
572
- fprintf(stderr, "* Performed system realloc without copy :-)\n");
573
- TEST_ASSERT(mem2[0] = 'a' && mem2[FIO_MEMORY_BLOCK_SIZE - 1] == 'z',
574
- "Reaclloc data was lost!");
575
- sys_free(mem2, FIO_MEMORY_BLOCK_SIZE * 2);
576
- fprintf(stderr, "=== Testing facil.io memory allocator's internal data.\n");
577
- TEST_ASSERT(arenas, "Missing arena data - library not initialized!");
578
- TEST_ASSERT(fio_malloc(0) == NULL, "fio_malloc 0 bytes should be NULL!\n");
579
- fio_free(NULL); /* fio_free(NULL) shouldn't crash... */
580
- mem = fio_malloc(1);
581
- TEST_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
582
- TEST_ASSERT(!((uintptr_t)mem & 15), "fio_malloc memory not aligned!\n");
583
- TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16,
584
- "small fio_malloc memory indicates system allocation!\n");
585
- mem[0] = 'a';
586
- TEST_ASSERT(mem[0] == 'a', "allocate memory wasn't written to!\n");
587
- mem = fio_realloc(mem, 1);
588
- TEST_ASSERT(mem[0] == 'a', "fio_realloc memory wasn't copied!\n");
589
- TEST_ASSERT(arena_last_used, "arena_last_used wasn't initialized!\n");
590
- block_s *b = arena_last_used->block;
591
- size_t count = 2;
592
- intptr_t old_memory_pool_count = memory.count;
593
- do {
594
- TEST_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
595
- TEST_ASSERT(!((uintptr_t)mem & 15),
596
- "fio_malloc memory not aligned at allocation #%zu!\n", count);
597
- TEST_ASSERT((((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16),
598
- "fio_malloc memory indicates system allocation!\n");
599
- #if __x86_64__
600
- fio_memcpy((size_t *)mem, (size_t *)"0123456789abcdefg", 1);
601
- #else
602
- mem[0] = 'a';
603
- #endif
604
- fio_free(mem); /* make sure we hold on to the block, so it rotates */
605
- mem = fio_malloc(1);
606
- ++count;
607
- } while (arena_last_used->block == b);
608
- {
609
- fprintf(
610
- stderr,
611
- "* Performed %zu allocations out of expected %zu allocations per "
612
- "block.\n",
613
- count,
614
- (size_t)((FIO_MEMORY_BLOCK_SLICES - 2) - (sizeof(block_s) >> 4) - 1));
615
- TEST_ASSERT(memory.available,
616
- "memory pool empty (memory block wasn't freed)!\n");
617
- TEST_ASSERT(old_memory_pool_count == memory.count,
618
- "memory.count == %ld (memory block not counted)!\n",
619
- (long)old_memory_pool_count);
620
- fio_free(mem);
621
- }
622
- /* rotate block again */
623
- b = arena_last_used->block;
624
- mem = fio_realloc(mem, 1);
625
- do {
626
- mem2 = mem;
627
- mem = fio_malloc(1);
628
- fio_free(mem2); /* make sure we hold on to the block, so it rotates */
629
- TEST_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
630
- TEST_ASSERT(!((uintptr_t)mem & 15),
631
- "fio_malloc memory not aligned at allocation #%zu!\n", count);
632
- TEST_ASSERT((((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16),
633
- "fio_malloc memory indicates system allocation!\n");
634
- #if __x86_64__
635
- fio_memcpy((size_t *)mem, (size_t *)"0123456789abcdefg", 1);
636
- #else
637
- mem[0] = 'a';
638
- #endif
639
- ++count;
640
- } while (arena_last_used->block == b);
641
-
642
- mem = fio_calloc(FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64, 1);
643
- TEST_ASSERT(mem,
644
- "failed to allocate FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64 bytes!\n");
645
- TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16,
646
- "fio_calloc (under limit) memory alignment error!\n");
647
- mem2 = fio_malloc(1);
648
- TEST_ASSERT(mem2, "fio_malloc(1) failed to allocate memory!\n");
649
- mem2[0] = 'a';
650
-
651
- for (uintptr_t i = 0; i < (FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64); ++i) {
652
- TEST_ASSERT(mem[i] == 0,
653
- "calloc returned memory that wasn't initialized?!\n");
654
- }
655
- fio_free(mem);
656
-
657
- mem = fio_malloc(FIO_MEMORY_BLOCK_SIZE);
658
- TEST_ASSERT(mem, "fio_malloc failed to FIO_MEMORY_BLOCK_SIZE bytes!\n");
659
- TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) == 16,
660
- "fio_malloc (big) memory isn't aligned!\n");
661
- mem = fio_realloc(mem, FIO_MEMORY_BLOCK_SIZE * 2);
662
- TEST_ASSERT(mem,
663
- "fio_realloc (big) failed on FIO_MEMORY_BLOCK_SIZE X2 bytes!\n");
664
- fio_free(mem);
665
- TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) == 16,
666
- "fio_realloc (big) memory isn't aligned!\n");
667
-
668
- fprintf(stderr, "* passed.\n");
669
- }
670
-
671
- #else
672
-
673
- void fio_malloc_test(void) {}
674
-
675
- #endif