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