xref: /netbsd/external/cddl/osnet/sys/kern/kmem.c (revision 0bb8aa10)
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
solaris_constructor(void * private,void * object,int flag)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
solaris_destructor(void * private,void * object)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
solaris_reclaim(void * private,int flag)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 *
kmem_cache_create(char * name,size_t bufsize,size_t align,int (* constructor)(void *,void *,int),void (* destructor)(void *,void *),void (* reclaim)(void *)__unused,void * private,vmem_t * vmp,int flags)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
kmem_cache_destroy(kmem_cache_t * km)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 *
kmem_cache_alloc(kmem_cache_t * km,int flags)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
kmem_cache_free(kmem_cache_t * km,void * object)116 kmem_cache_free(kmem_cache_t *km, void *object)
117 {
118 
119 	pool_cache_put(km->km_pool, object);
120 }
121 
122 void
kmem_cache_reap_now(kmem_cache_t * km)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 *
solaris_kmem_alloc(size_t size,int flags)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 *
solaris_kmem_zalloc(size_t size,int flags)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
solaris_kmem_free(void * buf,size_t size)159 solaris_kmem_free(void *buf, size_t size)
160 {
161 
162 	if (buf == NULL)
163 		return;
164 	kmem_free(buf, size);
165 }
166