1 /*
2  * Copyright (C) 2021 Jakub Kruszona-Zawadzki, Core Technology Sp. z o.o.
3  *
4  * This file is part of MooseFS.
5  *
6  * MooseFS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, version 2 (only).
9  *
10  * MooseFS is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with MooseFS; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA
18  * or visit http://www.gnu.org/licenses/gpl-2.0.html
19  */
20 
21 #ifndef _BUCKETS_MT_H_
22 #define _BUCKETS_MT_H_
23 
24 #ifdef BUCKETS_MT_MMAP_ALLOC
25 #include <sys/mman.h>
26 #define BUCKETS_MT_ALLOC(size) mmap(NULL,size,PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,-1,0)
27 #define BUCKETS_MT_FREE(p,size) munmap(p,size)
28 #else
29 #define BUCKETS_MT_ALLOC(size) malloc(size)
30 #define BUCKETS_MT_FREE(p,size) free(p)
31 #endif
32 
33 #include <pthread.h>
34 #include <inttypes.h>
35 
36 #define CREATE_BUCKET_MT_ALLOCATOR(allocator_name,element_type,bucket_size) \
37 typedef struct _##allocator_name##_bucket { \
38 	element_type bucket[bucket_size]; \
39 	uint32_t firstfree; \
40 	struct _##allocator_name##_bucket *next; \
41 } allocator_name##_bucket; \
42 static allocator_name##_bucket *allocator_name##_buckets_head = NULL; \
43 static void *allocator_name##_free_head = NULL; \
44 static uint64_t allocator_name##_allocated = 0; \
45 static uint64_t allocator_name##_used = 0; \
46 static pthread_mutex_t allocator_name##_lock = PTHREAD_MUTEX_INITIALIZER; \
47 static inline void allocator_name##_free_all(void) { \
48 	allocator_name##_bucket *srb,*nsrb; \
49 	pthread_mutex_lock(&allocator_name##_lock); \
50 	for (srb = allocator_name##_buckets_head ; srb ; srb = nsrb) { \
51 		nsrb = srb->next; \
52 		BUCKETS_MT_FREE(srb,sizeof(allocator_name##_bucket)); \
53 	} \
54 	allocator_name##_buckets_head = NULL; \
55 	allocator_name##_free_head = NULL; \
56 	allocator_name##_allocated = 0; \
57 	allocator_name##_used = 0; \
58 	pthread_mutex_unlock(&allocator_name##_lock); \
59 } \
60 static inline element_type* allocator_name##_malloc() { \
61 	allocator_name##_bucket *srb; \
62 	element_type *ret; \
63 	pthread_mutex_lock(&allocator_name##_lock); \
64 	if (allocator_name##_free_head) { \
65 		ret = (element_type*)allocator_name##_free_head; \
66 		allocator_name##_free_head = *((void**)(ret)); \
67 		allocator_name##_used += sizeof(element_type); \
68 		pthread_mutex_unlock(&allocator_name##_lock); \
69 		return ret; \
70 	} \
71 	if (allocator_name##_buckets_head==NULL || allocator_name##_buckets_head->firstfree==(bucket_size)) { \
72 		srb = (allocator_name##_bucket*)BUCKETS_MT_ALLOC(sizeof(allocator_name##_bucket)); \
73 		passert(srb); \
74 		srb->next = allocator_name##_buckets_head; \
75 		srb->firstfree = 0; \
76 		allocator_name##_buckets_head = srb; \
77 		allocator_name##_allocated += sizeof(allocator_name##_bucket); \
78 	} \
79 	ret = (allocator_name##_buckets_head->bucket)+(allocator_name##_buckets_head->firstfree); \
80 	allocator_name##_buckets_head->firstfree++; \
81 	allocator_name##_used += sizeof(element_type); \
82 	pthread_mutex_unlock(&allocator_name##_lock); \
83 	return ret; \
84 } \
85 static inline void allocator_name##_free(element_type *p) { \
86 	pthread_mutex_lock(&allocator_name##_lock); \
87 	*((void**)p) = allocator_name##_free_head; \
88 	allocator_name##_free_head = (void*)p; \
89 	allocator_name##_used -= sizeof(element_type); \
90 	pthread_mutex_unlock(&allocator_name##_lock); \
91 } \
92 static inline void allocator_name##_getusage(uint64_t *allocated,uint64_t *used) { \
93 	pthread_mutex_lock(&allocator_name##_lock); \
94 	*allocated = allocator_name##_allocated ; \
95 	*used = allocator_name##_used ; \
96 	pthread_mutex_unlock(&allocator_name##_lock); \
97 }
98 
99 #endif
100