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_NOWARN) 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 = malloc(size); 77 uatomic_inc(&nr_allocated); 78 if (kmalloc_verbose) 79 printf("Allocating %p from malloc\n", ret); 80 return ret; 81 } 82 83 void kfree(void *p) 84 { 85 if (!p) 86 return; 87 uatomic_dec(&nr_allocated); 88 if (kmalloc_verbose) 89 printf("Freeing %p to malloc\n", p); 90 free(p); 91 } 92 93 struct kmem_cache * 94 kmem_cache_create(const char *name, size_t size, size_t offset, 95 unsigned long flags, void (*ctor)(void *)) 96 { 97 struct kmem_cache *ret = malloc(sizeof(*ret)); 98 99 pthread_mutex_init(&ret->lock, NULL); 100 ret->size = size; 101 ret->nr_objs = 0; 102 ret->objs = NULL; 103 ret->ctor = ctor; 104 return ret; 105 } 106