xref: /freebsd/sys/contrib/openzfs/lib/libspl/include/umem.h (revision 8ac904ce090b1c2e355da8aa122ca2252183f4e1)
1 // SPDX-License-Identifier: CDDL-1.0
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or https://opensource.org/licenses/CDDL-1.0.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 /*
24  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #ifndef _LIBSPL_UMEM_H
29 #define	_LIBSPL_UMEM_H
30 
31 /*
32  * XXX: We should use the real portable umem library if it is detected
33  * at configure time.  However, if the library is not available, we can
34  * use a trivial malloc based implementation.  This obviously impacts
35  * performance, but unless you are using a full userspace build of zpool for
36  * something other than ztest, you are likely not going to notice or care.
37  *
38  * https://labs.omniti.com/trac/portableumem
39  */
40 #include <sys/debug.h>
41 
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <string.h>
45 #include <errno.h>
46 
47 #ifdef  __cplusplus
48 extern "C" {
49 #endif
50 
51 typedef void vmem_t;
52 
53 /*
54  * Flags for umem_alloc/umem_free
55  */
56 #define	UMEM_DEFAULT		0x0000  /* normal -- may fail */
57 #define	UMEM_NOFAIL		0x0100  /* Never fails */
58 
59 /*
60  * Flags for umem_cache_create()
61  */
62 #define	UMC_NODEBUG		0x00020000
63 
64 #define	UMEM_CACHE_NAMELEN	31
65 
66 typedef int umem_nofail_callback_t(void);
67 typedef int umem_constructor_t(void *, void *, int);
68 typedef void umem_destructor_t(void *, void *);
69 typedef void umem_reclaim_t(void *);
70 
71 typedef struct umem_cache {
72 	char			cache_name[UMEM_CACHE_NAMELEN + 1];
73 	size_t			cache_bufsize;
74 	size_t			cache_align;
75 	umem_constructor_t	*cache_constructor;
76 	umem_destructor_t	*cache_destructor;
77 	umem_reclaim_t		*cache_reclaim;
78 	void			*cache_private;
79 	void			*cache_arena;
80 	int			cache_cflags;
81 } umem_cache_t;
82 
83 /* Prototypes for functions to provide defaults for umem envvars */
84 const char *_umem_debug_init(void);
85 const char *_umem_options_init(void);
86 const char *_umem_logging_init(void);
87 
88 __attribute__((malloc, alloc_size(1)))
89 static inline void *
umem_alloc(size_t size,int flags)90 umem_alloc(size_t size, int flags)
91 {
92 	void *ptr = NULL;
93 
94 	do {
95 		ptr = malloc(size);
96 	} while (ptr == NULL && (flags & UMEM_NOFAIL));
97 
98 	return (ptr);
99 }
100 
101 __attribute__((malloc, alloc_size(1)))
102 static inline void *
umem_alloc_aligned(size_t size,size_t align,int flags)103 umem_alloc_aligned(size_t size, size_t align, int flags)
104 {
105 	void *ptr = NULL;
106 	int rc;
107 
108 	do {
109 		rc = posix_memalign(&ptr, align, size);
110 	} while (rc == ENOMEM && (flags & UMEM_NOFAIL));
111 
112 	if (rc == EINVAL) {
113 		fprintf(stderr, "%s: invalid memory alignment (%zd)\n",
114 		    __func__, align);
115 		if (flags & UMEM_NOFAIL)
116 			abort();
117 		return (NULL);
118 	}
119 
120 	return (ptr);
121 }
122 
123 __attribute__((malloc, alloc_size(1)))
124 static inline void *
umem_zalloc(size_t size,int flags)125 umem_zalloc(size_t size, int flags)
126 {
127 	void *ptr = NULL;
128 
129 	ptr = umem_alloc(size, flags);
130 	if (ptr)
131 		memset(ptr, 0, size);
132 
133 	return (ptr);
134 }
135 
136 static inline void
umem_free(const void * ptr,size_t size __maybe_unused)137 umem_free(const void *ptr, size_t size __maybe_unused)
138 {
139 	free((void *)ptr);
140 }
141 
142 /*
143  * umem_free_aligned was added for supporting portability
144  * with non-POSIX platforms that require a different free
145  * to be used with aligned allocations.
146  */
147 static inline void
umem_free_aligned(void * ptr,size_t size __maybe_unused)148 umem_free_aligned(void *ptr, size_t size __maybe_unused)
149 {
150 #ifndef _WIN32
151 	free((void *)ptr);
152 #else
153 	_aligned_free(ptr);
154 #endif
155 }
156 
157 static inline void
umem_nofail_callback(umem_nofail_callback_t * cb __maybe_unused)158 umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused)
159 {}
160 
161 static inline umem_cache_t *
umem_cache_create(const char * name,size_t bufsize,size_t align,umem_constructor_t * constructor,umem_destructor_t * destructor,umem_reclaim_t * reclaim,void * priv,void * vmp,int cflags)162 umem_cache_create(
163     const char *name, size_t bufsize, size_t align,
164     umem_constructor_t *constructor,
165     umem_destructor_t *destructor,
166     umem_reclaim_t *reclaim,
167     void *priv, void *vmp, int cflags)
168 {
169 	umem_cache_t *cp;
170 
171 	cp = (umem_cache_t *)umem_alloc(sizeof (umem_cache_t), UMEM_DEFAULT);
172 	if (cp) {
173 		strlcpy(cp->cache_name, name, UMEM_CACHE_NAMELEN);
174 		cp->cache_bufsize = bufsize;
175 		cp->cache_align = align;
176 		cp->cache_constructor = constructor;
177 		cp->cache_destructor = destructor;
178 		cp->cache_reclaim = reclaim;
179 		cp->cache_private = priv;
180 		cp->cache_arena = vmp;
181 		cp->cache_cflags = cflags;
182 	}
183 
184 	return (cp);
185 }
186 
187 static inline void
umem_cache_destroy(umem_cache_t * cp)188 umem_cache_destroy(umem_cache_t *cp)
189 {
190 	umem_free(cp, sizeof (umem_cache_t));
191 }
192 
193 __attribute__((malloc))
194 static inline void *
umem_cache_alloc(umem_cache_t * cp,int flags)195 umem_cache_alloc(umem_cache_t *cp, int flags)
196 {
197 	void *ptr = NULL;
198 
199 	if (cp->cache_align != 0)
200 		ptr = umem_alloc_aligned(
201 		    cp->cache_bufsize, cp->cache_align, flags);
202 	else
203 		ptr = umem_alloc(cp->cache_bufsize, flags);
204 
205 	if (ptr && cp->cache_constructor)
206 		cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT);
207 
208 	return (ptr);
209 }
210 
211 static inline void
umem_cache_free(umem_cache_t * cp,void * ptr)212 umem_cache_free(umem_cache_t *cp, void *ptr)
213 {
214 	if (cp->cache_destructor)
215 		cp->cache_destructor(ptr, cp->cache_private);
216 
217 	if (cp->cache_align != 0)
218 		umem_free_aligned(ptr, cp->cache_bufsize);
219 	else
220 		umem_free(ptr, cp->cache_bufsize);
221 }
222 
223 static inline void
umem_cache_reap_now(umem_cache_t * cp __maybe_unused)224 umem_cache_reap_now(umem_cache_t *cp __maybe_unused)
225 {
226 }
227 
228 #ifdef  __cplusplus
229 }
230 #endif
231 
232 #endif
233