1 // SPDX-License-Identifier: GPL-2.0 2 #include <stdlib.h> 3 #include <string.h> 4 #include <malloc.h> 5 #include <pthread.h> 6 #include <unistd.h> 7 #include <assert.h> 8 9 #include <linux/gfp.h> 10 #include <linux/poison.h> 11 #include <linux/slab.h> 12 #include <linux/radix-tree.h> 13 #include <urcu/uatomic.h> 14 15 int nr_allocated; 16 int preempt_count; 17 int kmalloc_verbose; 18 int test_verbose; 19 20 struct kmem_cache { 21 pthread_mutex_t lock; 22 int size; 23 int nr_objs; 24 void *objs; 25 void (*ctor)(void *); 26 }; 27 28 void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) 29 { 30 struct radix_tree_node *node; 31 32 if (!(flags & __GFP_DIRECT_RECLAIM)) 33 return NULL; 34 35 pthread_mutex_lock(&cachep->lock); 36 if (cachep->nr_objs) { 37 cachep->nr_objs--; 38 node = cachep->objs; 39 cachep->objs = node->parent; 40 pthread_mutex_unlock(&cachep->lock); 41 node->parent = NULL; 42 } else { 43 pthread_mutex_unlock(&cachep->lock); 44 node = malloc(cachep->size); 45 if (cachep->ctor) 46 cachep->ctor(node); 47 } 48 49 uatomic_inc(&nr_allocated); 50 if (kmalloc_verbose) 51 printf("Allocating %p from slab\n", node); 52 return node; 53 } 54 55 void kmem_cache_free(struct kmem_cache *cachep, void *objp) 56 { 57 assert(objp); 58 uatomic_dec(&nr_allocated); 59 if (kmalloc_verbose) 60 printf("Freeing %p to slab\n", objp); 61 pthread_mutex_lock(&cachep->lock); 62 if (cachep->nr_objs > 10) { 63 memset(objp, POISON_FREE, cachep->size); 64 free(objp); 65 } else { 66 struct radix_tree_node *node = objp; 67 cachep->nr_objs++; 68 node->parent = cachep->objs; 69 cachep->objs = node; 70 } 71 pthread_mutex_unlock(&cachep->lock); 72 } 73 74 void *kmalloc(size_t size, gfp_t gfp) 75 { 76 void *ret; 77 78 if (!(gfp & __GFP_DIRECT_RECLAIM)) 79 return NULL; 80 81 ret = malloc(size); 82 uatomic_inc(&nr_allocated); 83 if (kmalloc_verbose) 84 printf("Allocating %p from malloc\n", ret); 85 if (gfp & __GFP_ZERO) 86 memset(ret, 0, size); 87 return ret; 88 } 89 90 void kfree(void *p) 91 { 92 if (!p) 93 return; 94 uatomic_dec(&nr_allocated); 95 if (kmalloc_verbose) 96 printf("Freeing %p to malloc\n", p); 97 free(p); 98 } 99 100 struct kmem_cache * 101 kmem_cache_create(const char *name, size_t size, size_t offset, 102 unsigned long flags, void (*ctor)(void *)) 103 { 104 struct kmem_cache *ret = malloc(sizeof(*ret)); 105 106 pthread_mutex_init(&ret->lock, NULL); 107 ret->size = size; 108 ret->nr_objs = 0; 109 ret->objs = NULL; 110 ret->ctor = ctor; 111 return ret; 112 } 113