/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or https://opensource.org/licenses/CDDL-1.0. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LIBSPL_UMEM_H #define _LIBSPL_UMEM_H /* * XXX: We should use the real portable umem library if it is detected * at configure time. However, if the library is not available, we can * use a trivial malloc based implementation. This obviously impacts * performance, but unless you are using a full userspace build of zpool for * something other than ztest, you are likely not going to notice or care. * * https://labs.omniti.com/trac/portableumem */ #include #include #include #include #ifdef __cplusplus extern "C" { #endif typedef void vmem_t; /* * Flags for umem_alloc/umem_free */ #define UMEM_DEFAULT 0x0000 /* normal -- may fail */ #define UMEM_NOFAIL 0x0100 /* Never fails */ /* * Flags for umem_cache_create() */ #define UMC_NODEBUG 0x00020000 #define UMEM_CACHE_NAMELEN 31 typedef int umem_nofail_callback_t(void); typedef int umem_constructor_t(void *, void *, int); typedef void umem_destructor_t(void *, void *); typedef void umem_reclaim_t(void *); typedef struct umem_cache { char cache_name[UMEM_CACHE_NAMELEN + 1]; size_t cache_bufsize; size_t cache_align; umem_constructor_t *cache_constructor; umem_destructor_t *cache_destructor; umem_reclaim_t *cache_reclaim; void *cache_private; void *cache_arena; int cache_cflags; } umem_cache_t; /* Prototypes for functions to provide defaults for umem envvars */ const char *_umem_debug_init(void); const char *_umem_options_init(void); const char *_umem_logging_init(void); __attribute__((alloc_size(1))) static inline void * umem_alloc(size_t size, int flags) { void *ptr = NULL; do { ptr = malloc(size); } while (ptr == NULL && (flags & UMEM_NOFAIL)); return (ptr); } __attribute__((alloc_size(1))) static inline void * umem_alloc_aligned(size_t size, size_t align, int flags) { void *ptr = NULL; int rc = EINVAL; do { rc = posix_memalign(&ptr, align, size); } while (rc == ENOMEM && (flags & UMEM_NOFAIL)); if (rc == EINVAL) { fprintf(stderr, "%s: invalid memory alignment (%zd)\n", __func__, align); if (flags & UMEM_NOFAIL) abort(); return (NULL); } return (ptr); } __attribute__((alloc_size(1))) static inline void * umem_zalloc(size_t size, int flags) { void *ptr = NULL; ptr = umem_alloc(size, flags); if (ptr) memset(ptr, 0, size); return (ptr); } static inline void umem_free(const void *ptr, size_t size __maybe_unused) { free((void *)ptr); } /* * umem_free_aligned was added for supporting portability * with non-POSIX platforms that require a different free * to be used with aligned allocations. */ static inline void umem_free_aligned(void *ptr, size_t size __maybe_unused) { #ifndef _WIN32 free((void *)ptr); #else _aligned_free(ptr); #endif } static inline void umem_nofail_callback(umem_nofail_callback_t *cb __maybe_unused) {} 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) { umem_cache_t *cp; cp = (umem_cache_t *)umem_alloc(sizeof (umem_cache_t), UMEM_DEFAULT); if (cp) { strlcpy(cp->cache_name, name, UMEM_CACHE_NAMELEN); cp->cache_bufsize = bufsize; cp->cache_align = align; cp->cache_constructor = constructor; cp->cache_destructor = destructor; cp->cache_reclaim = reclaim; cp->cache_private = priv; cp->cache_arena = vmp; cp->cache_cflags = cflags; } return (cp); } static inline void umem_cache_destroy(umem_cache_t *cp) { umem_free(cp, sizeof (umem_cache_t)); } static inline void * umem_cache_alloc(umem_cache_t *cp, int flags) { void *ptr = NULL; if (cp->cache_align != 0) ptr = umem_alloc_aligned( cp->cache_bufsize, cp->cache_align, flags); else ptr = umem_alloc(cp->cache_bufsize, flags); if (ptr && cp->cache_constructor) cp->cache_constructor(ptr, cp->cache_private, UMEM_DEFAULT); return (ptr); } static inline void umem_cache_free(umem_cache_t *cp, void *ptr) { if (cp->cache_destructor) cp->cache_destructor(ptr, cp->cache_private); if (cp->cache_align != 0) umem_free_aligned(ptr, cp->cache_bufsize); else umem_free(ptr, cp->cache_bufsize); } static inline void umem_cache_reap_now(umem_cache_t *cp __maybe_unused) { } #ifdef __cplusplus } #endif #endif