forked from nfs-ganesha/nfs-ganesha
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathabstract_mem.h
427 lines (380 loc) · 12.1 KB
/
abstract_mem.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
/*
*
*
* Copyright © Linux box Corporation, 2012
* Author: Adam C. Emerson <aemerson@linuxbox.com>
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* ---------------------------------------
*/
/**
* @file abstract_mem.h
* @author Adam C. Emerson <aemerson@linuxbox.com>
* @brief Abstract memory shims to allow swapping out allocators
*
* This file's purpose is to allow us to easily replace the memory
* allocator used by Ganesha. Further, it provides a pool abstraction
* that may be implemented in terms of the normal allocator that may
* be expanded at a later date. These are intended to be thin
* wrappers, but conditionally compiled trace information could be
* added.
*/
#ifndef ABSTRACT_MEM_H
#define ABSTRACT_MEM_H
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "log.h"
/**
* @page GeneralAllocator General Allocator Shim
*
* These functions provide an interface akin to the standard libc
* allocation functions. Currently they call the functions malloc,
* free, and so forth, with changes in functionality being provided by
* linking in alternate allocator libraries (tcmalloc and jemalloc, at
* present.) So long as the interface remains the same, these
* functions can be switched out using ifdef for versions that do more
* memory tracking or that call allocators with other names.
*/
/**
* @brief Allocate memory
*
* This function allocates a block of memory no less than the given
* size. The block of memory allocated must be released with gsh_free.
*
* This function aborts if no memory is available.
*
* @param[in] n Number of bytes to allocate
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return Pointer to a block of memory.
*/
static inline void *
gsh_malloc__(size_t n,
const char *file, int line, const char *function)
{
void *p = malloc(n);
fprintf(stderr, "%s %d: malloc %p %zu\n", function, line, p, n);
if (p == NULL) {
LogMallocFailure(file, line, function, "gsh_malloc");
abort();
}
return p;
}
#define gsh_malloc(n) gsh_malloc__(n, __FILE__, __LINE__, __func__)
/**
* @brief Allocate aligned memory
*
* This function allocates a block of memory to the given alignment.
* Failure may indicate either insufficient memory or an invalid
* alignment.
*
* @param[in] a Block alignment
* @param[in] n Number of bytes to allocate
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return Pointer to a block of memory or NULL.
*/
static inline void *
gsh_malloc_aligned__(size_t a, size_t n,
const char *file, int line, const char *function)
{
void *p;
#ifdef __APPLE__
p = valloc(n);
#else
if (posix_memalign(&p, a, n) != 0)
p = NULL;
#endif
if (p == NULL) {
LogMallocFailure(file, line, function, "gsh_malloc_aligned");
abort();
}
return p;
}
#define gsh_malloc_aligned(a, n) \
gsh_malloc_aligned__(a, n, __FILE__, __LINE__, __func__)
/**
* @brief Allocate zeroed memory
*
* This function allocates a block of memory that is guaranteed to be
* zeroed. The block of memory allocated must be released with gsh_free.
*
* This function aborts if no memory is available.
*
* @param[in] n Number of objects in block
* @param[in] s Size of object
*
* @return Pointer to a block of zeroed memory.
*/
static inline void *
gsh_calloc__(size_t n, size_t s,
const char *file, int line, const char *function)
{
void *p = calloc(n, s);
if (p == NULL) {
LogMallocFailure(file, line, function, "gsh_calloc");
abort();
}
return p;
}
#define gsh_calloc(n, s) gsh_calloc__(n, s, __FILE__, __LINE__, __func__)
/**
* @brief Resize a block of memory
*
* This function resizes the buffer indicated by the supplied pointer
* to the given size. The block may be moved in this process. On
* failure, the original block is retained at its original address.
*
* This function aborts if no memory is available to resize.
*
* @param[in] p Block of memory to resize
* @param[in] n New size
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return Pointer to the address of the resized block.
*/
static inline void *
gsh_realloc__(void *p, size_t n,
const char *file, int line, const char *function)
{
void *p2 = realloc(p, n);
if (n != 0 && p2 == NULL) {
LogMallocFailure(file, line, function, "gsh_realloc");
abort();
}
return p2;
}
#define gsh_realloc(p, n) gsh_realloc__(p, n, __FILE__, __LINE__, __func__)
/**
* @brief Duplicate a string to newly allocated memory
*
* This function allocates a new block of memory sufficient to contain
* the supplied string, then copies the string into that buffer.
*
* This function aborts if no memory is available.
*
* @param[in] s String to duplicate
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return Pointer to new copy of string.
*/
static inline char *
gsh_strdup__(const char *s, const char *file, int line, const char *function)
{
char *p = strdup(s);
fprintf(stderr, "%s %d: strdup %p\n", function, line, p);
if (p == NULL) {
LogMallocFailure(file, line, function, "gsh_strdup");
abort();
}
return p;
}
#define gsh_strdup(s) gsh_strdup__(s, __FILE__, __LINE__, __func__)
/**
* @brief Duplicate a string to newly allocated memory (bounded)
*
* This function allocates a new block of memory sufficient to contain
* the supplied string, then copies the string into that buffer.
*
* This function aborts if no memory is available.
*
* The returned copied value includes the terminating NUL.
*
* @param[in] s String to duplicate
* @param[in] length Size of the returned string shall be <= length+1
* @param[out] copied Number of bytes copied
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return Pointer to new copy of string.
*/
static inline char *
gsh_strldup__(const char *s, size_t length, size_t *copied,
const char *file, int line, const char *function)
{
char *p = (char *) gsh_malloc__(length+1, file, line, function);
if (p == NULL) {
LogMallocFailure(file, line, function, "gsh_strldup");
abort();
}
memcpy(p, s, length);
p[length] = '\0';
*copied = length + 1;
return p;
}
#define gsh_strldup(s, l, n) gsh_strldup__(s, l, n, __FILE__, __LINE__, \
__func__)
/**
* @brief Free a block of memory
*
* This function frees a block of memory allocated with gsh_malloc,
* gsh_malloc_aligned, gsh_calloc, gsh_realloc, or gsh_strdup.
*
* @param[in] p Block of memory to free.
*/
static inline void
gsh_free__(void *p, const char *file, int line, const char *function)
{
fprintf(stderr, "%s %d: free %p\n", function, line, p);
free(p);
}
#define gsh_free(p) gsh_free__(p, __FILE__, __LINE__, __func__)
/**
* @brief Free a block of memory with size
*
* This function exists to be passed to TIRPC when setting
* allocators. It should not be used by anyone else. New shim layers
* should not redefine it.
*
* @param[in] p Block of memory to free.
* @param[in] n Size of block (unused)
*/
static inline void
gsh_free_size(void *p, size_t n __attribute__ ((unused)))
{
free(p);
}
/**
* @brief Type representing a pool
*
* This type represents a memory pool. it should be treated, by all
* callers, as a completely abstract type. The pointer should only be
* stored or passed to pool functions. The pointer should never be
* referenced. No assumptions about the size of the pointed-to type
* should be made.
*
* This allows for flexible growth in the future.
*/
typedef struct pool {
char *name; /*< The name of the pool */
size_t object_size; /*< The size of the objects created */
} pool_t;
/**
* @brief Create a basic object pool
*
* This function creates a new object pool, given a name, object size,
* constructor and destructor.
*
* This particular implementation throws the name away, but other
* implementations that do tracking or keep counts of allocated or
* de-allocated objects will likely wish to use it in log messages.
*
* This initializer function is expected to abort if it fails.
*
* @param[in] name The name of this pool
* @param[in] object_size The size of objects to allocate
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return A pointer to the pool object. This pointer must not be
* dereferenced. It may be stored or supplied as an argument
* to the other pool functions. It must not be supplied as an
* argument to gsh_free, rather it must be disposed of with
* pool_destroy.
*/
static inline pool_t *
pool_basic_init__(const char *name, size_t object_size,
const char *file, int line, const char *function)
{
pool_t *pool = (pool_t *) gsh_malloc__(sizeof(pool_t), file, line,
function);
pool->object_size = object_size;
if (name)
pool->name = gsh_strdup__(name, file, line, function);
else
pool->name = NULL;
return pool;
}
#define pool_basic_init(name, object_size) \
pool_basic_init__(name, object_size, __FILE__, __LINE__, __func__)
/**
* @brief Destroy a memory pool
*
* This function destroys a memory pool. All objects must be returned
* to the pool before this function is called.
*
* @param[in] pool The pool to be destroyed.
*/
static inline void
pool_destroy(pool_t *pool)
{
gsh_free(pool->name);
gsh_free(pool);
}
/**
* @brief Allocate an object from a pool
*
* This function allocates a single object from the pool and returns a
* pointer to it. If a constructor was specified at pool creation, it
* is called on that pointer. This function must be thread safe. If
* the underlying pool abstraction requires a lock, this function must
* take and release it.
*
* This function returns void pointers. Programmers who wish for more
* type safety can easily create static inline wrappers (alloc_client
* or similar) to return pointers of a specific type (and omitting the
* pool parameter).
*
* This function aborts if no memory is available.
*
* @param[in] pool The pool from which to allocate
* @param[in] file Calling source file
* @param[in] line Calling source line
* @param[in] function Calling source function
*
* @return A pointer to the allocated pool item.
*/
static inline void *
pool_alloc__(pool_t *pool, const char *file, int line, const char *function)
{
return gsh_calloc__(1, pool->object_size, file, line, function);
}
#define pool_alloc(pool) \
pool_alloc__(pool, __FILE__, __LINE__, __func__)
/**
* @brief Return an entry to a pool
*
* This function returns a single object to the pool. If a destructor
* was defined at pool creation time, it is called before the object
* is freed. This function must be thread-safe. If the underlying
* pool abstract requires a lock, this function must take and release
* it.
*
* @param[in] pool Pool to which to return the object
* @param[in] object Object to return. This is a void pointer.
* Programmers wishing more type safety could create
* a static inline wrapper taking an object of a
* specific type (and omitting the pool parameter.)
*/
static inline void
pool_free(pool_t *pool, void *object)
{
gsh_free(object);
}
#endif /* ABSTRACT_MEM_H */