1 /* $NetBSD: kmem.c,v 1.3 2020/11/11 03:31:04 chs Exp $ */ 2 3 /*- 4 * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/kmem.h> 30 31 struct kmem_cache { 32 pool_cache_t km_pool; 33 char km_name[32]; 34 void *km_private; 35 int (*km_constructor)(void *, void *, int); 36 void (*km_destructor)(void *, void *); 37 void (*km_reclaim)(void *); 38 }; 39 40 static int 41 solaris_constructor(void *private, void *object, int flag) 42 { 43 kmem_cache_t *km = private; 44 45 if (km->km_constructor) 46 return (*km->km_constructor)(object, km->km_private, flag); 47 48 return 0; 49 } 50 51 static void 52 solaris_destructor(void *private, void *object) 53 { 54 kmem_cache_t *km = private; 55 56 if (km->km_destructor) 57 (*km->km_destructor)(object, km->km_private); 58 } 59 60 static void 61 solaris_reclaim(void *private, int flag) 62 { 63 64 kmem_cache_t *km = private; 65 66 if (km->km_reclaim) 67 (*km->km_reclaim)(km->km_private); 68 } 69 70 kmem_cache_t * 71 kmem_cache_create(char *name, size_t bufsize, size_t align, 72 int (*constructor)(void *, void *, int), void (*destructor)(void *, void *), 73 void (*reclaim)(void *) __unused, void *private, vmem_t *vmp, int flags) 74 { 75 kmem_cache_t *km; 76 77 KASSERT(ISSET(flags, ~(KMC_NOTOUCH | KMC_NODEBUG)) == 0); 78 KASSERT(private == NULL); 79 KASSERT(vmp == NULL); 80 81 km = kmem_zalloc(sizeof(*km), KM_SLEEP); 82 strlcpy(km->km_name, name, sizeof(km->km_name)); 83 km->km_private = private; 84 km->km_constructor = constructor; 85 km->km_destructor = destructor; 86 km->km_reclaim = reclaim; 87 km->km_pool = pool_cache_init(bufsize, align, 0, 0, km->km_name, NULL, 88 IPL_NONE, solaris_constructor, solaris_destructor, km); 89 if (km->km_pool == NULL) { 90 kmem_free(km, sizeof(*km)); 91 return NULL; 92 } 93 if (reclaim) 94 pool_cache_set_drain_hook(km->km_pool, solaris_reclaim, km); 95 96 return km; 97 } 98 void 99 kmem_cache_destroy(kmem_cache_t *km) 100 { 101 102 pool_cache_destroy(km->km_pool); 103 kmem_free(km, sizeof(*km)); 104 } 105 106 void * 107 kmem_cache_alloc(kmem_cache_t *km, int flags) 108 { 109 110 KASSERT(ISSET(flags, ~(KM_SLEEP | KM_NOSLEEP | KM_PUSHPAGE)) == 0); 111 112 return pool_cache_get(km->km_pool, flags); 113 } 114 115 void 116 kmem_cache_free(kmem_cache_t *km, void *object) 117 { 118 119 pool_cache_put(km->km_pool, object); 120 } 121 122 void 123 kmem_cache_reap_now(kmem_cache_t *km) 124 { 125 126 pool_cache_invalidate(km->km_pool); 127 } 128 129 #undef kmem_alloc 130 #undef kmem_zalloc 131 #undef kmem_free 132 133 /* 134 * Solaris allows allocating zero bytes (which returns NULL) 135 * and freeing a NULL pointer (which does nothing), 136 * so allow that here with wrappers around the native functions 137 * (which do not allow those things). 138 */ 139 140 void * 141 solaris_kmem_alloc(size_t size, int flags) 142 { 143 144 if (size == 0) 145 return NULL; 146 return kmem_alloc(size, flags); 147 } 148 149 void * 150 solaris_kmem_zalloc(size_t size, int flags) 151 { 152 153 if (size == 0) 154 return NULL; 155 return kmem_zalloc(size, flags); 156 } 157 158 void 159 solaris_kmem_free(void *buf, size_t size) 160 { 161 162 if (buf == NULL) 163 return; 164 kmem_free(buf, size); 165 } 166