Home | History | Annotate | Line # | Download | only in kern
      1 /*	$NetBSD: kmem.c,v 1.4 2023/09/09 00:14:16 riastradh 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_reclaim(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