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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Standalone-specific vmem routines 29 * 30 * The standalone allocator operates on a pre-existing blob of memory, the 31 * location and dimensions of which are set using vmem_stand_setsize(). We 32 * then hand out CHUNKSIZE-sized pieces of this blob, until we run out. 33 */ 34 35 #define DEF_CHUNKSIZE (64 * 1024) /* 64K */ 36 37 #define DEF_NREGIONS 2 38 39 #include <errno.h> 40 #include <limits.h> 41 #include <sys/sysmacros.h> 42 #include <sys/mman.h> 43 #include <unistd.h> 44 #include <strings.h> 45 46 #include "vmem_base.h" 47 #include "misc.h" 48 49 static vmem_t *stand_heap; 50 51 static size_t stand_chunksize; 52 53 typedef struct stand_region { 54 caddr_t sr_base; 55 caddr_t sr_curtop; 56 size_t sr_left; 57 } stand_region_t; 58 59 static stand_region_t stand_regions[DEF_NREGIONS]; 60 static int stand_nregions; 61 62 extern void membar_producer(void); 63 64 void 65 vmem_stand_init(void) 66 { 67 stand_chunksize = MAX(DEF_CHUNKSIZE, pagesize); 68 69 stand_nregions = 0; 70 } 71 72 int 73 vmem_stand_add(caddr_t base, size_t len) 74 { 75 stand_region_t *sr = &stand_regions[stand_nregions]; 76 77 ASSERT(pagesize != 0); 78 79 if (stand_nregions == DEF_NREGIONS) { 80 errno = ENOSPC; 81 return (-1); /* we don't have room -- throw it back */ 82 } 83 84 /* 85 * We guarantee that only one call to `vmem_stand_add' will be 86 * active at a time, but we can't ensure that the allocator won't be 87 * in use while this function is being called. As such, we have to 88 * ensure that sr is populated and visible to other processors before 89 * allowing the allocator to access the new region. 90 */ 91 sr->sr_base = base; 92 sr->sr_curtop = (caddr_t)P2ROUNDUP((ulong_t)base, stand_chunksize); 93 sr->sr_left = P2ALIGN(len - (size_t)(sr->sr_curtop - sr->sr_base), 94 stand_chunksize); 95 membar_producer(); 96 97 stand_nregions++; 98 99 return (0); 100 } 101 102 static void * 103 stand_parent_alloc(vmem_t *src, size_t size, int vmflags) 104 { 105 int old_errno = errno; 106 stand_region_t *sr; 107 size_t chksize; 108 void *ret; 109 int i; 110 111 if ((ret = vmem_alloc(src, size, VM_NOSLEEP)) != NULL) { 112 errno = old_errno; 113 return (ret); 114 } 115 116 /* We need to allocate another chunk */ 117 chksize = roundup(size, stand_chunksize); 118 119 for (sr = stand_regions, i = 0; i < stand_nregions; i++, sr++) { 120 if (sr->sr_left >= chksize) 121 break; 122 } 123 124 if (i == stand_nregions) { 125 /* 126 * We don't have enough in any of our regions to satisfy the 127 * request. 128 */ 129 errno = old_errno; 130 return (NULL); 131 } 132 133 if ((ret = _vmem_extend_alloc(src, sr->sr_curtop, chksize, size, 134 vmflags)) == NULL) { 135 errno = old_errno; 136 return (NULL); 137 } 138 139 bzero(sr->sr_curtop, chksize); 140 141 sr->sr_curtop += chksize; 142 sr->sr_left -= chksize; 143 144 return (ret); 145 } 146 147 vmem_t * 148 vmem_stand_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 149 { 150 ASSERT(stand_nregions == 1); 151 152 stand_heap = vmem_init("stand_parent", stand_chunksize, 153 stand_parent_alloc, vmem_free, 154 "stand_heap", NULL, 0, pagesize, vmem_alloc, vmem_free); 155 156 if (a_out != NULL) 157 *a_out = vmem_alloc; 158 if (f_out != NULL) 159 *f_out = vmem_free; 160 161 return (stand_heap); 162 } 163