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 static inline void * 87 umem_alloc(size_t size, int flags) 88 { 89 void *ptr = NULL; 90 91 do { 92 ptr = malloc(size); 93 } while (ptr == NULL && (flags & UMEM_NOFAIL)); 94 95 return (ptr); 96 } 97 98 static inline void * 99 umem_alloc_aligned(size_t size, size_t align, int flags) 100 { 101 void *ptr = NULL; 102 int rc = EINVAL; 103 104 do { 105 rc = posix_memalign(&ptr, align, size); 106 } while (rc == ENOMEM && (flags & UMEM_NOFAIL)); 107 108 if (rc == EINVAL) { 109 fprintf(stderr, "%s: invalid memory alignment (%zd)\n", 110 __func__, align); 111 if (flags & UMEM_NOFAIL) 112 abort(); 113 return (NULL); 114 } 115 116 return (ptr); 117 } 118 119 static inline void * 120 umem_zalloc(size_t size, int flags) 121 { 122 void *ptr = NULL; 123 124 ptr = umem_alloc(size, flags); 125 if (ptr) 126 memset(ptr, 0, size); 127 128 return (ptr); 129 } 130 131 static inline void 132 umem_free(const void *ptr, size_t size __maybe_unused) 133 { 134 free((void *)ptr); 135 } 136 137 static inline void 138 umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused) 139 {} 140 141 static inline umem_cache_t * 142 umem_cache_create( 143 const char *name, size_t bufsize, size_t align, 144 umem_constructor_t *constructor, 145 umem_destructor_t *destructor, 146 umem_reclaim_t *reclaim, 147 void *priv, void *vmp, int cflags) 148 { 149 umem_cache_t *cp; 150 151 cp = (umem_cache_t *)umem_alloc(sizeof (umem_cache_t), UMEM_DEFAULT); 152 if (cp) { 153 strlcpy(cp->cache_name, name, UMEM_CACHE_NAMELEN); 154 cp->cache_bufsize = bufsize; 155 cp->cache_align = align; 156 cp->cache_constructor = constructor; 157 cp->cache_destructor = destructor; 158 cp->cache_reclaim = reclaim; 159 cp->cache_private = priv; 160 cp->cache_arena = vmp; 161 cp->cache_cflags = cflags; 162 } 163 164 return (cp); 165 } 166 167 static inline void 168 umem_cache_destroy(umem_cache_t *cp) 169 { 170 umem_free(cp, sizeof (umem_cache_t)); 171 } 172 173 static inline void * 174 umem_cache_alloc(umem_cache_t *cp, int flags) 175 { 176 void *ptr = NULL; 177 178 if (cp->cache_align != 0) 179 ptr = umem_alloc_aligned( 180 cp->cache_bufsize, cp->cache_align, flags); 181 else 182 ptr = umem_alloc(cp->cache_bufsize, flags); 183 184 if (ptr && cp->cache_constructor) 185 cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT); 186 187 return (ptr); 188 } 189 190 static inline void 191 umem_cache_free(umem_cache_t *cp, void *ptr) 192 { 193 if (cp->cache_destructor) 194 cp->cache_destructor(ptr, cp->cache_private); 195 196 umem_free(ptr, cp->cache_bufsize); 197 } 198 199 static inline void 200 umem_cache_reap_now(umem_cache_t *cp __maybe_unused) 201 { 202 } 203 204 #ifdef __cplusplus 205 } 206 #endif 207 208 #endif 209