1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate /* 27*7c478bd9Sstevel@tonic-gate * Copyright (c) 1991-1997,2000-2001 by Sun Microsystems, Inc. 28*7c478bd9Sstevel@tonic-gate * All rights reserved. 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" /* SVR4/MNLS 1.1.2.1 */ 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate /*LINTLIBRARY*/ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate /* 39*7c478bd9Sstevel@tonic-gate * Simplified version of malloc(), free() and realloc(), to be linked with 40*7c478bd9Sstevel@tonic-gate * utilities that use [s]brk() and do not define their own version of the 41*7c478bd9Sstevel@tonic-gate * routines. 42*7c478bd9Sstevel@tonic-gate * 43*7c478bd9Sstevel@tonic-gate * The algorithm used to get extra memory space by mmap'ing /dev/zero. This 44*7c478bd9Sstevel@tonic-gate * breaks if the application closes the open descriptor, so now it uses 45*7c478bd9Sstevel@tonic-gate * mmap's MAP_ANON feature. 46*7c478bd9Sstevel@tonic-gate * 47*7c478bd9Sstevel@tonic-gate * Each call to mmap() creates a page. The pages are linked in a list. 48*7c478bd9Sstevel@tonic-gate * Each page is divided in blocks. There is at least one block in a page. 49*7c478bd9Sstevel@tonic-gate * New memory chunks are allocated on a first-fit basis. 50*7c478bd9Sstevel@tonic-gate * Freed blocks are joined in larger blocks. Free pages are unmapped. 51*7c478bd9Sstevel@tonic-gate */ 52*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/mman.h> 55*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 56*7c478bd9Sstevel@tonic-gate #include <errno.h> 57*7c478bd9Sstevel@tonic-gate #include <unistd.h> 58*7c478bd9Sstevel@tonic-gate #include <thread.h> 59*7c478bd9Sstevel@tonic-gate #include <synch.h> 60*7c478bd9Sstevel@tonic-gate #include <string.h> 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #ifdef _REENTRANT 64*7c478bd9Sstevel@tonic-gate static mutex_t lock = DEFAULTMUTEX; 65*7c478bd9Sstevel@tonic-gate #endif /* _REENTRANT */ 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate struct block { 68*7c478bd9Sstevel@tonic-gate size_t size; /* Space available for user */ 69*7c478bd9Sstevel@tonic-gate struct page *page; /* Backwards reference to page */ 70*7c478bd9Sstevel@tonic-gate int status; 71*7c478bd9Sstevel@tonic-gate struct block *next; 72*7c478bd9Sstevel@tonic-gate void *memstart[1]; 73*7c478bd9Sstevel@tonic-gate }; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate struct page { 76*7c478bd9Sstevel@tonic-gate size_t size; /* Total page size (incl. header) */ 77*7c478bd9Sstevel@tonic-gate struct page *next; 78*7c478bd9Sstevel@tonic-gate struct block block[1]; 79*7c478bd9Sstevel@tonic-gate }; 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate #define FREE 0 82*7c478bd9Sstevel@tonic-gate #define BUSY 1 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate #define HDR_BLOCK (sizeof (struct block) - sizeof (void *)) 85*7c478bd9Sstevel@tonic-gate #define HDR_PAGE (sizeof (struct page) - sizeof (void *)) 86*7c478bd9Sstevel@tonic-gate #define MINSZ sizeof (double) 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* for convenience */ 89*7c478bd9Sstevel@tonic-gate #ifndef NULL 90*7c478bd9Sstevel@tonic-gate #define NULL (0) 91*7c478bd9Sstevel@tonic-gate #endif 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate struct page *memstart; 94*7c478bd9Sstevel@tonic-gate static int pagesize; 95*7c478bd9Sstevel@tonic-gate static void defrag(struct page *); 96*7c478bd9Sstevel@tonic-gate static void split(struct block *, size_t); 97*7c478bd9Sstevel@tonic-gate static void *malloc_unlocked(size_t); 98*7c478bd9Sstevel@tonic-gate static size_t align(size_t, int); 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate void * 101*7c478bd9Sstevel@tonic-gate malloc(size_t size) 102*7c478bd9Sstevel@tonic-gate { 103*7c478bd9Sstevel@tonic-gate void *retval; 104*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&lock); 105*7c478bd9Sstevel@tonic-gate retval = malloc_unlocked(size); 106*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lock); 107*7c478bd9Sstevel@tonic-gate return (retval); 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate 111*7c478bd9Sstevel@tonic-gate static void * 112*7c478bd9Sstevel@tonic-gate malloc_unlocked(size_t size) 113*7c478bd9Sstevel@tonic-gate { 114*7c478bd9Sstevel@tonic-gate struct block *block; 115*7c478bd9Sstevel@tonic-gate struct page *page; 116*7c478bd9Sstevel@tonic-gate 117*7c478bd9Sstevel@tonic-gate if (pagesize == 0) 118*7c478bd9Sstevel@tonic-gate pagesize = (int)sysconf(_SC_PAGESIZE); 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate size = align(size, MINSZ); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate /* 123*7c478bd9Sstevel@tonic-gate * Try to locate necessary space 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate for (page = memstart; page; page = page->next) { 126*7c478bd9Sstevel@tonic-gate for (block = page->block; block; block = block->next) { 127*7c478bd9Sstevel@tonic-gate if (block->status == FREE && block->size >= size) 128*7c478bd9Sstevel@tonic-gate goto found; 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate } 131*7c478bd9Sstevel@tonic-gate found: 132*7c478bd9Sstevel@tonic-gate 133*7c478bd9Sstevel@tonic-gate /* 134*7c478bd9Sstevel@tonic-gate * Need to allocate a new page 135*7c478bd9Sstevel@tonic-gate */ 136*7c478bd9Sstevel@tonic-gate if (!page) { 137*7c478bd9Sstevel@tonic-gate size_t totsize = size + HDR_PAGE; 138*7c478bd9Sstevel@tonic-gate size_t totpage = align(totsize, pagesize); 139*7c478bd9Sstevel@tonic-gate 140*7c478bd9Sstevel@tonic-gate if ((page = (struct page *)mmap(0, totpage, 141*7c478bd9Sstevel@tonic-gate PROT_READ|PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0)) 142*7c478bd9Sstevel@tonic-gate == MAP_FAILED) 143*7c478bd9Sstevel@tonic-gate return (0); 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate page->next = memstart; 146*7c478bd9Sstevel@tonic-gate memstart = page; 147*7c478bd9Sstevel@tonic-gate page->size = totpage; 148*7c478bd9Sstevel@tonic-gate block = page->block; 149*7c478bd9Sstevel@tonic-gate block->next = 0; 150*7c478bd9Sstevel@tonic-gate block->status = FREE; 151*7c478bd9Sstevel@tonic-gate block->size = totpage - HDR_PAGE; 152*7c478bd9Sstevel@tonic-gate block->page = page; 153*7c478bd9Sstevel@tonic-gate } 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate split(block, size); 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate block->status = BUSY; 158*7c478bd9Sstevel@tonic-gate return (&block->memstart); 159*7c478bd9Sstevel@tonic-gate } 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate void * 162*7c478bd9Sstevel@tonic-gate realloc(void *ptr, size_t size) 163*7c478bd9Sstevel@tonic-gate { 164*7c478bd9Sstevel@tonic-gate struct block *block; 165*7c478bd9Sstevel@tonic-gate size_t osize; 166*7c478bd9Sstevel@tonic-gate void *newptr; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&lock); 169*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 170*7c478bd9Sstevel@tonic-gate newptr = malloc_unlocked(size); 171*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lock); 172*7c478bd9Sstevel@tonic-gate return (newptr); 173*7c478bd9Sstevel@tonic-gate } 174*7c478bd9Sstevel@tonic-gate block = (struct block *)((char *)ptr - HDR_BLOCK); 175*7c478bd9Sstevel@tonic-gate size = align(size, MINSZ); 176*7c478bd9Sstevel@tonic-gate osize = block->size; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate /* 179*7c478bd9Sstevel@tonic-gate * Join block with next one if it is free 180*7c478bd9Sstevel@tonic-gate */ 181*7c478bd9Sstevel@tonic-gate if (block->next && block->next->status == FREE) { 182*7c478bd9Sstevel@tonic-gate block->size += block->next->size + HDR_BLOCK; 183*7c478bd9Sstevel@tonic-gate block->next = block->next->next; 184*7c478bd9Sstevel@tonic-gate } 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate if (size <= block->size) { 187*7c478bd9Sstevel@tonic-gate split(block, size); 188*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lock); 189*7c478bd9Sstevel@tonic-gate return (ptr); 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate newptr = malloc_unlocked(size); 193*7c478bd9Sstevel@tonic-gate (void) memcpy(newptr, ptr, osize); 194*7c478bd9Sstevel@tonic-gate block->status = FREE; 195*7c478bd9Sstevel@tonic-gate defrag(block->page); 196*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lock); 197*7c478bd9Sstevel@tonic-gate return (newptr); 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate void 201*7c478bd9Sstevel@tonic-gate free(void *ptr) 202*7c478bd9Sstevel@tonic-gate { 203*7c478bd9Sstevel@tonic-gate struct block *block; 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&lock); 206*7c478bd9Sstevel@tonic-gate if (ptr == NULL) { 207*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lock); 208*7c478bd9Sstevel@tonic-gate return; 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate block = (struct block *)((char *)ptr - HDR_BLOCK); 211*7c478bd9Sstevel@tonic-gate block->status = FREE; 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate defrag(block->page); 214*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&lock); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* 218*7c478bd9Sstevel@tonic-gate * Align size on an appropriate boundary 219*7c478bd9Sstevel@tonic-gate */ 220*7c478bd9Sstevel@tonic-gate static size_t 221*7c478bd9Sstevel@tonic-gate align(size_t size, int bound) 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate if (size < bound) 224*7c478bd9Sstevel@tonic-gate return ((size_t)bound); 225*7c478bd9Sstevel@tonic-gate else 226*7c478bd9Sstevel@tonic-gate return (size + bound - 1 - (size + bound - 1) % bound); 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate static void 230*7c478bd9Sstevel@tonic-gate split(struct block *block, size_t size) 231*7c478bd9Sstevel@tonic-gate { 232*7c478bd9Sstevel@tonic-gate if (block->size > size + sizeof (struct block)) { 233*7c478bd9Sstevel@tonic-gate struct block *newblock; 234*7c478bd9Sstevel@tonic-gate newblock = (struct block *)((char *)block + HDR_BLOCK + size); 235*7c478bd9Sstevel@tonic-gate newblock->next = block->next; 236*7c478bd9Sstevel@tonic-gate block->next = newblock; 237*7c478bd9Sstevel@tonic-gate newblock->status = FREE; 238*7c478bd9Sstevel@tonic-gate newblock->page = block->page; 239*7c478bd9Sstevel@tonic-gate newblock->size = block->size - size - HDR_BLOCK; 240*7c478bd9Sstevel@tonic-gate block->size = size; 241*7c478bd9Sstevel@tonic-gate } 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate 244*7c478bd9Sstevel@tonic-gate /* 245*7c478bd9Sstevel@tonic-gate * Defragmentation 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate static void 248*7c478bd9Sstevel@tonic-gate defrag(struct page *page) 249*7c478bd9Sstevel@tonic-gate { 250*7c478bd9Sstevel@tonic-gate struct block *block; 251*7c478bd9Sstevel@tonic-gate 252*7c478bd9Sstevel@tonic-gate for (block = page->block; block; block = block->next) { 253*7c478bd9Sstevel@tonic-gate struct block *block2; 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate if (block->status == BUSY) 256*7c478bd9Sstevel@tonic-gate continue; 257*7c478bd9Sstevel@tonic-gate for (block2 = block->next; block2 && block2->status == FREE; 258*7c478bd9Sstevel@tonic-gate block2 = block2->next) { 259*7c478bd9Sstevel@tonic-gate block->next = block2->next; 260*7c478bd9Sstevel@tonic-gate block->size += block2->size + HDR_BLOCK; 261*7c478bd9Sstevel@tonic-gate } 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate /* 265*7c478bd9Sstevel@tonic-gate * Free page 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate if (page->block->size == page->size - HDR_PAGE) { 268*7c478bd9Sstevel@tonic-gate if (page == memstart) 269*7c478bd9Sstevel@tonic-gate memstart = page->next; 270*7c478bd9Sstevel@tonic-gate else { 271*7c478bd9Sstevel@tonic-gate struct page *page2; 272*7c478bd9Sstevel@tonic-gate for (page2 = memstart; page2->next; 273*7c478bd9Sstevel@tonic-gate page2 = page2->next) { 274*7c478bd9Sstevel@tonic-gate if (page2->next == page) { 275*7c478bd9Sstevel@tonic-gate page2->next = page->next; 276*7c478bd9Sstevel@tonic-gate break; 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)page, page->size); 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate } 283