| /* |
| * 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 http://www.opensolaris.org/os/licensing. |
| * 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 <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| |
| #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_NOTOUCH 0x00010000 |
| #define UMC_NODEBUG 0x00020000 |
| #define UMC_NOMAGAZINE 0x00040000 |
| #define UMC_NOHASH 0x00080000 |
| |
| #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; |
| |
| 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); |
| } |
| |
| 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); |
| } |
| |
| 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(void *ptr, size_t size) |
| { |
| free(ptr); |
| } |
| |
| static inline void |
| umem_nofail_callback(umem_nofail_callback_t *cb) |
| {} |
| |
| static inline umem_cache_t * |
| umem_cache_create( |
| 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_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); |
| |
| umem_free(ptr, cp->cache_bufsize); |
| } |
| |
| static inline void |
| umem_cache_reap_now(umem_cache_t *cp) |
| { |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif |