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