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 #include <unistd.h> 28 #include <errno.h> 29 #include <sys/mman.h> 30 #include <sys/sysmacros.h> 31 #include "vmem_base.h" 32 33 #define ALLOC_PROT PROT_READ | PROT_WRITE | PROT_EXEC 34 #define FREE_PROT PROT_NONE 35 36 #define ALLOC_FLAGS MAP_PRIVATE | MAP_ANON 37 #define FREE_FLAGS MAP_PRIVATE | MAP_ANON | MAP_NORESERVE 38 39 #define CHUNKSIZE (64*1024) /* 64 kilobytes */ 40 41 static vmem_t *mmap_heap; 42 43 static void * 44 vmem_mmap_alloc(vmem_t *src, size_t size, int vmflags) 45 { 46 void *ret; 47 int old_errno = errno; 48 49 ret = vmem_alloc(src, size, vmflags); 50 if (ret != NULL && 51 mmap(ret, size, ALLOC_PROT, ALLOC_FLAGS | MAP_FIXED, -1, 0) == 52 MAP_FAILED) { 53 vmem_free(src, ret, size); 54 vmem_reap(); 55 56 ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 57 errno = old_errno; 58 return (NULL); 59 } 60 61 errno = old_errno; 62 return (ret); 63 } 64 65 static void 66 vmem_mmap_free(vmem_t *src, void *addr, size_t size) 67 { 68 int old_errno = errno; 69 (void) mmap(addr, size, FREE_PROT, FREE_FLAGS | MAP_FIXED, -1, 0); 70 vmem_free(src, addr, size); 71 errno = old_errno; 72 } 73 74 static void * 75 vmem_mmap_top_alloc(vmem_t *src, size_t size, int vmflags) 76 { 77 void *ret; 78 void *buf; 79 int old_errno = errno; 80 81 ret = vmem_alloc(src, size, VM_NOSLEEP); 82 83 if (ret) { 84 errno = old_errno; 85 return (ret); 86 } 87 /* 88 * Need to grow the heap 89 */ 90 buf = mmap((void *)CHUNKSIZE, size, FREE_PROT, FREE_FLAGS | MAP_ALIGN, 91 -1, 0); 92 93 if (buf != MAP_FAILED) { 94 ret = _vmem_extend_alloc(src, buf, size, size, vmflags); 95 if (ret != NULL) 96 return (ret); 97 else { 98 (void) munmap(buf, size); 99 errno = old_errno; 100 return (NULL); 101 } 102 } else { 103 /* 104 * Growing the heap failed. The allocation above will 105 * already have called umem_reap(). 106 */ 107 ASSERT((vmflags & VM_NOSLEEP) == VM_NOSLEEP); 108 109 errno = old_errno; 110 return (NULL); 111 } 112 } 113 114 vmem_t * 115 vmem_mmap_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 116 { 117 size_t pagesize = sysconf(_SC_PAGESIZE); 118 119 if (mmap_heap == NULL) { 120 mmap_heap = vmem_init("mmap_top", CHUNKSIZE, 121 vmem_mmap_top_alloc, vmem_free, 122 "mmap_heap", NULL, 0, pagesize, 123 vmem_mmap_alloc, vmem_mmap_free); 124 } 125 126 if (a_out != NULL) 127 *a_out = vmem_mmap_alloc; 128 if (f_out != NULL) 129 *f_out = vmem_mmap_free; 130 131 return (mmap_heap); 132 } 133