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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <unistd.h> 30 #include <errno.h> 31 #include <sys/mman.h> 32 #include <sys/sysmacros.h> 33 #include "vmem_base.h" 34 35 #define ALLOC_PROT PROT_READ | PROT_WRITE | PROT_EXEC 36 #define FREE_PROT PROT_NONE 37 38 #define ALLOC_FLAGS MAP_PRIVATE | MAP_ANON 39 #define FREE_FLAGS MAP_PRIVATE | MAP_ANON | MAP_NORESERVE 40 41 #define CHUNKSIZE (64*1024) /* 64 kilobytes */ 42 43 static vmem_t *mmap_heap; 44 45 static void * 46 vmem_mmap_alloc(vmem_t *src, size_t size, int vmflags) 47 { 48 void *ret; 49 int old_errno = errno; 50 51 ret = vmem_alloc(src, size, vmflags); 52 if (ret != NULL && 53 mmap(ret, size, ALLOC_PROT, ALLOC_FLAGS | MAP_FIXED, -1, 0) == 54 MAP_FAILED) { 55 vmem_free(src, ret, size); 56 vmem_reap(); 57 58 ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 59 errno = old_errno; 60 return (NULL); 61 } 62 63 errno = old_errno; 64 return (ret); 65 } 66 67 static void 68 vmem_mmap_free(vmem_t *src, void *addr, size_t size) 69 { 70 int old_errno = errno; 71 (void) mmap(addr, size, FREE_PROT, FREE_FLAGS | MAP_FIXED, -1, 0); 72 vmem_free(src, addr, size); 73 errno = old_errno; 74 } 75 76 static void * 77 vmem_mmap_top_alloc(vmem_t *src, size_t size, int vmflags) 78 { 79 void *ret; 80 void *buf; 81 int old_errno = errno; 82 83 ret = vmem_alloc(src, size, VM_NOSLEEP); 84 85 if (ret) { 86 errno = old_errno; 87 return (ret); 88 } 89 /* 90 * Need to grow the heap 91 */ 92 buf = mmap((void *)CHUNKSIZE, size, FREE_PROT, FREE_FLAGS | MAP_ALIGN, 93 -1, 0); 94 95 if (buf != MAP_FAILED) { 96 ret = _vmem_extend_alloc(src, buf, size, size, vmflags); 97 if (ret != NULL) 98 return (ret); 99 else { 100 (void) munmap(buf, size); 101 errno = old_errno; 102 return (NULL); 103 } 104 } else { 105 /* 106 * Growing the heap failed. The allocation above will 107 * already have called umem_reap(). 108 */ 109 ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 110 111 errno = old_errno; 112 return (NULL); 113 } 114 } 115 116 vmem_t * 117 vmem_mmap_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 118 { 119 size_t pagesize = sysconf(_SC_PAGESIZE); 120 121 if (mmap_heap == NULL) { 122 mmap_heap = vmem_init("mmap_top", CHUNKSIZE, 123 vmem_mmap_top_alloc, vmem_free, 124 "mmap_heap", NULL, 0, pagesize, 125 vmem_mmap_alloc, vmem_mmap_free); 126 } 127 128 if (a_out != NULL) 129 *a_out = vmem_mmap_alloc; 130 if (f_out != NULL) 131 *f_out = vmem_mmap_free; 132 133 return (mmap_heap); 134 } 135