iodine 0.4.19 → 0.5.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +22 -0
- data/LIMITS.md +19 -9
- data/README.md +92 -77
- data/SPEC-PubSub-Draft.md +113 -0
- data/SPEC-Websocket-Draft.md +127 -143
- data/bin/http-hello +0 -1
- data/bin/raw-rbhttp +1 -1
- data/bin/raw_broadcast +8 -10
- data/bin/updated api +2 -2
- data/bin/ws-broadcast +2 -4
- data/bin/ws-echo +2 -2
- data/examples/config.ru +13 -13
- data/examples/echo.ru +5 -6
- data/examples/hello.ru +2 -3
- data/examples/info.md +316 -0
- data/examples/pubsub_engine.ru +81 -0
- data/examples/redis.ru +9 -9
- data/examples/shootout.ru +45 -11
- data/ext/iodine/defer.c +194 -297
- data/ext/iodine/defer.h +61 -53
- data/ext/iodine/evio.c +0 -260
- data/ext/iodine/evio.h +50 -22
- data/ext/iodine/evio_callbacks.c +26 -0
- data/ext/iodine/evio_epoll.c +251 -0
- data/ext/iodine/evio_kqueue.c +193 -0
- data/ext/iodine/extconf.rb +1 -1
- data/ext/iodine/facil.c +1420 -542
- data/ext/iodine/facil.h +151 -64
- data/ext/iodine/fio_ary.h +418 -0
- data/ext/iodine/{base64.c → fio_base64.c} +33 -24
- data/ext/iodine/{base64.h → fio_base64.h} +6 -7
- data/ext/iodine/{fio_cli_helper.c → fio_cli.c} +77 -58
- data/ext/iodine/{fio_cli_helper.h → fio_cli.h} +9 -4
- data/ext/iodine/fio_hashmap.h +759 -0
- data/ext/iodine/fio_json_parser.h +651 -0
- data/ext/iodine/fio_llist.h +257 -0
- data/ext/iodine/fio_mem.c +672 -0
- data/ext/iodine/fio_mem.h +140 -0
- data/ext/iodine/fio_random.c +248 -0
- data/ext/iodine/{random.h → fio_random.h} +11 -14
- data/ext/iodine/{sha1.c → fio_sha1.c} +28 -24
- data/ext/iodine/{sha1.h → fio_sha1.h} +38 -16
- data/ext/iodine/{sha2.c → fio_sha2.c} +66 -49
- data/ext/iodine/{sha2.h → fio_sha2.h} +57 -26
- data/ext/iodine/{fiobj_internal.c → fio_siphash.c} +9 -90
- data/ext/iodine/fio_siphash.h +18 -0
- data/ext/iodine/fio_tmpfile.h +38 -0
- data/ext/iodine/fiobj.h +24 -7
- data/ext/iodine/fiobj4sock.h +23 -0
- data/ext/iodine/fiobj_ary.c +143 -226
- data/ext/iodine/fiobj_ary.h +17 -16
- data/ext/iodine/fiobj_data.c +1160 -0
- data/ext/iodine/fiobj_data.h +164 -0
- data/ext/iodine/fiobj_hash.c +298 -406
- data/ext/iodine/fiobj_hash.h +101 -54
- data/ext/iodine/fiobj_json.c +478 -601
- data/ext/iodine/fiobj_json.h +34 -9
- data/ext/iodine/fiobj_numbers.c +383 -51
- data/ext/iodine/fiobj_numbers.h +87 -11
- data/ext/iodine/fiobj_str.c +423 -184
- data/ext/iodine/fiobj_str.h +81 -32
- data/ext/iodine/fiobject.c +273 -522
- data/ext/iodine/fiobject.h +477 -112
- data/ext/iodine/http.c +2243 -83
- data/ext/iodine/http.h +842 -121
- data/ext/iodine/http1.c +810 -385
- data/ext/iodine/http1.h +16 -39
- data/ext/iodine/http1_parser.c +146 -74
- data/ext/iodine/http1_parser.h +15 -4
- data/ext/iodine/http_internal.c +1258 -0
- data/ext/iodine/http_internal.h +226 -0
- data/ext/iodine/http_mime_parser.h +341 -0
- data/ext/iodine/iodine.c +86 -68
- data/ext/iodine/iodine.h +26 -11
- data/ext/iodine/iodine_helpers.c +8 -7
- data/ext/iodine/iodine_http.c +487 -324
- data/ext/iodine/iodine_json.c +304 -0
- data/ext/iodine/iodine_json.h +6 -0
- data/ext/iodine/iodine_protocol.c +107 -45
- data/ext/iodine/iodine_pubsub.c +526 -225
- data/ext/iodine/iodine_pubsub.h +10 -0
- data/ext/iodine/iodine_websockets.c +268 -510
- data/ext/iodine/iodine_websockets.h +2 -4
- data/ext/iodine/pubsub.c +726 -432
- data/ext/iodine/pubsub.h +85 -103
- data/ext/iodine/rb-call.c +4 -4
- data/ext/iodine/rb-defer.c +46 -22
- data/ext/iodine/rb-fiobj2rb.h +117 -0
- data/ext/iodine/rb-rack-io.c +73 -238
- data/ext/iodine/rb-rack-io.h +2 -2
- data/ext/iodine/rb-registry.c +35 -93
- data/ext/iodine/rb-registry.h +1 -0
- data/ext/iodine/redis_engine.c +742 -304
- data/ext/iodine/redis_engine.h +42 -39
- data/ext/iodine/resp_parser.h +311 -0
- data/ext/iodine/sock.c +627 -490
- data/ext/iodine/sock.h +345 -297
- data/ext/iodine/spnlock.inc +15 -4
- data/ext/iodine/websocket_parser.h +16 -20
- data/ext/iodine/websockets.c +188 -257
- data/ext/iodine/websockets.h +24 -133
- data/lib/iodine.rb +52 -7
- data/lib/iodine/cli.rb +6 -24
- data/lib/iodine/json.rb +40 -0
- data/lib/iodine/version.rb +1 -1
- data/lib/iodine/websocket.rb +5 -3
- data/lib/rack/handler/iodine.rb +58 -13
- metadata +38 -48
- data/bin/ws-shootout +0 -107
- data/examples/broadcast.ru +0 -56
- data/ext/iodine/bscrypt-common.h +0 -116
- data/ext/iodine/bscrypt.h +0 -49
- data/ext/iodine/fio2resp.c +0 -60
- data/ext/iodine/fio2resp.h +0 -51
- data/ext/iodine/fio_dict.c +0 -446
- data/ext/iodine/fio_dict.h +0 -99
- data/ext/iodine/fio_hash_table.h +0 -370
- data/ext/iodine/fio_list.h +0 -111
- data/ext/iodine/fiobj_internal.h +0 -280
- data/ext/iodine/fiobj_primitives.c +0 -131
- data/ext/iodine/fiobj_primitives.h +0 -55
- data/ext/iodine/fiobj_sym.c +0 -135
- data/ext/iodine/fiobj_sym.h +0 -60
- data/ext/iodine/hex.c +0 -124
- data/ext/iodine/hex.h +0 -70
- data/ext/iodine/http1_request.c +0 -81
- data/ext/iodine/http1_request.h +0 -58
- data/ext/iodine/http1_response.c +0 -417
- data/ext/iodine/http1_response.h +0 -95
- data/ext/iodine/http_request.c +0 -111
- data/ext/iodine/http_request.h +0 -102
- data/ext/iodine/http_response.c +0 -1703
- data/ext/iodine/http_response.h +0 -250
- data/ext/iodine/misc.c +0 -182
- data/ext/iodine/misc.h +0 -74
- data/ext/iodine/random.c +0 -208
- data/ext/iodine/redis_connection.c +0 -278
- data/ext/iodine/redis_connection.h +0 -86
- data/ext/iodine/resp.c +0 -842
- data/ext/iodine/resp.h +0 -261
- data/ext/iodine/siphash.c +0 -154
- data/ext/iodine/siphash.h +0 -22
- data/ext/iodine/xor-crypt.c +0 -193
- data/ext/iodine/xor-crypt.h +0 -107
@@ -0,0 +1,257 @@
|
|
1
|
+
#ifndef H_FIO_SIMPLE_LIST_H
|
2
|
+
/*
|
3
|
+
Copyright: Boaz Segev, 2017-2018
|
4
|
+
License: MIT
|
5
|
+
*/
|
6
|
+
|
7
|
+
/* *****************************************************************************
|
8
|
+
Simple Linked List - Used for existing objects (not embeddable).
|
9
|
+
***************************************************************************** */
|
10
|
+
|
11
|
+
/**
|
12
|
+
This header includes all the internal rescources / data and types required to
|
13
|
+
create object types.
|
14
|
+
*/
|
15
|
+
#define H_FIO_SIMPLE_LIST_H
|
16
|
+
|
17
|
+
#ifndef _GNU_SOURCE
|
18
|
+
#define _GNU_SOURCE
|
19
|
+
#endif
|
20
|
+
|
21
|
+
#ifndef FIO_FUNC
|
22
|
+
#define FIO_FUNC static __attribute__((unused))
|
23
|
+
#endif
|
24
|
+
|
25
|
+
#include <errno.h>
|
26
|
+
#include <stdio.h>
|
27
|
+
#include <stdlib.h>
|
28
|
+
|
29
|
+
/* *****************************************************************************
|
30
|
+
Data Structure and Initialization.
|
31
|
+
***************************************************************************** */
|
32
|
+
|
33
|
+
/** an embeded linked list. */
|
34
|
+
typedef struct fio_ls_embd_s {
|
35
|
+
struct fio_ls_embd_s *prev;
|
36
|
+
struct fio_ls_embd_s *next;
|
37
|
+
} fio_ls_embd_s;
|
38
|
+
|
39
|
+
/** an independent linked list. */
|
40
|
+
typedef struct fio_ls_s {
|
41
|
+
struct fio_ls_s *prev;
|
42
|
+
struct fio_ls_s *next;
|
43
|
+
const void *obj;
|
44
|
+
} fio_ls_s;
|
45
|
+
|
46
|
+
#define FIO_LS_INIT(name) \
|
47
|
+
{ .next = &(name), .prev = &(name) }
|
48
|
+
|
49
|
+
/* *****************************************************************************
|
50
|
+
Independent List API
|
51
|
+
***************************************************************************** */
|
52
|
+
|
53
|
+
/** Adds an object to the list's head. */
|
54
|
+
FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj);
|
55
|
+
|
56
|
+
/** Adds an object to the list's tail. */
|
57
|
+
FIO_FUNC inline void fio_ls_unshift(fio_ls_s *pos, const void *obj);
|
58
|
+
|
59
|
+
/** Removes an object from the list's head. */
|
60
|
+
FIO_FUNC inline void *fio_ls_pop(fio_ls_s *list);
|
61
|
+
|
62
|
+
/** Removes an object from the list's tail. */
|
63
|
+
FIO_FUNC inline void *fio_ls_shift(fio_ls_s *list);
|
64
|
+
|
65
|
+
/** Removes a node from the list, returning the contained object. */
|
66
|
+
FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node);
|
67
|
+
|
68
|
+
/** Tests if the list is empty. */
|
69
|
+
FIO_FUNC inline int fio_ls_is_empty(fio_ls_s *list);
|
70
|
+
|
71
|
+
/** Tests if the list is NOT empty (contains any nodes). */
|
72
|
+
FIO_FUNC inline int fio_ls_any(fio_ls_s *list);
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Iterates through the list using a `for` loop.
|
76
|
+
*
|
77
|
+
* Access the data with `pos->obj` (`pos` can be named however you pleas..
|
78
|
+
*/
|
79
|
+
#define FIO_LS_FOR(list, pos)
|
80
|
+
|
81
|
+
/* *****************************************************************************
|
82
|
+
Embedded List API
|
83
|
+
***************************************************************************** */
|
84
|
+
|
85
|
+
/** Adds a node to the list's head. */
|
86
|
+
FIO_FUNC inline void fio_ls_embd_push(fio_ls_embd_s *dest, fio_ls_embd_s *node);
|
87
|
+
|
88
|
+
/** Adds a node to the list's tail. */
|
89
|
+
FIO_FUNC inline void fio_ls_embd_unshift(fio_ls_embd_s *dest,
|
90
|
+
fio_ls_embd_s *node);
|
91
|
+
|
92
|
+
/** Removes a node from the list's head. */
|
93
|
+
FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_pop(fio_ls_embd_s *list);
|
94
|
+
|
95
|
+
/** Removes a node from the list's tail. */
|
96
|
+
FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_shift(fio_ls_embd_s *list);
|
97
|
+
|
98
|
+
/** Removes a node from the containing node. */
|
99
|
+
FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_remove(fio_ls_embd_s *node);
|
100
|
+
|
101
|
+
/** Tests if the list is empty. */
|
102
|
+
FIO_FUNC inline int fio_ls_embd_is_empty(fio_ls_embd_s *list);
|
103
|
+
|
104
|
+
/** Tests if the list is NOT empty (contains any nodes). */
|
105
|
+
FIO_FUNC inline int fio_ls_embd_any(fio_ls_embd_s *list);
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Iterates through the list using a `for` loop.
|
109
|
+
*
|
110
|
+
* Access the data with `pos->obj` (`pos` can be named however you pleas..
|
111
|
+
*/
|
112
|
+
#define FIO_LS_EMBD_FOR(list, node)
|
113
|
+
|
114
|
+
/**
|
115
|
+
* Takes a list pointer `plist` and returns a pointer to it's container.
|
116
|
+
*
|
117
|
+
* This uses pointer offset calculations and can be used to calculate any
|
118
|
+
* struct's pointer (not just list containers) as an offset from a pointer of
|
119
|
+
* one of it's members.
|
120
|
+
*
|
121
|
+
* Very useful.
|
122
|
+
*/
|
123
|
+
#define FIO_LS_EMBD_OBJ(type, member, plist) \
|
124
|
+
((type *)((uintptr_t)(plist) - (uintptr_t)(&(((type *)0)->member))))
|
125
|
+
|
126
|
+
/* *****************************************************************************
|
127
|
+
Independent Implementation
|
128
|
+
***************************************************************************** */
|
129
|
+
|
130
|
+
/** Adds an object to the list's head. */
|
131
|
+
FIO_FUNC inline void fio_ls_push(fio_ls_s *pos, const void *obj) {
|
132
|
+
/* prepare item */
|
133
|
+
fio_ls_s *item = (fio_ls_s *)malloc(sizeof(*item));
|
134
|
+
if (!item) {
|
135
|
+
perror("ERROR: simple list couldn't allocate memory");
|
136
|
+
exit(errno);
|
137
|
+
}
|
138
|
+
*item = (fio_ls_s){.prev = pos, .next = pos->next, .obj = obj};
|
139
|
+
/* inject item */
|
140
|
+
pos->next->prev = item;
|
141
|
+
pos->next = item;
|
142
|
+
}
|
143
|
+
|
144
|
+
/** Adds an object to the list's tail. */
|
145
|
+
FIO_FUNC inline void fio_ls_unshift(fio_ls_s *pos, const void *obj) {
|
146
|
+
pos = pos->prev;
|
147
|
+
fio_ls_push(pos, obj);
|
148
|
+
}
|
149
|
+
|
150
|
+
/** Removes an object from the list's head. */
|
151
|
+
FIO_FUNC inline void *fio_ls_pop(fio_ls_s *list) {
|
152
|
+
if (list->next == list)
|
153
|
+
return NULL;
|
154
|
+
fio_ls_s *item = list->next;
|
155
|
+
const void *ret = item->obj;
|
156
|
+
list->next = item->next;
|
157
|
+
list->next->prev = list;
|
158
|
+
free(item);
|
159
|
+
return (void *)ret;
|
160
|
+
}
|
161
|
+
|
162
|
+
/** Removes an object from the list's tail. */
|
163
|
+
FIO_FUNC inline void *fio_ls_shift(fio_ls_s *list) {
|
164
|
+
if (list->prev == list)
|
165
|
+
return NULL;
|
166
|
+
fio_ls_s *item = list->prev;
|
167
|
+
const void *ret = item->obj;
|
168
|
+
list->prev = item->prev;
|
169
|
+
list->prev->next = list;
|
170
|
+
free(item);
|
171
|
+
return (void *)ret;
|
172
|
+
}
|
173
|
+
|
174
|
+
/** Removes an object from the containing node. */
|
175
|
+
FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node) {
|
176
|
+
const void *ret = node->obj;
|
177
|
+
node->next->prev = node->prev;
|
178
|
+
node->prev->next = node->next;
|
179
|
+
free(node);
|
180
|
+
return (void *)ret;
|
181
|
+
}
|
182
|
+
|
183
|
+
/** Tests if the list is empty. */
|
184
|
+
FIO_FUNC inline int fio_ls_is_empty(fio_ls_s *list) {
|
185
|
+
return list->next == list;
|
186
|
+
}
|
187
|
+
|
188
|
+
/** Tests if the list is NOT empty (contains any nodes). */
|
189
|
+
FIO_FUNC inline int fio_ls_any(fio_ls_s *list) { return list->next != list; }
|
190
|
+
|
191
|
+
#undef FIO_LS_FOR
|
192
|
+
#define FIO_LS_FOR(list, pos) \
|
193
|
+
for (fio_ls_s *pos = (list)->next; pos != (list); pos = pos->next)
|
194
|
+
|
195
|
+
/* *****************************************************************************
|
196
|
+
Embeded List Implementation
|
197
|
+
***************************************************************************** */
|
198
|
+
|
199
|
+
/** Adds a node to the list's head. */
|
200
|
+
FIO_FUNC inline void fio_ls_embd_push(fio_ls_embd_s *dest,
|
201
|
+
fio_ls_embd_s *node) {
|
202
|
+
node->next = dest->next;
|
203
|
+
node->prev = dest->next->prev;
|
204
|
+
dest->next->prev = node;
|
205
|
+
dest->next = node;
|
206
|
+
}
|
207
|
+
|
208
|
+
/** Adds a node to the list's tail. */
|
209
|
+
FIO_FUNC inline void fio_ls_embd_unshift(fio_ls_embd_s *dest,
|
210
|
+
fio_ls_embd_s *node) {
|
211
|
+
fio_ls_embd_push(dest->prev, node);
|
212
|
+
}
|
213
|
+
|
214
|
+
/** Removes a node from the list's head. */
|
215
|
+
FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_pop(fio_ls_embd_s *list) {
|
216
|
+
if (list->next == list)
|
217
|
+
return NULL;
|
218
|
+
fio_ls_embd_s *item = list->next;
|
219
|
+
list->next = item->next;
|
220
|
+
list->next->prev = list;
|
221
|
+
return item;
|
222
|
+
}
|
223
|
+
|
224
|
+
/** Removes a node from the list's tail. */
|
225
|
+
FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_shift(fio_ls_embd_s *list) {
|
226
|
+
if (list->prev == list)
|
227
|
+
return NULL;
|
228
|
+
fio_ls_embd_s *item = list->prev;
|
229
|
+
list->prev = item->prev;
|
230
|
+
list->prev->next = list;
|
231
|
+
return item;
|
232
|
+
}
|
233
|
+
|
234
|
+
/** Removes a node from the containing node. */
|
235
|
+
FIO_FUNC inline fio_ls_embd_s *fio_ls_embd_remove(fio_ls_embd_s *node) {
|
236
|
+
node->next->prev = node->prev;
|
237
|
+
node->prev->next = node->next;
|
238
|
+
return node;
|
239
|
+
}
|
240
|
+
|
241
|
+
/** Tests if the list is empty. */
|
242
|
+
FIO_FUNC inline int fio_ls_embd_is_empty(fio_ls_embd_s *list) {
|
243
|
+
return list->next == list;
|
244
|
+
}
|
245
|
+
|
246
|
+
/** Tests if the list is NOT empty (contains any nodes). */
|
247
|
+
FIO_FUNC inline int fio_ls_embd_any(fio_ls_embd_s *list) {
|
248
|
+
return list->next != list;
|
249
|
+
}
|
250
|
+
|
251
|
+
#undef FIO_LS_EMBD_FOR
|
252
|
+
#define FIO_LS_EMBD_FOR(list, node) \
|
253
|
+
for (fio_ls_embd_s *node = (list)->next; node != (list); node = node->next)
|
254
|
+
|
255
|
+
#undef FIO_FUNC
|
256
|
+
|
257
|
+
#endif
|
@@ -0,0 +1,672 @@
|
|
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 = mmap(
|
144
|
+
next_alloc, len, PROT_READ | PROT_WRITE | PROT_EXEC,
|
145
|
+
MAP_PRIVATE | MAP_ANONYMOUS | MAP_ALIGNED(FIO_MEMORY_BLOCK_SIZE), -1, 0);
|
146
|
+
#else
|
147
|
+
result = mmap(next_alloc, len, PROT_READ | PROT_WRITE | PROT_EXEC,
|
148
|
+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
149
|
+
#endif
|
150
|
+
if (result == MAP_FAILED)
|
151
|
+
return NULL;
|
152
|
+
if (((uintptr_t)result & FIO_MEMORY_BLOCK_MASK)) {
|
153
|
+
munmap(result, len);
|
154
|
+
result = mmap(NULL, len + FIO_MEMORY_BLOCK_SIZE,
|
155
|
+
PROT_READ | PROT_WRITE | PROT_EXEC,
|
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 = mmap((void *)((uintptr_t)mem + prev_len), new_len - prev_len,
|
184
|
+
PROT_READ | PROT_WRITE | PROT_EXEC,
|
185
|
+
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
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
|
+
*mem = size;
|
395
|
+
return (void *)(((uintptr_t)mem) + 16);
|
396
|
+
}
|
397
|
+
|
398
|
+
static inline void big_free(void *ptr) {
|
399
|
+
size_t *mem = (void *)(((uintptr_t)ptr) - 16);
|
400
|
+
sys_free(mem, *mem);
|
401
|
+
}
|
402
|
+
|
403
|
+
static inline void *big_realloc(void *ptr, size_t new_size) {
|
404
|
+
size_t *mem = (void *)(((uintptr_t)ptr) - 16);
|
405
|
+
new_size = sys_round_size(new_size + 16);
|
406
|
+
mem = sys_realloc(mem, *mem, new_size);
|
407
|
+
if (!mem)
|
408
|
+
return NULL;
|
409
|
+
*mem = new_size;
|
410
|
+
return (void *)(((uintptr_t)mem) + 16);
|
411
|
+
}
|
412
|
+
|
413
|
+
/* *****************************************************************************
|
414
|
+
Library Initialization (initialize arenas and allocate a block for each CPU)
|
415
|
+
***************************************************************************** */
|
416
|
+
|
417
|
+
static void __attribute__((constructor)) fio_mem_init(void) {
|
418
|
+
if (arenas)
|
419
|
+
return;
|
420
|
+
|
421
|
+
#ifdef _SC_NPROCESSORS_ONLN
|
422
|
+
ssize_t cpu_count = sysconf(_SC_NPROCESSORS_ONLN);
|
423
|
+
#else
|
424
|
+
#warning Dynamic CPU core count is unavailable - assuming 8 cores for memory allocation pools.
|
425
|
+
ssize_t cpu_count = 8; /* fallback */
|
426
|
+
#endif
|
427
|
+
memory.cores = cpu_count;
|
428
|
+
memory.count = 0 - (intptr_t)cpu_count;
|
429
|
+
arenas = big_alloc(sizeof(*arenas) * cpu_count);
|
430
|
+
if (!arenas) {
|
431
|
+
perror("FATAL ERROR: Couldn't initialize memory allocator");
|
432
|
+
exit(errno);
|
433
|
+
}
|
434
|
+
size_t pre_pool = cpu_count > 32 ? 32 : cpu_count;
|
435
|
+
for (size_t i = 0; i < pre_pool; ++i) {
|
436
|
+
void *block = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
|
437
|
+
if (block) {
|
438
|
+
block_init(block);
|
439
|
+
block_free(block);
|
440
|
+
}
|
441
|
+
}
|
442
|
+
}
|
443
|
+
|
444
|
+
static void __attribute__((destructor)) fio_mem_destroy(void) {
|
445
|
+
if (!arenas)
|
446
|
+
return;
|
447
|
+
|
448
|
+
arena_s *arena = arenas;
|
449
|
+
for (size_t i = 0; i < memory.cores; ++i) {
|
450
|
+
if (arena->block)
|
451
|
+
block_free(arena->block);
|
452
|
+
arena->block = NULL;
|
453
|
+
++arena;
|
454
|
+
}
|
455
|
+
while (memory.available) {
|
456
|
+
block_s *b = memory.available;
|
457
|
+
memory.available = *(block_s **)b;
|
458
|
+
sys_free(b, FIO_MEMORY_BLOCK_SIZE);
|
459
|
+
}
|
460
|
+
big_free(arenas);
|
461
|
+
arenas = NULL;
|
462
|
+
}
|
463
|
+
|
464
|
+
/* *****************************************************************************
|
465
|
+
Memory allocation / deacclocation API
|
466
|
+
***************************************************************************** */
|
467
|
+
|
468
|
+
void *fio_malloc(size_t size) {
|
469
|
+
if (!size)
|
470
|
+
return NULL;
|
471
|
+
if (size >= FIO_MEMORY_BLOCK_ALLOC_LIMIT) {
|
472
|
+
/* system allocation - must be block aligned */
|
473
|
+
return big_alloc(size);
|
474
|
+
}
|
475
|
+
/* ceiling for 16 byte alignement, translated to 16 byte units */
|
476
|
+
size = (size >> 4) + (!!(size & 15));
|
477
|
+
arena_enter();
|
478
|
+
void *mem = block_slice(size);
|
479
|
+
arena_exit();
|
480
|
+
return mem;
|
481
|
+
}
|
482
|
+
|
483
|
+
void *fio_calloc(size_t size, size_t count) {
|
484
|
+
return fio_malloc(size * count); // memory is pre-initialized by mmap or pool.
|
485
|
+
}
|
486
|
+
|
487
|
+
void fio_free(void *ptr) {
|
488
|
+
if (!ptr)
|
489
|
+
return;
|
490
|
+
if (((uintptr_t)ptr & FIO_MEMORY_BLOCK_MASK) == 16) {
|
491
|
+
/* big allocation - direct from the system */
|
492
|
+
big_free(ptr);
|
493
|
+
return;
|
494
|
+
}
|
495
|
+
/* allocated within block */
|
496
|
+
block_slice_free(ptr);
|
497
|
+
}
|
498
|
+
|
499
|
+
/**
|
500
|
+
* Re-allocates memory. An attept to avoid copying the data is made only for
|
501
|
+
* memory allocations larger than 64Kb.
|
502
|
+
*
|
503
|
+
* This variation is slightly faster as it might copy less data
|
504
|
+
*/
|
505
|
+
void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length) {
|
506
|
+
if (!ptr)
|
507
|
+
return fio_malloc(new_size);
|
508
|
+
if (((uintptr_t)ptr & FIO_MEMORY_BLOCK_MASK) == 16) {
|
509
|
+
/* big reallocation - direct from the system */
|
510
|
+
return big_realloc(ptr, new_size);
|
511
|
+
}
|
512
|
+
/* allocated within block - don't even try to expand the allocation */
|
513
|
+
/* ceiling for 16 byte alignement, translated to 16 byte units */
|
514
|
+
void *new_mem = fio_malloc(new_size);
|
515
|
+
if (!new_mem)
|
516
|
+
return NULL;
|
517
|
+
new_size = ((new_size >> 4) + (!!(new_size & 15)));
|
518
|
+
copy_length = ((copy_length >> 4) + (!!(copy_length & 15)));
|
519
|
+
// memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length) <<
|
520
|
+
// 4);
|
521
|
+
fio_memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length));
|
522
|
+
block_slice_free(ptr);
|
523
|
+
return new_mem;
|
524
|
+
}
|
525
|
+
|
526
|
+
void *fio_realloc(void *ptr, size_t new_size) {
|
527
|
+
const size_t max_old =
|
528
|
+
FIO_MEMORY_BLOCK_SIZE - ((uintptr_t)ptr & FIO_MEMORY_BLOCK_MASK);
|
529
|
+
return fio_realloc2(ptr, new_size, max_old);
|
530
|
+
}
|
531
|
+
|
532
|
+
/* *****************************************************************************
|
533
|
+
FIO_OVERRIDE_MALLOC - override glibc / library malloc
|
534
|
+
***************************************************************************** */
|
535
|
+
#if FIO_OVERRIDE_MALLOC
|
536
|
+
void *malloc(size_t size) { return fio_malloc(size); }
|
537
|
+
void *calloc(size_t size, size_t count) { return fio_calloc(size, count); }
|
538
|
+
void free(void *ptr) { fio_free(ptr); }
|
539
|
+
void *realloc(void *ptr, size_t new_size) { return fio_realloc(ptr, new_size); }
|
540
|
+
#endif
|
541
|
+
|
542
|
+
#endif
|
543
|
+
|
544
|
+
/* *****************************************************************************
|
545
|
+
Some Tests
|
546
|
+
***************************************************************************** */
|
547
|
+
|
548
|
+
#if DEBUG && !FIO_FORCE_MALLOC
|
549
|
+
|
550
|
+
void fio_malloc_test(void) {
|
551
|
+
#define TEST_ASSERT(cond, ...) \
|
552
|
+
if (!(cond)) { \
|
553
|
+
fprintf(stderr, "* " __VA_ARGS__); \
|
554
|
+
fprintf(stderr, "\nTesting failed.\n"); \
|
555
|
+
exit(-1); \
|
556
|
+
}
|
557
|
+
|
558
|
+
fprintf(stderr, "=== Testing facil.io memory allocator's system calls\n");
|
559
|
+
char *mem = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
|
560
|
+
TEST_ASSERT(mem, "sys_alloc failed to allocate memory!\n");
|
561
|
+
TEST_ASSERT(!((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK),
|
562
|
+
"Memory allocation not aligned to FIO_MEMORY_BLOCK_SIZE!");
|
563
|
+
mem[0] = 'a';
|
564
|
+
mem[FIO_MEMORY_BLOCK_SIZE - 1] = 'z';
|
565
|
+
fprintf(stderr, "* Testing reallocation from %p\n", (void *)mem);
|
566
|
+
char *mem2 =
|
567
|
+
sys_realloc(mem, FIO_MEMORY_BLOCK_SIZE, FIO_MEMORY_BLOCK_SIZE * 2);
|
568
|
+
if (mem == mem2)
|
569
|
+
fprintf(stderr, "* Performed system realloc without copy :-)\n");
|
570
|
+
TEST_ASSERT(mem2[0] = 'a' && mem2[FIO_MEMORY_BLOCK_SIZE - 1] == 'z',
|
571
|
+
"Reaclloc data was lost!");
|
572
|
+
sys_free(mem2, FIO_MEMORY_BLOCK_SIZE * 2);
|
573
|
+
fprintf(stderr, "=== Testing facil.io memory allocator's internal data.\n");
|
574
|
+
TEST_ASSERT(arenas, "Missing arena data - library not initialized!");
|
575
|
+
TEST_ASSERT(fio_malloc(0) == NULL, "fio_malloc 0 bytes should be NULL!\n");
|
576
|
+
fio_free(NULL); /* fio_free(NULL) shouldn't crash... */
|
577
|
+
mem = fio_malloc(1);
|
578
|
+
TEST_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
|
579
|
+
TEST_ASSERT(!((uintptr_t)mem & 15), "fio_malloc memory not aligned!\n");
|
580
|
+
TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16,
|
581
|
+
"small fio_malloc memory indicates system allocation!\n");
|
582
|
+
mem[0] = 'a';
|
583
|
+
TEST_ASSERT(mem[0] == 'a', "allocate memory wasn't written to!\n");
|
584
|
+
mem = fio_realloc(mem, 1);
|
585
|
+
TEST_ASSERT(mem[0] == 'a', "fio_realloc memory wasn't copied!\n");
|
586
|
+
TEST_ASSERT(arena_last_used, "arena_last_used wasn't initialized!\n");
|
587
|
+
block_s *b = arena_last_used->block;
|
588
|
+
size_t count = 2;
|
589
|
+
intptr_t old_memory_pool_count = memory.count;
|
590
|
+
do {
|
591
|
+
TEST_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
|
592
|
+
TEST_ASSERT(!((uintptr_t)mem & 15),
|
593
|
+
"fio_malloc memory not aligned at allocation #%zu!\n", count);
|
594
|
+
TEST_ASSERT((((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16),
|
595
|
+
"fio_malloc memory indicates system allocation!\n");
|
596
|
+
#if __x86_64__
|
597
|
+
fio_memcpy((size_t *)mem, (size_t *)"0123456789abcdefg", 1);
|
598
|
+
#else
|
599
|
+
mem[0] = 'a';
|
600
|
+
#endif
|
601
|
+
fio_free(mem); /* make sure we hold on to the block, so it rotates */
|
602
|
+
mem = fio_malloc(1);
|
603
|
+
++count;
|
604
|
+
} while (arena_last_used->block == b);
|
605
|
+
{
|
606
|
+
fprintf(
|
607
|
+
stderr,
|
608
|
+
"* Performed %zu allocations out of expected %zu allocations per "
|
609
|
+
"block.\n",
|
610
|
+
count,
|
611
|
+
(size_t)((FIO_MEMORY_BLOCK_SLICES - 2) - (sizeof(block_s) >> 4) - 1));
|
612
|
+
TEST_ASSERT(memory.available,
|
613
|
+
"memory pool empty (memory block wasn't freed)!\n");
|
614
|
+
TEST_ASSERT(old_memory_pool_count == memory.count,
|
615
|
+
"memory.count == %ld (memory block not counted)!\n",
|
616
|
+
(long)old_memory_pool_count);
|
617
|
+
fio_free(mem);
|
618
|
+
}
|
619
|
+
/* rotate block again */
|
620
|
+
b = arena_last_used->block;
|
621
|
+
mem = fio_realloc(mem, 1);
|
622
|
+
do {
|
623
|
+
mem2 = mem;
|
624
|
+
mem = fio_malloc(1);
|
625
|
+
fio_free(mem2); /* make sure we hold on to the block, so it rotates */
|
626
|
+
TEST_ASSERT(mem, "fio_malloc failed to allocate memory!\n");
|
627
|
+
TEST_ASSERT(!((uintptr_t)mem & 15),
|
628
|
+
"fio_malloc memory not aligned at allocation #%zu!\n", count);
|
629
|
+
TEST_ASSERT((((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16),
|
630
|
+
"fio_malloc memory indicates system allocation!\n");
|
631
|
+
#if __x86_64__
|
632
|
+
fio_memcpy((size_t *)mem, (size_t *)"0123456789abcdefg", 1);
|
633
|
+
#else
|
634
|
+
mem[0] = 'a';
|
635
|
+
#endif
|
636
|
+
++count;
|
637
|
+
} while (arena_last_used->block == b);
|
638
|
+
|
639
|
+
mem = fio_calloc(FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64, 1);
|
640
|
+
TEST_ASSERT(mem,
|
641
|
+
"failed to allocate FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64 bytes!\n");
|
642
|
+
TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16,
|
643
|
+
"fio_calloc (under limit) memory alignment error!\n");
|
644
|
+
mem2 = fio_malloc(1);
|
645
|
+
TEST_ASSERT(mem2, "fio_malloc(1) failed to allocate memory!\n");
|
646
|
+
mem2[0] = 'a';
|
647
|
+
|
648
|
+
for (uintptr_t i = 0; i < (FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64); ++i) {
|
649
|
+
TEST_ASSERT(mem[i] == 0,
|
650
|
+
"calloc returned memory that wasn't initialized?!\n");
|
651
|
+
}
|
652
|
+
fio_free(mem);
|
653
|
+
|
654
|
+
mem = fio_malloc(FIO_MEMORY_BLOCK_SIZE);
|
655
|
+
TEST_ASSERT(mem, "fio_malloc failed to FIO_MEMORY_BLOCK_SIZE bytes!\n");
|
656
|
+
TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) == 16,
|
657
|
+
"fio_malloc (big) memory isn't aligned!\n");
|
658
|
+
mem = fio_realloc(mem, FIO_MEMORY_BLOCK_SIZE * 2);
|
659
|
+
TEST_ASSERT(mem,
|
660
|
+
"fio_realloc (big) failed on FIO_MEMORY_BLOCK_SIZE X2 bytes!\n");
|
661
|
+
fio_free(mem);
|
662
|
+
TEST_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) == 16,
|
663
|
+
"fio_realloc (big) memory isn't aligned!\n");
|
664
|
+
|
665
|
+
fprintf(stderr, "* passed.\n");
|
666
|
+
}
|
667
|
+
|
668
|
+
#else
|
669
|
+
|
670
|
+
void fio_malloc_test(void) {}
|
671
|
+
|
672
|
+
#endif
|