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