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