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 test_verbose; 18 19 struct kmem_cache { 20 pthread_mutex_t lock; 21 unsigned int size; 22 unsigned int align; 23 int nr_objs; 24 void *objs; 25 void (*ctor)(void *); 26 }; 27 28 void *kmem_cache_alloc(struct kmem_cache *cachep, int gfp) 29 { 30 void *p; 31 32 if (!(gfp & __GFP_DIRECT_RECLAIM)) 33 return NULL; 34 35 pthread_mutex_lock(&cachep->lock); 36 if (cachep->nr_objs) { 37 struct radix_tree_node *node = cachep->objs; 38 cachep->nr_objs--; 39 cachep->objs = node->parent; 40 pthread_mutex_unlock(&cachep->lock); 41 node->parent = NULL; 42 p = node; 43 } else { 44 pthread_mutex_unlock(&cachep->lock); 45 if (cachep->align) 46 posix_memalign(&p, cachep->align, cachep->size); 47 else 48 p = malloc(cachep->size); 49 if (cachep->ctor) 50 cachep->ctor(p); 51 else if (gfp & __GFP_ZERO) 52 memset(p, 0, cachep->size); 53 } 54 55 uatomic_inc(&nr_allocated); 56 if (kmalloc_verbose) 57 printf("Allocating %p from slab\n", p); 58 return p; 59 } 60 61 void kmem_cache_free(struct kmem_cache *cachep, void *objp) 62 { 63 assert(objp); 64 uatomic_dec(&nr_allocated); 65 if (kmalloc_verbose) 66 printf("Freeing %p to slab\n", objp); 67 pthread_mutex_lock(&cachep->lock); 68 if (cachep->nr_objs > 10 || cachep->align) { 69 memset(objp, POISON_FREE, cachep->size); 70 free(objp); 71 } else { 72 struct radix_tree_node *node = objp; 73 cachep->nr_objs++; 74 node->parent = cachep->objs; 75 cachep->objs = node; 76 } 77 pthread_mutex_unlock(&cachep->lock); 78 } 79 80 struct kmem_cache * 81 kmem_cache_create(const char *name, unsigned int size, unsigned int align, 82 unsigned int flags, void (*ctor)(void *)) 83 { 84 struct kmem_cache *ret = malloc(sizeof(*ret)); 85 86 pthread_mutex_init(&ret->lock, NULL); 87 ret->size = size; 88 ret->align = align; 89 ret->nr_objs = 0; 90 ret->objs = NULL; 91 ret->ctor = ctor; 92 return ret; 93 } 94