xref: /freebsd/sys/contrib/openzfs/lib/libspl/include/umem.h (revision 4e8d558c9d1cf3e7e424e3fb123b01979c3d57f2)
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 
86*4e8d558cSMartin Matuska __attribute__((malloc, alloc_size(1)))
87eda14cbcSMatt Macy static inline void *
umem_alloc(size_t size,int flags)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 
99*4e8d558cSMartin Matuska __attribute__((malloc, alloc_size(1)))
100eda14cbcSMatt Macy static inline void *
umem_alloc_aligned(size_t size,size_t align,int flags)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 
121*4e8d558cSMartin Matuska __attribute__((malloc, alloc_size(1)))
122eda14cbcSMatt Macy static inline void *
umem_zalloc(size_t size,int flags)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
umem_free(const void * ptr,size_t size __maybe_unused)135e92ffd9bSMartin Matuska umem_free(const void *ptr, size_t size __maybe_unused)
136eda14cbcSMatt Macy {
137e92ffd9bSMartin Matuska 	free((void *)ptr);
138eda14cbcSMatt Macy }
139eda14cbcSMatt Macy 
140dbd5678dSMartin Matuska /*
141dbd5678dSMartin Matuska  * umem_free_aligned was added for supporting portability
142dbd5678dSMartin Matuska  * with non-POSIX platforms that require a different free
143dbd5678dSMartin Matuska  * to be used with aligned allocations.
144dbd5678dSMartin Matuska  */
145dbd5678dSMartin Matuska static inline void
umem_free_aligned(void * ptr,size_t size __maybe_unused)146dbd5678dSMartin Matuska umem_free_aligned(void *ptr, size_t size __maybe_unused)
147dbd5678dSMartin Matuska {
148dbd5678dSMartin Matuska #ifndef _WIN32
149dbd5678dSMartin Matuska 	free((void *)ptr);
150dbd5678dSMartin Matuska #else
151dbd5678dSMartin Matuska 	_aligned_free(ptr);
152dbd5678dSMartin Matuska #endif
153dbd5678dSMartin Matuska }
154dbd5678dSMartin Matuska 
155eda14cbcSMatt Macy static inline void
umem_nofail_callback(umem_nofail_callback_t * cb __maybe_unused)156eda14cbcSMatt Macy umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused)
157eda14cbcSMatt Macy {}
158eda14cbcSMatt Macy 
159eda14cbcSMatt Macy 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)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
umem_cache_destroy(umem_cache_t * cp)186eda14cbcSMatt Macy umem_cache_destroy(umem_cache_t *cp)
187eda14cbcSMatt Macy {
188eda14cbcSMatt Macy 	umem_free(cp, sizeof (umem_cache_t));
189eda14cbcSMatt Macy }
190eda14cbcSMatt Macy 
191*4e8d558cSMartin Matuska __attribute__((malloc))
192eda14cbcSMatt Macy static inline void *
umem_cache_alloc(umem_cache_t * cp,int flags)193eda14cbcSMatt Macy umem_cache_alloc(umem_cache_t *cp, int flags)
194eda14cbcSMatt Macy {
195eda14cbcSMatt Macy 	void *ptr = NULL;
196eda14cbcSMatt Macy 
197eda14cbcSMatt Macy 	if (cp->cache_align != 0)
198eda14cbcSMatt Macy 		ptr = umem_alloc_aligned(
199eda14cbcSMatt Macy 		    cp->cache_bufsize, cp->cache_align, flags);
200eda14cbcSMatt Macy 	else
201eda14cbcSMatt Macy 		ptr = umem_alloc(cp->cache_bufsize, flags);
202eda14cbcSMatt Macy 
203eda14cbcSMatt Macy 	if (ptr && cp->cache_constructor)
204eda14cbcSMatt Macy 		cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT);
205eda14cbcSMatt Macy 
206eda14cbcSMatt Macy 	return (ptr);
207eda14cbcSMatt Macy }
208eda14cbcSMatt Macy 
209eda14cbcSMatt Macy static inline void
umem_cache_free(umem_cache_t * cp,void * ptr)210eda14cbcSMatt Macy umem_cache_free(umem_cache_t *cp, void *ptr)
211eda14cbcSMatt Macy {
212eda14cbcSMatt Macy 	if (cp->cache_destructor)
213eda14cbcSMatt Macy 		cp->cache_destructor(ptr, cp->cache_private);
214eda14cbcSMatt Macy 
215dbd5678dSMartin Matuska 	if (cp->cache_align != 0)
216dbd5678dSMartin Matuska 		umem_free_aligned(ptr, cp->cache_bufsize);
217dbd5678dSMartin Matuska 	else
218eda14cbcSMatt Macy 		umem_free(ptr, cp->cache_bufsize);
219eda14cbcSMatt Macy }
220eda14cbcSMatt Macy 
221eda14cbcSMatt Macy static inline void
umem_cache_reap_now(umem_cache_t * cp __maybe_unused)222eda14cbcSMatt Macy umem_cache_reap_now(umem_cache_t *cp __maybe_unused)
223eda14cbcSMatt Macy {
224eda14cbcSMatt Macy }
225eda14cbcSMatt Macy 
226eda14cbcSMatt Macy #ifdef  __cplusplus
227eda14cbcSMatt Macy }
228eda14cbcSMatt Macy #endif
229eda14cbcSMatt Macy 
230eda14cbcSMatt Macy #endif
231