-
Notifications
You must be signed in to change notification settings - Fork 526
/
Copy pathfast_mblock.h
474 lines (413 loc) · 13.5 KB
/
fast_mblock.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
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
/*
* Copyright (c) 2020 YuQing <384681@qq.com>
*
* This program is free software: you can use, redistribute, and/or modify
* it under the terms of the Lesser GNU General Public License, version 3
* or later ("LGPL"), as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the Lesser GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
//fast_mblock.h
#ifndef _FAST_MBLOCK_H
#define _FAST_MBLOCK_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "common_define.h"
#include "fc_memory.h"
#include "logger.h"
/* following two macros for debug only */
/*
#define FAST_MBLOCK_MAGIC_CHECK 1
#define FAST_MBLOCK_MAGIC_NUMBER 1234567890
*/
#define FAST_MBLOCK_NAME_SIZE 32
#define FAST_MBLOCK_ORDER_BY_ALLOC_BYTES 1
#define FAST_MBLOCK_ORDER_BY_ELEMENT_SIZE 2
#define FAST_MBLOCK_ORDER_BY_USED_RATIO 3
enum fast_mblock_notify_type {
fast_mblock_notify_type_alloc,
fast_mblock_notify_type_reclaim,
};
/* free node chain */
struct fast_mblock_node
{
struct fast_mblock_node *next;
int offset; //trunk offset
int recycle_timestamp;
#ifdef FAST_MBLOCK_MAGIC_CHECK
int index;
int magic; //magic number
#endif
char data[0]; //the data buffer
};
/* malloc chain */
struct fast_mblock_malloc
{
int64_t ref_count; //refference count
int alloc_count; //allocated element count
int trunk_size; //trunk bytes
struct fast_mblock_malloc *prev;
struct fast_mblock_malloc *next;
};
struct fast_mblock_chain {
struct fast_mblock_node *head;
struct fast_mblock_node *tail;
};
/* call by alloc trunk */
typedef int (*fast_mblock_object_init_func)(void *element, void *args);
/* call by free trunk */
typedef void (*fast_mblock_object_destroy_func)(void *element, void *args);
typedef int (*fast_mblock_malloc_trunk_check_func)(
const int alloc_bytes, void *args);
typedef void (*fast_mblock_malloc_trunk_notify_func)(
const enum fast_mblock_notify_type type,
const struct fast_mblock_malloc *node, void *args);
struct fast_mblock_info
{
char name[FAST_MBLOCK_NAME_SIZE];
int element_size; //element size
int trunk_size; //trunk size
int instance_count; //instance count
int block_size;
int64_t element_total_count; //total element count
int64_t element_used_count; //used element count
int64_t delay_free_elements; //delay free element count
int64_t trunk_total_count; //total trunk count
int64_t trunk_used_count; //used trunk count
};
struct fast_mblock_trunks
{
struct fast_mblock_malloc head; //malloc chain to be freed
};
struct fast_mblock_object_callbacks {
fast_mblock_object_init_func init_func;
fast_mblock_object_destroy_func destroy_func;
void *args;
};
struct fast_mblock_trunk_callbacks
{
fast_mblock_malloc_trunk_check_func check_func;
fast_mblock_malloc_trunk_notify_func notify_func;
void *args;
};
struct fast_mblock_man
{
struct fast_mblock_info info;
struct {
bool need_wait;
int exceed_log_level; //for exceed limit
int once; //alloc elements once
int64_t limit; //<= 0 for no limit
bool *pcontinue_flag;
} alloc_elements;
struct fast_mblock_node *free_chain_head; //free node chain
struct fast_mblock_trunks trunks;
struct fast_mblock_chain delay_free_chain; //delay free node chain
struct fast_mblock_object_callbacks object_callbacks;
struct fast_mblock_trunk_callbacks trunk_callbacks;
bool need_lock; //if need mutex lock
pthread_lock_cond_pair_t lcp; //for read / write free node chain
struct fast_mblock_man *prev; //for stat manager
struct fast_mblock_man *next; //for stat manager
};
#define fast_mblock_get_block_size(element_size) \
(MEM_ALIGN(sizeof(struct fast_mblock_node) + element_size))
#define fast_mblock_get_trunk_size(block_size, element_count) \
(sizeof(struct fast_mblock_malloc) + block_size * element_count)
#define fast_mblock_to_node_ptr(data_ptr) \
(struct fast_mblock_node *)((char *)data_ptr - ((size_t)(char *) \
&((struct fast_mblock_node *)0)->data))
#ifdef __cplusplus
extern "C" {
#endif
#define fast_mblock_init(mblock, element_size, alloc_elements_once) \
fast_mblock_init_ex(mblock, element_size, alloc_elements_once, \
0, NULL, NULL, true)
/**
mblock init
parameters:
name: the mblock name
mblock: the mblock pointer
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
prealloc_trunk_count: prealloc trunk node count
object_callbacks: the object callback functions and args
need_lock: if need lock
trunk_callbacks: the trunk callback functions and args
return error no, 0 for success, != 0 fail
*/
int fast_mblock_init_ex2(struct fast_mblock_man *mblock, const char *name,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit, const int prealloc_trunk_count,
struct fast_mblock_object_callbacks *object_callbacks,
const bool need_lock, struct fast_mblock_trunk_callbacks
*trunk_callbacks);
/**
mblock init
parameters:
name: the mblock name
mblock: the mblock pointer
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
init_func: the object init function
init_args: the args for object init function
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
static inline int fast_mblock_init_ex1(struct fast_mblock_man *mblock,
const char *name, const int element_size,
const int alloc_elements_once, const int64_t alloc_elements_limit,
fast_mblock_object_init_func init_func, void *init_args,
const bool need_lock)
{
const int prealloc_trunk_count = 0;
struct fast_mblock_object_callbacks object_callbacks;
object_callbacks.init_func = init_func;
object_callbacks.destroy_func = NULL;
object_callbacks.args = init_args;
return fast_mblock_init_ex2(mblock, name, element_size,
alloc_elements_once, alloc_elements_limit,
prealloc_trunk_count, &object_callbacks,
need_lock, NULL);
}
/**
mblock init
parameters:
mblock: the mblock pointer
element_size: element size, such as sizeof(struct xxx)
alloc_elements_once: malloc elements once, 0 for malloc 1MB memory once
alloc_elements_limit: malloc elements limit, <= 0 for no limit
object_callbacks: the object callback functions and args
need_lock: if need lock
return error no, 0 for success, != 0 fail
*/
static inline int fast_mblock_init_ex(struct fast_mblock_man *mblock,
const int element_size, const int alloc_elements_once,
const int64_t alloc_elements_limit, fast_mblock_object_init_func
init_func, void *init_args, const bool need_lock)
{
return fast_mblock_init_ex1(mblock, NULL, element_size,
alloc_elements_once, alloc_elements_limit,
init_func, init_args, need_lock);
}
/**
mblock destroy
parameters:
mblock: the mblock pointer
*/
void fast_mblock_destroy(struct fast_mblock_man *mblock);
static inline int fast_mblock_set_need_wait(struct fast_mblock_man *mblock,
const bool need_wait, bool * volatile pcontinue_flag)
{
if (!mblock->need_lock || mblock->alloc_elements.limit <= 0)
{
logError("file: "__FILE__", line: %d, "
"need_lock: %d != 1 or alloc_elements.limit: %"PRId64" <= 0",
__LINE__, mblock->need_lock, mblock->alloc_elements.limit);
return EINVAL;
}
mblock->alloc_elements.need_wait = need_wait;
mblock->alloc_elements.pcontinue_flag = pcontinue_flag;
if (need_wait)
{
mblock->alloc_elements.exceed_log_level = LOG_NOTHING;
}
return 0;
}
static inline void fast_mblock_set_exceed_log_level(
struct fast_mblock_man *mblock, const int log_level)
{
mblock->alloc_elements.exceed_log_level = log_level;
}
#define fast_mblock_set_exceed_silence(mblock) \
fast_mblock_set_exceed_log_level(mblock, LOG_NOTHING)
/**
alloc a node from the mblock
parameters:
mblock: the mblock pointer
return the alloced node, return NULL if fail
*/
struct fast_mblock_node *fast_mblock_alloc(struct fast_mblock_man *mblock);
/**
free a node (put a node to the mblock)
parameters:
mblock: the mblock pointer
pNode: the node to free
return 0 for success, return none zero if fail
*/
int fast_mblock_free(struct fast_mblock_man *mblock,
struct fast_mblock_node *pNode);
/**
batch alloc nodes from the mblock
parameters:
mblock: the mblock pointer
count: alloc count
chain: return the mblock node chain
return 0 for success, return none zero if fail
*/
int fast_mblock_batch_alloc(struct fast_mblock_man *mblock,
const int count, struct fast_mblock_chain *chain);
/**
batch alloc nodes from the mblock
parameters:
mblock: the mblock pointer
count: alloc count
return the alloced node head, return NULL if fail
*/
static inline struct fast_mblock_node *fast_mblock_batch_alloc1(
struct fast_mblock_man *mblock, const int count)
{
struct fast_mblock_chain chain;
if (fast_mblock_batch_alloc(mblock, count, &chain) == 0) {
return chain.head;
} else {
return NULL;
}
}
/**
batch free nodes
parameters:
mblock: the mblock pointer
chain: the node chain to free
return 0 for success, return none zero if fail
*/
int fast_mblock_batch_free(struct fast_mblock_man *mblock,
struct fast_mblock_chain *chain);
/**
delay free a node (put a node to the mblock)
parameters:
mblock: the mblock pointer
pNode: the node to free
delay: delay seconds to free
return 0 for success, return none zero if fail
*/
int fast_mblock_delay_free(struct fast_mblock_man *mblock,
struct fast_mblock_node *pNode, const int delay);
/**
alloc a object from the mblock
parameters:
mblock: the mblock pointer
return the alloced object, return NULL if fail
*/
static inline void *fast_mblock_alloc_object(struct fast_mblock_man *mblock)
{
struct fast_mblock_node *node;
node = fast_mblock_alloc(mblock);
if (node == NULL)
{
return NULL;
}
return node->data;
}
/**
free a object (put the object to the mblock)
parameters:
mblock: the mblock pointer
object: the object to free
return 0 for success, return none zero if fail
*/
static inline int fast_mblock_free_object(struct fast_mblock_man *mblock,
void *object)
{
return fast_mblock_free(mblock, fast_mblock_to_node_ptr(object));
}
/**
free objects (put objects to the mblock)
parameters:
mblock: the mblock pointer
objs: the object array to free
count: the count of the object array
return none
*/
void fast_mblock_free_objects(struct fast_mblock_man *mblock,
void **objs, const int count);
/**
delay free a object (put a node to the mblock)
parameters:
mblock: the mblock pointer
pNode: the node to free
delay: delay seconds to free
return 0 for success, return none zero if fail
*/
static inline int fast_mblock_delay_free_object(struct fast_mblock_man *mblock,
void *object, const int delay)
{
return fast_mblock_delay_free(mblock, fast_mblock_to_node_ptr(object), delay);
}
/**
get node count of the mblock
parameters:
mblock: the mblock pointer
return the free node count of the mblock, return -1 if fail
*/
int fast_mblock_free_count(struct fast_mblock_man *mblock);
/**
get delay free node count of the mblock
parameters:
mblock: the mblock pointer
return the delay free node count of the mblock, return -1 if fail
*/
int fast_mblock_delay_free_count(struct fast_mblock_man *mblock);
#define fast_mblock_total_count(mblock) (mblock)->total_count
/**
init mblock manager
parameters:
return error no, 0 for success, != 0 fail
*/
int fast_mblock_manager_init();
/**
get mblock stat
parameters:
stats: return mblock stats
size: max size of stats
count: return mblock stat count
return error no, 0 for success, != 0 fail
*/
int fast_mblock_manager_stat(struct fast_mblock_info *stats,
const int size, int *count);
/**
print mblock manager stat
parameters:
hide_empty: if hide empty
order_by: order by which field
return error no, 0 for success, != 0 fail
*/
int fast_mblock_manager_stat_print_ex(const bool hide_empty, const int order_by);
#define fast_mblock_manager_stat_print(hide_empty) \
fast_mblock_manager_stat_print_ex(hide_empty, FAST_MBLOCK_ORDER_BY_ALLOC_BYTES)
typedef void (*fast_mblock_free_trunks_func)(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *freelist);
/**
free the trunks
parameters:
mblock: the mblock pointer
freelist: the trunks to free
return error no, 0 for success, != 0 fail
*/
void fast_mblock_free_trunks(struct fast_mblock_man *mblock,
struct fast_mblock_malloc *freelist);
/**
reclaim the free trunks of the mblock
parameters:
mblock: the mblock pointer
reclaim_target: reclaim target trunks, 0 for no limit
reclaim_count: reclaimed trunk count
freelist: the free trunks
return error no, 0 for success, != 0 fail
*/
int fast_mblock_reclaim(struct fast_mblock_man *mblock,
const int reclaim_target, int *reclaim_count,
fast_mblock_free_trunks_func free_trunks_func);
#ifdef __cplusplus
}
#endif
#endif