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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Standalone-specific vmem routines 31 * 32 * The standalone allocator operates on a pre-existing blob of memory, the 33 * location and dimensions of which are set using vmem_stand_setsize(). We 34 * then hand out CHUNKSIZE-sized pieces of this blob, until we run out. 35 */ 36 37 #define DEF_CHUNKSIZE (64 * 1024) /* 64K */ 38 39 #define DEF_NREGIONS 2 40 41 #include <errno.h> 42 #include <limits.h> 43 #include <sys/sysmacros.h> 44 #include <sys/mman.h> 45 #include <unistd.h> 46 #include <strings.h> 47 48 #include "vmem_base.h" 49 #include "misc.h" 50 51 static vmem_t *stand_heap; 52 53 static size_t stand_chunksize; 54 55 typedef struct stand_region { 56 caddr_t sr_base; 57 caddr_t sr_curtop; 58 size_t sr_left; 59 } stand_region_t; 60 61 static stand_region_t stand_regions[DEF_NREGIONS]; 62 static int stand_nregions; 63 64 extern void membar_producer(void); 65 66 void 67 vmem_stand_init(void) 68 { 69 stand_chunksize = MAX(DEF_CHUNKSIZE, pagesize); 70 71 stand_nregions = 0; 72 } 73 74 int 75 vmem_stand_add(caddr_t base, size_t len) 76 { 77 stand_region_t *sr = &stand_regions[stand_nregions]; 78 79 ASSERT(pagesize != 0); 80 81 if (stand_nregions == DEF_NREGIONS) { 82 errno = ENOSPC; 83 return (-1); /* we don't have room -- throw it back */ 84 } 85 86 /* 87 * We guarantee that only one call to `vmem_stand_add' will be 88 * active at a time, but we can't ensure that the allocator won't be 89 * in use while this function is being called. As such, we have to 90 * ensure that sr is populated and visible to other processors before 91 * allowing the allocator to access the new region. 92 */ 93 sr->sr_base = base; 94 sr->sr_curtop = (caddr_t)P2ROUNDUP((ulong_t)base, stand_chunksize); 95 sr->sr_left = P2ALIGN(len - (size_t)(sr->sr_curtop - sr->sr_base), 96 stand_chunksize); 97 membar_producer(); 98 99 stand_nregions++; 100 101 return (0); 102 } 103 104 static void * 105 stand_parent_alloc(vmem_t *src, size_t size, int vmflags) 106 { 107 int old_errno = errno; 108 stand_region_t *sr; 109 size_t chksize; 110 void *ret; 111 int i; 112 113 if ((ret = vmem_alloc(src, size, VM_NOSLEEP)) != NULL) { 114 errno = old_errno; 115 return (ret); 116 } 117 118 /* We need to allocate another chunk */ 119 chksize = roundup(size, stand_chunksize); 120 121 for (sr = stand_regions, i = 0; i < stand_nregions; i++, sr++) { 122 if (sr->sr_left >= chksize) 123 break; 124 } 125 126 if (i == stand_nregions) { 127 /* 128 * We don't have enough in any of our regions to satisfy the 129 * request. 130 */ 131 errno = old_errno; 132 return (NULL); 133 } 134 135 if ((ret = _vmem_extend_alloc(src, sr->sr_curtop, chksize, size, 136 vmflags)) == NULL) { 137 errno = old_errno; 138 return (NULL); 139 } 140 141 bzero(sr->sr_curtop, chksize); 142 143 sr->sr_curtop += chksize; 144 sr->sr_left -= chksize; 145 146 return (ret); 147 } 148 149 vmem_t * 150 vmem_stand_arena(vmem_alloc_t **a_out, vmem_free_t **f_out) 151 { 152 ASSERT(stand_nregions == 1); 153 154 stand_heap = vmem_init("stand_parent", stand_chunksize, 155 stand_parent_alloc, vmem_free, 156 "stand_heap", NULL, 0, pagesize, vmem_alloc, vmem_free); 157 158 if (a_out != NULL) 159 *a_out = vmem_alloc; 160 if (f_out != NULL) 161 *f_out = vmem_free; 162 163 return (stand_heap); 164 } 165