17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*5d54f3d8Smuffin * Copyright 1986 Sun Microsystems, Inc. All rights reserved. 24*5d54f3d8Smuffin * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 27*5d54f3d8Smuffin #pragma ident "%Z%%M% %I% %E% SMI" 28*5d54f3d8Smuffin 297c478bd9Sstevel@tonic-gate /* 307c478bd9Sstevel@tonic-gate * file: malloc.c 317c478bd9Sstevel@tonic-gate * description: 327c478bd9Sstevel@tonic-gate * Yet another memory allocator, this one based on a method 337c478bd9Sstevel@tonic-gate * described in C.J. Stephenson, "Fast Fits" 347c478bd9Sstevel@tonic-gate * 357c478bd9Sstevel@tonic-gate * The basic data structure is a "Cartesian" binary tree, in which 367c478bd9Sstevel@tonic-gate * nodes are ordered by ascending addresses (thus minimizing free 377c478bd9Sstevel@tonic-gate * list insertion time) and block sizes decrease with depth in the 387c478bd9Sstevel@tonic-gate * tree (thus minimizing search time for a block of a given size). 397c478bd9Sstevel@tonic-gate * 407c478bd9Sstevel@tonic-gate * In other words: for any node s, let D(s) denote the set of 417c478bd9Sstevel@tonic-gate * descendents of s; for all x in D(left(s)) and all y in 427c478bd9Sstevel@tonic-gate * D(right(s)), we have: 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * a. addr(x) < addr(s) < addr(y) 457c478bd9Sstevel@tonic-gate * b. len(x) <= len(s) >= len(y) 467c478bd9Sstevel@tonic-gate */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate #include "mallint.h" 497c478bd9Sstevel@tonic-gate #include <errno.h> 50*5d54f3d8Smuffin #include <stdlib.h> 51*5d54f3d8Smuffin #include <stdarg.h> 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate /* system interface */ 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate extern char *sbrk(); 567c478bd9Sstevel@tonic-gate extern int getpagesize(); 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate static int nbpg = 0; /* set by calling getpagesize() */ 59*5d54f3d8Smuffin static bool morecore(uint); /* get more memory into free space */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #ifdef S5EMUL 627c478bd9Sstevel@tonic-gate #define ptr_t void * /* ANSI C says these are voids */ 637c478bd9Sstevel@tonic-gate #define free_t void /* ANSI says void free(ptr_t ptr) */ 647c478bd9Sstevel@tonic-gate #define free_return(x) return 657c478bd9Sstevel@tonic-gate #else 667c478bd9Sstevel@tonic-gate #define ptr_t char * /* BSD still (4.3) wants char*'s */ 677c478bd9Sstevel@tonic-gate #define free_t int /* BSD says int free(ptr_t ptr) */ 687c478bd9Sstevel@tonic-gate #define free_return(x) return(x) 697c478bd9Sstevel@tonic-gate #endif 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* SystemV-compatible information structure */ 727c478bd9Sstevel@tonic-gate #define INIT_MXFAST 0 737c478bd9Sstevel@tonic-gate #define INIT_NLBLKS 100 747c478bd9Sstevel@tonic-gate #define INIT_GRAIN ALIGNSIZ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate struct mallinfo __mallinfo = { 777c478bd9Sstevel@tonic-gate 0,0,0,0,0,0,0,0,0,0, /* basic info */ 787c478bd9Sstevel@tonic-gate INIT_MXFAST, INIT_NLBLKS, INIT_GRAIN, /* mallopt options */ 797c478bd9Sstevel@tonic-gate 0,0,0 807c478bd9Sstevel@tonic-gate }; 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* heap data structures */ 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate Freehdr _root = NIL; /* root of free space list */ 857c478bd9Sstevel@tonic-gate char *_lbound = NULL; /* lower bound of heap */ 867c478bd9Sstevel@tonic-gate char *_ubound = NULL; /* upper bound of heap */ 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* free header list management */ 897c478bd9Sstevel@tonic-gate 90*5d54f3d8Smuffin static Freehdr getfreehdr(void); 91*5d54f3d8Smuffin static void putfreehdr(Freehdr); 927c478bd9Sstevel@tonic-gate static Freehdr freehdrptr = NIL; /* ptr to block of available headers */ 937c478bd9Sstevel@tonic-gate static int nfreehdrs = 0; /* # of headers in current block */ 947c478bd9Sstevel@tonic-gate static Freehdr freehdrlist = NIL; /* List of available headers */ 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* error checking */ 97*5d54f3d8Smuffin static void error(char *, ...); 98*5d54f3d8Smuffin /* sets errno; prints msg and aborts if DEBUG is on */ 99*5d54f3d8Smuffin 100*5d54f3d8Smuffin static int reclaim(Dblk, uint, int); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate #ifdef DEBUG /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ 1037c478bd9Sstevel@tonic-gate 104*5d54f3d8Smuffin int malloc_debug(int); 105*5d54f3d8Smuffin int malloc_verify(void); 1067c478bd9Sstevel@tonic-gate static int debug_level = 1; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * A block with a negative size, a size that is not a multiple 1107c478bd9Sstevel@tonic-gate * of ALIGNSIZ, a size greater than the current extent of the 1117c478bd9Sstevel@tonic-gate * heap, or a size which extends beyond the end of the heap is 1127c478bd9Sstevel@tonic-gate * considered bad. 1137c478bd9Sstevel@tonic-gate */ 1147c478bd9Sstevel@tonic-gate 1157c478bd9Sstevel@tonic-gate #define badblksize(p,size)\ 1167c478bd9Sstevel@tonic-gate ( (size) < SMALLEST_BLK \ 1177c478bd9Sstevel@tonic-gate || (size) & (ALIGNSIZ-1) \ 1187c478bd9Sstevel@tonic-gate || (size) > heapsize() \ 1197c478bd9Sstevel@tonic-gate || ((char*)(p))+(size) > _ubound ) 1207c478bd9Sstevel@tonic-gate 121*5d54f3d8Smuffin #else /* !DEBUG ================================================= */ 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate #define malloc_debug(level) 0 1247c478bd9Sstevel@tonic-gate #define malloc_verify() 1 1257c478bd9Sstevel@tonic-gate #define debug_level 0 1267c478bd9Sstevel@tonic-gate #define badblksize(p,size) 0 1277c478bd9Sstevel@tonic-gate 128*5d54f3d8Smuffin #endif /* !DEBUG <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ 1297c478bd9Sstevel@tonic-gate 130*5d54f3d8Smuffin 1317c478bd9Sstevel@tonic-gate /* 1327c478bd9Sstevel@tonic-gate * insert (newblk, len) 1337c478bd9Sstevel@tonic-gate * Inserts a new node in the free space tree, placing it 1347c478bd9Sstevel@tonic-gate * in the correct position with respect to the existing nodes. 1357c478bd9Sstevel@tonic-gate * 1367c478bd9Sstevel@tonic-gate * algorithm: 1377c478bd9Sstevel@tonic-gate * Starting from the root, a binary search is made for the new 1387c478bd9Sstevel@tonic-gate * node. If this search were allowed to continue, it would 1397c478bd9Sstevel@tonic-gate * eventually fail (since there cannot already be a node at the 1407c478bd9Sstevel@tonic-gate * given address); but in fact it stops when it reaches a node in 1417c478bd9Sstevel@tonic-gate * the tree which has a length less than that of the new node (or 1427c478bd9Sstevel@tonic-gate * when it reaches a null tree pointer). 1437c478bd9Sstevel@tonic-gate * 1447c478bd9Sstevel@tonic-gate * The new node is then inserted at the root of the subtree for 1457c478bd9Sstevel@tonic-gate * which the shorter node forms the old root (or in place of the 1467c478bd9Sstevel@tonic-gate * null pointer). 147*5d54f3d8Smuffin * 148*5d54f3d8Smuffin * Arguments 149*5d54f3d8Smuffin * newblk: Ptr to the block to insert 150*5d54f3d8Smuffin * len: Length of new node 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate 153*5d54f3d8Smuffin static void 154*5d54f3d8Smuffin insert(Dblk newblk, uint len) 1557c478bd9Sstevel@tonic-gate { 156*5d54f3d8Smuffin Freehdr *fpp; /* Address of ptr to subtree */ 157*5d54f3d8Smuffin Freehdr x; 158*5d54f3d8Smuffin Freehdr *left_hook; /* Temp for insertion */ 159*5d54f3d8Smuffin Freehdr *right_hook; /* Temp for insertion */ 160*5d54f3d8Smuffin Freehdr newhdr; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * check for bad block size. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate if ( badblksize(newblk,len) ) { 1667c478bd9Sstevel@tonic-gate error("insert: bad block size (%d) at %#x\n", len, newblk); 1677c478bd9Sstevel@tonic-gate return; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * Search for the first node which has a weight less 1727c478bd9Sstevel@tonic-gate * than that of the new node; this will be the 1737c478bd9Sstevel@tonic-gate * point at which we insert the new node. 1747c478bd9Sstevel@tonic-gate */ 1757c478bd9Sstevel@tonic-gate fpp = &_root; 1767c478bd9Sstevel@tonic-gate x = *fpp; 1777c478bd9Sstevel@tonic-gate while (weight(x) >= len) { 1787c478bd9Sstevel@tonic-gate if (newblk < x->block) 1797c478bd9Sstevel@tonic-gate fpp = &x->left; 1807c478bd9Sstevel@tonic-gate else 1817c478bd9Sstevel@tonic-gate fpp = &x->right; 1827c478bd9Sstevel@tonic-gate x = *fpp; 1837c478bd9Sstevel@tonic-gate } 1847c478bd9Sstevel@tonic-gate 1857c478bd9Sstevel@tonic-gate /* 1867c478bd9Sstevel@tonic-gate * Perform root insertion. The variable x traces a path through 1877c478bd9Sstevel@tonic-gate * the fpp, and with the help of left_hook and right_hook, 1887c478bd9Sstevel@tonic-gate * rewrites all links that cross the territory occupied 1897c478bd9Sstevel@tonic-gate * by newblk. 1907c478bd9Sstevel@tonic-gate */ 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate if ((newhdr = getfreehdr()) == NIL) { 1937c478bd9Sstevel@tonic-gate /* Error message returned by getfreehdr() */ 1947c478bd9Sstevel@tonic-gate return; 1957c478bd9Sstevel@tonic-gate } 1967c478bd9Sstevel@tonic-gate *fpp = newhdr; 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate newhdr->left = NIL; 1997c478bd9Sstevel@tonic-gate newhdr->right = NIL; 2007c478bd9Sstevel@tonic-gate newhdr->block = newblk; 2017c478bd9Sstevel@tonic-gate newhdr->size = len; 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate /* 2047c478bd9Sstevel@tonic-gate * set length word in the block for consistency with the header. 2057c478bd9Sstevel@tonic-gate */ 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate newblk->size = len; 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate left_hook = &newhdr->left; 2107c478bd9Sstevel@tonic-gate right_hook = &newhdr->right; 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate while (x != NIL) { 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * Remark: 2157c478bd9Sstevel@tonic-gate * The name 'left_hook' is somewhat confusing, since 2167c478bd9Sstevel@tonic-gate * it is always set to the address of a .right link 2177c478bd9Sstevel@tonic-gate * field. However, its value is always an address 2187c478bd9Sstevel@tonic-gate * below (i.e., to the left of) newblk. Similarly 2197c478bd9Sstevel@tonic-gate * for right_hook. The values of left_hook and 2207c478bd9Sstevel@tonic-gate * right_hook converge toward the value of newblk, 2217c478bd9Sstevel@tonic-gate * as in a classical binary search. 2227c478bd9Sstevel@tonic-gate */ 2237c478bd9Sstevel@tonic-gate if (x->block < newblk) { 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * rewrite link crossing from the left 2267c478bd9Sstevel@tonic-gate */ 2277c478bd9Sstevel@tonic-gate *left_hook = x; 2287c478bd9Sstevel@tonic-gate left_hook = &x->right; 2297c478bd9Sstevel@tonic-gate x = x->right; 2307c478bd9Sstevel@tonic-gate } else { 2317c478bd9Sstevel@tonic-gate /* 2327c478bd9Sstevel@tonic-gate * rewrite link crossing from the right 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate *right_hook = x; 2357c478bd9Sstevel@tonic-gate right_hook = &x->left; 2367c478bd9Sstevel@tonic-gate x = x->left; 2377c478bd9Sstevel@tonic-gate } /*else*/ 2387c478bd9Sstevel@tonic-gate } /*while*/ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate *left_hook = *right_hook = NIL; /* clear remaining hooks */ 2417c478bd9Sstevel@tonic-gate 2427c478bd9Sstevel@tonic-gate } /*insert*/ 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate /* 2457c478bd9Sstevel@tonic-gate * delete(p) 2467c478bd9Sstevel@tonic-gate * deletes a node from a cartesian tree. p is the address of 2477c478bd9Sstevel@tonic-gate * a pointer to the node which is to be deleted. 2487c478bd9Sstevel@tonic-gate * 2497c478bd9Sstevel@tonic-gate * algorithm: 2507c478bd9Sstevel@tonic-gate * The left and right branches of the node to be deleted define two 2517c478bd9Sstevel@tonic-gate * subtrees which are to be merged and attached in place of the 2527c478bd9Sstevel@tonic-gate * deleted node. Each node on the inside edges of these two 2537c478bd9Sstevel@tonic-gate * subtrees is examined and longer nodes are placed above the 2547c478bd9Sstevel@tonic-gate * shorter ones. 2557c478bd9Sstevel@tonic-gate * 2567c478bd9Sstevel@tonic-gate * On entry: 2577c478bd9Sstevel@tonic-gate * *p is assumed to be non-null. 2587c478bd9Sstevel@tonic-gate */ 259*5d54f3d8Smuffin static void 260*5d54f3d8Smuffin delete(Freehdr *p) 2617c478bd9Sstevel@tonic-gate { 262*5d54f3d8Smuffin Freehdr x; 263*5d54f3d8Smuffin Freehdr left_branch; /* left subtree of deleted node */ 264*5d54f3d8Smuffin Freehdr right_branch; /* right subtree of deleted node */ 265*5d54f3d8Smuffin uint left_weight; 266*5d54f3d8Smuffin uint right_weight; 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate x = *p; 2697c478bd9Sstevel@tonic-gate left_branch = x->left; 2707c478bd9Sstevel@tonic-gate left_weight = weight(left_branch); 2717c478bd9Sstevel@tonic-gate right_branch = x->right; 2727c478bd9Sstevel@tonic-gate right_weight = weight(right_branch); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate while (left_branch != right_branch) { 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * iterate until left branch and right branch are 2777c478bd9Sstevel@tonic-gate * both NIL. 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate if ( left_weight >= right_weight ) { 2807c478bd9Sstevel@tonic-gate /* 2817c478bd9Sstevel@tonic-gate * promote the left branch 2827c478bd9Sstevel@tonic-gate */ 2837c478bd9Sstevel@tonic-gate if (left_branch != NIL) { 2847c478bd9Sstevel@tonic-gate if (left_weight == 0) { 2857c478bd9Sstevel@tonic-gate /* zero-length block */ 2867c478bd9Sstevel@tonic-gate error("blocksize=0 at %#x\n", 2877c478bd9Sstevel@tonic-gate (int)left_branch->block->data); 2887c478bd9Sstevel@tonic-gate break; 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate *p = left_branch; 2917c478bd9Sstevel@tonic-gate p = &left_branch->right; 2927c478bd9Sstevel@tonic-gate left_branch = *p; 2937c478bd9Sstevel@tonic-gate left_weight = weight(left_branch); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate } else { 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * promote the right branch 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate if (right_branch != NIL) { 3007c478bd9Sstevel@tonic-gate if (right_weight == 0) { 3017c478bd9Sstevel@tonic-gate /* zero-length block */ 3027c478bd9Sstevel@tonic-gate error("blocksize=0 at %#x\n", 3037c478bd9Sstevel@tonic-gate (int)right_branch->block->data); 3047c478bd9Sstevel@tonic-gate break; 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate *p = right_branch; 3077c478bd9Sstevel@tonic-gate p = &right_branch->left; 3087c478bd9Sstevel@tonic-gate right_branch = *p; 3097c478bd9Sstevel@tonic-gate right_weight = weight(right_branch); 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate }/*else*/ 3127c478bd9Sstevel@tonic-gate }/*while*/ 3137c478bd9Sstevel@tonic-gate *p = NIL; 3147c478bd9Sstevel@tonic-gate putfreehdr(x); 3157c478bd9Sstevel@tonic-gate } /*delete*/ 3167c478bd9Sstevel@tonic-gate 317*5d54f3d8Smuffin 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * demote(p) 3207c478bd9Sstevel@tonic-gate * Demotes a node in a cartesian tree, if necessary, to establish 3217c478bd9Sstevel@tonic-gate * the required vertical ordering. 3227c478bd9Sstevel@tonic-gate * 3237c478bd9Sstevel@tonic-gate * algorithm: 3247c478bd9Sstevel@tonic-gate * The left and right subtrees of the node to be demoted are to 3257c478bd9Sstevel@tonic-gate * be partially merged and attached in place of the demoted node. 3267c478bd9Sstevel@tonic-gate * The nodes on the inside edges of these two subtrees are 3277c478bd9Sstevel@tonic-gate * examined and the longer nodes are placed above the shorter 3287c478bd9Sstevel@tonic-gate * ones, until a node is reached which has a length no greater 3297c478bd9Sstevel@tonic-gate * than that of the node being demoted (or until a null pointer 3307c478bd9Sstevel@tonic-gate * is reached). The node is then attached at this point, and 3317c478bd9Sstevel@tonic-gate * the remaining subtrees (if any) become its descendants. 3327c478bd9Sstevel@tonic-gate * 3337c478bd9Sstevel@tonic-gate * on entry: 3347c478bd9Sstevel@tonic-gate * a. All the nodes in the tree, including the one to be demoted, 3357c478bd9Sstevel@tonic-gate * must be correctly ordered horizontally; 3367c478bd9Sstevel@tonic-gate * b. All the nodes except the one to be demoted must also be 3377c478bd9Sstevel@tonic-gate * correctly positioned vertically. The node to be demoted 3387c478bd9Sstevel@tonic-gate * may be already correctly positioned vertically, or it may 3397c478bd9Sstevel@tonic-gate * have a length which is less than that of one or both of 3407c478bd9Sstevel@tonic-gate * its progeny. 3417c478bd9Sstevel@tonic-gate * c. *p is non-null 3427c478bd9Sstevel@tonic-gate */ 3437c478bd9Sstevel@tonic-gate 344*5d54f3d8Smuffin static void 345*5d54f3d8Smuffin demote(Freehdr *p) 3467c478bd9Sstevel@tonic-gate { 347*5d54f3d8Smuffin Freehdr x; /* addr of node to be demoted */ 348*5d54f3d8Smuffin Freehdr left_branch; 349*5d54f3d8Smuffin Freehdr right_branch; 350*5d54f3d8Smuffin uint left_weight; 351*5d54f3d8Smuffin uint right_weight; 352*5d54f3d8Smuffin uint x_weight; 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate x = *p; 3557c478bd9Sstevel@tonic-gate x_weight = weight(x); 3567c478bd9Sstevel@tonic-gate left_branch = x->left; 3577c478bd9Sstevel@tonic-gate right_branch = x->right; 3587c478bd9Sstevel@tonic-gate left_weight = weight(left_branch); 3597c478bd9Sstevel@tonic-gate right_weight = weight(right_branch); 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate while (left_weight > x_weight || right_weight > x_weight) { 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * select a descendant branch for promotion 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate if (left_weight >= right_weight) { 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * promote the left branch 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate *p = left_branch; 3707c478bd9Sstevel@tonic-gate p = &left_branch->right; 3717c478bd9Sstevel@tonic-gate left_branch = *p; 3727c478bd9Sstevel@tonic-gate left_weight = weight(left_branch); 3737c478bd9Sstevel@tonic-gate } else { 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * promote the right branch 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate *p = right_branch; 3787c478bd9Sstevel@tonic-gate p = &right_branch->left; 3797c478bd9Sstevel@tonic-gate right_branch = *p; 3807c478bd9Sstevel@tonic-gate right_weight = weight(right_branch); 3817c478bd9Sstevel@tonic-gate } /*else*/ 3827c478bd9Sstevel@tonic-gate } /*while*/ 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate *p = x; /* attach demoted node here */ 3857c478bd9Sstevel@tonic-gate x->left = left_branch; 3867c478bd9Sstevel@tonic-gate x->right = right_branch; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate } /*demote*/ 3897c478bd9Sstevel@tonic-gate 390*5d54f3d8Smuffin 3917c478bd9Sstevel@tonic-gate /* 3927c478bd9Sstevel@tonic-gate * char* 3937c478bd9Sstevel@tonic-gate * malloc(nbytes) 3947c478bd9Sstevel@tonic-gate * Allocates a block of length specified in bytes. If nbytes is 3957c478bd9Sstevel@tonic-gate * zero, a valid pointer (that should not be dereferenced) is returned. 3967c478bd9Sstevel@tonic-gate * 3977c478bd9Sstevel@tonic-gate * algorithm: 3987c478bd9Sstevel@tonic-gate * The freelist is searched by descending the tree from the root 3997c478bd9Sstevel@tonic-gate * so that at each decision point the "better fitting" branch node 4007c478bd9Sstevel@tonic-gate * is chosen (i.e., the shorter one, if it is long enough, or 4017c478bd9Sstevel@tonic-gate * the longer one, otherwise). The descent stops when both 4027c478bd9Sstevel@tonic-gate * branch nodes are too short. 4037c478bd9Sstevel@tonic-gate * 4047c478bd9Sstevel@tonic-gate * function result: 4057c478bd9Sstevel@tonic-gate * Malloc returns a pointer to the allocated block. A null 4067c478bd9Sstevel@tonic-gate * pointer indicates an error. 4077c478bd9Sstevel@tonic-gate * 4087c478bd9Sstevel@tonic-gate * diagnostics: 4097c478bd9Sstevel@tonic-gate * 4107c478bd9Sstevel@tonic-gate * ENOMEM: storage could not be allocated. 4117c478bd9Sstevel@tonic-gate * 4127c478bd9Sstevel@tonic-gate * EINVAL: either the argument was invalid, or the heap was found 4137c478bd9Sstevel@tonic-gate * to be in an inconsistent state. More detailed information may 4147c478bd9Sstevel@tonic-gate * be obtained by enabling range checks (cf., malloc_debug()). 4157c478bd9Sstevel@tonic-gate * 4167c478bd9Sstevel@tonic-gate * Note: In this implementation, each allocated block includes a 4177c478bd9Sstevel@tonic-gate * length word, which occurs before the address seen by the caller. 4187c478bd9Sstevel@tonic-gate * Allocation requests are rounded up to a multiple of wordsize. 4197c478bd9Sstevel@tonic-gate */ 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate ptr_t 422*5d54f3d8Smuffin malloc(uint nbytes) 4237c478bd9Sstevel@tonic-gate { 424*5d54f3d8Smuffin Freehdr allocp; /* ptr to node to be allocated */ 425*5d54f3d8Smuffin Freehdr *fpp; /* for tree modifications */ 426*5d54f3d8Smuffin Freehdr left_branch; 427*5d54f3d8Smuffin Freehdr right_branch; 428*5d54f3d8Smuffin uint left_weight; 429*5d54f3d8Smuffin uint right_weight; 4307c478bd9Sstevel@tonic-gate Dblk retblk; /* block returned to the user */ 4317c478bd9Sstevel@tonic-gate 4327c478bd9Sstevel@tonic-gate /* 4337c478bd9Sstevel@tonic-gate * if rigorous checking was requested, do it. 4347c478bd9Sstevel@tonic-gate */ 4357c478bd9Sstevel@tonic-gate if (debug_level >= 2) { 4367c478bd9Sstevel@tonic-gate malloc_verify(); 4377c478bd9Sstevel@tonic-gate } 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * add the size of a length word to the request, and 4417c478bd9Sstevel@tonic-gate * guarantee at least one word of usable data. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate nbytes += ALIGNSIZ; 4447c478bd9Sstevel@tonic-gate if (nbytes < SMALLEST_BLK) { 4457c478bd9Sstevel@tonic-gate nbytes = SMALLEST_BLK; 4467c478bd9Sstevel@tonic-gate } else { 4477c478bd9Sstevel@tonic-gate nbytes = roundup(nbytes, ALIGNSIZ); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * ensure that at least one block is big enough to satisfy 4527c478bd9Sstevel@tonic-gate * the request. 4537c478bd9Sstevel@tonic-gate */ 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate if (weight(_root) < nbytes) { 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * the largest block is not enough. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate if(!morecore(nbytes)) 4607c478bd9Sstevel@tonic-gate return 0; 4617c478bd9Sstevel@tonic-gate } 4627c478bd9Sstevel@tonic-gate 4637c478bd9Sstevel@tonic-gate /* 4647c478bd9Sstevel@tonic-gate * search down through the tree until a suitable block is 4657c478bd9Sstevel@tonic-gate * found. At each decision point, select the better 4667c478bd9Sstevel@tonic-gate * fitting node. 4677c478bd9Sstevel@tonic-gate */ 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate fpp = &_root; 4707c478bd9Sstevel@tonic-gate allocp = *fpp; 4717c478bd9Sstevel@tonic-gate left_branch = allocp->left; 4727c478bd9Sstevel@tonic-gate right_branch = allocp->right; 4737c478bd9Sstevel@tonic-gate left_weight = weight(left_branch); 4747c478bd9Sstevel@tonic-gate right_weight = weight(right_branch); 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate while (left_weight >= nbytes || right_weight >= nbytes) { 4777c478bd9Sstevel@tonic-gate if (left_weight <= right_weight) { 4787c478bd9Sstevel@tonic-gate if (left_weight >= nbytes) { 4797c478bd9Sstevel@tonic-gate fpp = &allocp->left; 4807c478bd9Sstevel@tonic-gate allocp = left_branch; 4817c478bd9Sstevel@tonic-gate } else { 4827c478bd9Sstevel@tonic-gate fpp = &allocp->right; 4837c478bd9Sstevel@tonic-gate allocp = right_branch; 4847c478bd9Sstevel@tonic-gate } 4857c478bd9Sstevel@tonic-gate } else { 4867c478bd9Sstevel@tonic-gate if (right_weight >= nbytes) { 4877c478bd9Sstevel@tonic-gate fpp = &allocp->right; 4887c478bd9Sstevel@tonic-gate allocp = right_branch; 4897c478bd9Sstevel@tonic-gate } else { 4907c478bd9Sstevel@tonic-gate fpp = &allocp->left; 4917c478bd9Sstevel@tonic-gate allocp = left_branch; 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate left_branch = allocp->left; 4957c478bd9Sstevel@tonic-gate right_branch = allocp->right; 4967c478bd9Sstevel@tonic-gate left_weight = weight(left_branch); 4977c478bd9Sstevel@tonic-gate right_weight = weight(right_branch); 4987c478bd9Sstevel@tonic-gate } /*while*/ 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * allocate storage from the selected node. 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate if (allocp->size - nbytes <= SMALLEST_BLK) { 5057c478bd9Sstevel@tonic-gate /* 5067c478bd9Sstevel@tonic-gate * not big enough to split; must leave at least 5077c478bd9Sstevel@tonic-gate * a dblk's worth of space. 5087c478bd9Sstevel@tonic-gate */ 5097c478bd9Sstevel@tonic-gate retblk = allocp->block; 5107c478bd9Sstevel@tonic-gate delete(fpp); 5117c478bd9Sstevel@tonic-gate } else { 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* 5147c478bd9Sstevel@tonic-gate * Split the selected block n bytes from the top. The 5157c478bd9Sstevel@tonic-gate * n bytes at the top are returned to the caller; the 5167c478bd9Sstevel@tonic-gate * remainder of the block goes back to free space. 5177c478bd9Sstevel@tonic-gate */ 518*5d54f3d8Smuffin Dblk nblk; 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate retblk = allocp->block; 5217c478bd9Sstevel@tonic-gate nblk = nextblk(retblk, nbytes); /* ^next block */ 5227c478bd9Sstevel@tonic-gate nblk->size = allocp->size = retblk->size - nbytes; 5237c478bd9Sstevel@tonic-gate __mallinfo.ordblks++; /* count fragments */ 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * Change the selected node to point at the newly split 5277c478bd9Sstevel@tonic-gate * block, and move the node to its proper place in 5287c478bd9Sstevel@tonic-gate * the free space list. 5297c478bd9Sstevel@tonic-gate */ 5307c478bd9Sstevel@tonic-gate allocp->block = nblk; 5317c478bd9Sstevel@tonic-gate demote(fpp); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 5347c478bd9Sstevel@tonic-gate * set the length field of the allocated block; we need 5357c478bd9Sstevel@tonic-gate * this because free() does not specify a length. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate retblk->size = nbytes; 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate /* maintain statistics */ 5407c478bd9Sstevel@tonic-gate __mallinfo.uordbytes += retblk->size; /* bytes allocated */ 5417c478bd9Sstevel@tonic-gate __mallinfo.allocated++; /* frags allocated */ 5427c478bd9Sstevel@tonic-gate if (nbytes < __mallinfo.mxfast) 5437c478bd9Sstevel@tonic-gate __mallinfo.smblks++; /* kludge to pass the SVVS */ 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate return((ptr_t)retblk->data); 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate } /*malloc*/ 548*5d54f3d8Smuffin 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * free(p) 5517c478bd9Sstevel@tonic-gate * return a block to the free space tree. 5527c478bd9Sstevel@tonic-gate * 5537c478bd9Sstevel@tonic-gate * algorithm: 5547c478bd9Sstevel@tonic-gate * Starting at the root, search for and coalesce free blocks 5557c478bd9Sstevel@tonic-gate * adjacent to one given. When the appropriate place in the 5567c478bd9Sstevel@tonic-gate * tree is found, insert the given block. 5577c478bd9Sstevel@tonic-gate * 5587c478bd9Sstevel@tonic-gate * Some sanity checks to avoid total confusion in the tree. 5597c478bd9Sstevel@tonic-gate * If the block has already been freed, return. 5607c478bd9Sstevel@tonic-gate * If the ptr is not from the sbrk'ed space, return. 5617c478bd9Sstevel@tonic-gate * If the block size is invalid, return. 5627c478bd9Sstevel@tonic-gate */ 5637c478bd9Sstevel@tonic-gate free_t 564*5d54f3d8Smuffin free(ptr_t ptr) 5657c478bd9Sstevel@tonic-gate { 566*5d54f3d8Smuffin uint nbytes; /* Size of node to be released */ 567*5d54f3d8Smuffin Freehdr *fpp; /* For deletion from free list */ 568*5d54f3d8Smuffin Freehdr neighbor; /* Node to be coalesced */ 569*5d54f3d8Smuffin Dblk neighbor_blk; /* Ptr to potential neighbor */ 570*5d54f3d8Smuffin uint neighbor_size; /* Size of potential neighbor */ 571*5d54f3d8Smuffin Dblk oldblk; /* Ptr to block to be freed */ 5727c478bd9Sstevel@tonic-gate 5737c478bd9Sstevel@tonic-gate /* 5747c478bd9Sstevel@tonic-gate * if rigorous checking was requested, do it. 5757c478bd9Sstevel@tonic-gate */ 5767c478bd9Sstevel@tonic-gate if (debug_level >= 2) { 5777c478bd9Sstevel@tonic-gate malloc_verify(); 5787c478bd9Sstevel@tonic-gate } 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate /* 5817c478bd9Sstevel@tonic-gate * Check the address of the old block. 5827c478bd9Sstevel@tonic-gate */ 5837c478bd9Sstevel@tonic-gate if ( misaligned(ptr) ) { 5847c478bd9Sstevel@tonic-gate error("free: illegal address (%#x)\n", ptr); 5857c478bd9Sstevel@tonic-gate free_return(0); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * Freeing something that wasn't allocated isn't 5907c478bd9Sstevel@tonic-gate * exactly kosher, but fclose() does it routinely. 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate if( ptr < (ptr_t)_lbound || ptr > (ptr_t)_ubound ) { 5937c478bd9Sstevel@tonic-gate errno = EINVAL; 5947c478bd9Sstevel@tonic-gate free_return(0); 5957c478bd9Sstevel@tonic-gate } 5967c478bd9Sstevel@tonic-gate 5977c478bd9Sstevel@tonic-gate /* 5987c478bd9Sstevel@tonic-gate * Get node length by backing up by the size of a header. 5997c478bd9Sstevel@tonic-gate * Check for a valid length. It must be a positive 6007c478bd9Sstevel@tonic-gate * multiple of ALIGNSIZ, at least as large as SMALLEST_BLK, 6017c478bd9Sstevel@tonic-gate * no larger than the extent of the heap, and must not 6027c478bd9Sstevel@tonic-gate * extend beyond the end of the heap. 6037c478bd9Sstevel@tonic-gate */ 6047c478bd9Sstevel@tonic-gate oldblk = (Dblk)((char*)ptr - ALIGNSIZ); 6057c478bd9Sstevel@tonic-gate nbytes = oldblk->size; 6067c478bd9Sstevel@tonic-gate if (badblksize(oldblk,nbytes)) { 6077c478bd9Sstevel@tonic-gate error("free: bad block size (%d) at %#x\n", 6087c478bd9Sstevel@tonic-gate (int)nbytes, (int)oldblk ); 6097c478bd9Sstevel@tonic-gate free_return(0); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* maintain statistics */ 6137c478bd9Sstevel@tonic-gate __mallinfo.uordbytes -= nbytes; /* bytes allocated */ 6147c478bd9Sstevel@tonic-gate __mallinfo.allocated--; /* frags allocated */ 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * Search the tree for the correct insertion point for this 6187c478bd9Sstevel@tonic-gate * node, coalescing adjacent free blocks along the way. 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate fpp = &_root; 6217c478bd9Sstevel@tonic-gate neighbor = *fpp; 6227c478bd9Sstevel@tonic-gate while (neighbor != NIL) { 6237c478bd9Sstevel@tonic-gate neighbor_blk = neighbor->block; 6247c478bd9Sstevel@tonic-gate neighbor_size = neighbor->size; 6257c478bd9Sstevel@tonic-gate if (oldblk < neighbor_blk) { 6267c478bd9Sstevel@tonic-gate Dblk nblk = nextblk(oldblk,nbytes); 6277c478bd9Sstevel@tonic-gate if (nblk == neighbor_blk) { 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * Absorb and delete right neighbor 6307c478bd9Sstevel@tonic-gate */ 6317c478bd9Sstevel@tonic-gate nbytes += neighbor_size; 6327c478bd9Sstevel@tonic-gate __mallinfo.ordblks--; 6337c478bd9Sstevel@tonic-gate delete(fpp); 6347c478bd9Sstevel@tonic-gate } else if (nblk > neighbor_blk) { 6357c478bd9Sstevel@tonic-gate /* 6367c478bd9Sstevel@tonic-gate * The block being freed overlaps 6377c478bd9Sstevel@tonic-gate * another block in the tree. This 6387c478bd9Sstevel@tonic-gate * is bad news. Return to avoid 6397c478bd9Sstevel@tonic-gate * further fouling up the the tree. 6407c478bd9Sstevel@tonic-gate */ 6417c478bd9Sstevel@tonic-gate error("free: blocks %#x, %#x overlap\n", 6427c478bd9Sstevel@tonic-gate (int)oldblk, (int)neighbor_blk); 6437c478bd9Sstevel@tonic-gate free_return(0); 6447c478bd9Sstevel@tonic-gate } else { 6457c478bd9Sstevel@tonic-gate /* 6467c478bd9Sstevel@tonic-gate * Search to the left 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate fpp = &neighbor->left; 6497c478bd9Sstevel@tonic-gate } 6507c478bd9Sstevel@tonic-gate } else if (oldblk > neighbor_blk) { 6517c478bd9Sstevel@tonic-gate Dblk nblk = nextblk(neighbor_blk, neighbor_size); 6527c478bd9Sstevel@tonic-gate if (nblk == oldblk) { 6537c478bd9Sstevel@tonic-gate /* 6547c478bd9Sstevel@tonic-gate * Absorb and delete left neighbor 6557c478bd9Sstevel@tonic-gate */ 6567c478bd9Sstevel@tonic-gate oldblk = neighbor_blk; 6577c478bd9Sstevel@tonic-gate nbytes += neighbor_size; 6587c478bd9Sstevel@tonic-gate __mallinfo.ordblks--; 6597c478bd9Sstevel@tonic-gate delete(fpp); 6607c478bd9Sstevel@tonic-gate } else if (nblk > oldblk) { 6617c478bd9Sstevel@tonic-gate /* 6627c478bd9Sstevel@tonic-gate * This block has already been freed 6637c478bd9Sstevel@tonic-gate */ 6647c478bd9Sstevel@tonic-gate error("free: block %#x was already free\n", 6657c478bd9Sstevel@tonic-gate (int)ptr); 6667c478bd9Sstevel@tonic-gate free_return(0); 6677c478bd9Sstevel@tonic-gate } else { 6687c478bd9Sstevel@tonic-gate /* 6697c478bd9Sstevel@tonic-gate * search to the right 6707c478bd9Sstevel@tonic-gate */ 6717c478bd9Sstevel@tonic-gate fpp = &neighbor->right; 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate } else { 6747c478bd9Sstevel@tonic-gate /* 6757c478bd9Sstevel@tonic-gate * This block has already been freed 6767c478bd9Sstevel@tonic-gate * as "oldblk == neighbor_blk" 6777c478bd9Sstevel@tonic-gate */ 6787c478bd9Sstevel@tonic-gate error("free: block %#x was already free\n", (int)ptr); 6797c478bd9Sstevel@tonic-gate free_return(0); 6807c478bd9Sstevel@tonic-gate } /*else*/ 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate /* 6837c478bd9Sstevel@tonic-gate * Note that this depends on a side effect of 6847c478bd9Sstevel@tonic-gate * delete(fpp) in order to terminate the loop! 6857c478bd9Sstevel@tonic-gate */ 6867c478bd9Sstevel@tonic-gate neighbor = *fpp; 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate } /*while*/ 6897c478bd9Sstevel@tonic-gate 6907c478bd9Sstevel@tonic-gate /* 6917c478bd9Sstevel@tonic-gate * Insert the new node into the free space tree 6927c478bd9Sstevel@tonic-gate */ 6937c478bd9Sstevel@tonic-gate insert( oldblk, nbytes ); 6947c478bd9Sstevel@tonic-gate free_return(1); 6957c478bd9Sstevel@tonic-gate 6967c478bd9Sstevel@tonic-gate } /*free*/ 6977c478bd9Sstevel@tonic-gate 698*5d54f3d8Smuffin 6997c478bd9Sstevel@tonic-gate /* 7007c478bd9Sstevel@tonic-gate * char* 7017c478bd9Sstevel@tonic-gate * shrink(oldblk, oldsize, newsize) 7027c478bd9Sstevel@tonic-gate * Decreases the size of an old block to a new size. 7037c478bd9Sstevel@tonic-gate * Returns the remainder to free space. Returns the 7047c478bd9Sstevel@tonic-gate * truncated block to the caller. 7057c478bd9Sstevel@tonic-gate */ 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate static char * 708*5d54f3d8Smuffin shrink(Dblk oldblk, uint oldsize, uint newsize) 7097c478bd9Sstevel@tonic-gate { 710*5d54f3d8Smuffin Dblk remainder; 7117c478bd9Sstevel@tonic-gate if (oldsize - newsize >= SMALLEST_BLK) { 7127c478bd9Sstevel@tonic-gate /* 7137c478bd9Sstevel@tonic-gate * Block is to be contracted. Split the old block 7147c478bd9Sstevel@tonic-gate * and return the remainder to free space. 7157c478bd9Sstevel@tonic-gate */ 7167c478bd9Sstevel@tonic-gate remainder = nextblk(oldblk, newsize); 7177c478bd9Sstevel@tonic-gate remainder->size = oldsize - newsize; 7187c478bd9Sstevel@tonic-gate oldblk->size = newsize; 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* maintain statistics */ 7217c478bd9Sstevel@tonic-gate __mallinfo.ordblks++; /* count fragments */ 7227c478bd9Sstevel@tonic-gate __mallinfo.allocated++; /* negate effect of free() */ 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate free(remainder->data); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate return(oldblk->data); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * char* 7317c478bd9Sstevel@tonic-gate * realloc(ptr, nbytes) 7327c478bd9Sstevel@tonic-gate * 7337c478bd9Sstevel@tonic-gate * Reallocate an old block with a new size, returning the old block 7347c478bd9Sstevel@tonic-gate * if possible. The block returned is guaranteed to preserve the 7357c478bd9Sstevel@tonic-gate * contents of the old block up to min(size(old block), newsize). 7367c478bd9Sstevel@tonic-gate * 7377c478bd9Sstevel@tonic-gate * For backwards compatibility, ptr is allowed to reference 7387c478bd9Sstevel@tonic-gate * a block freed since the LAST call of malloc(). Thus the old 7397c478bd9Sstevel@tonic-gate * block may be busy, free, or may even be nested within a free 7407c478bd9Sstevel@tonic-gate * block. 7417c478bd9Sstevel@tonic-gate * 7427c478bd9Sstevel@tonic-gate * Some old programs have been known to do things like the following, 7437c478bd9Sstevel@tonic-gate * which is guaranteed not to work: 7447c478bd9Sstevel@tonic-gate * 7457c478bd9Sstevel@tonic-gate * free(ptr); 7467c478bd9Sstevel@tonic-gate * free(dummy); 7477c478bd9Sstevel@tonic-gate * dummy = malloc(1); 7487c478bd9Sstevel@tonic-gate * ptr = realloc(ptr,nbytes); 7497c478bd9Sstevel@tonic-gate * 7507c478bd9Sstevel@tonic-gate * This atrocity was found in the source for diff(1). 7517c478bd9Sstevel@tonic-gate */ 7527c478bd9Sstevel@tonic-gate ptr_t 753*5d54f3d8Smuffin realloc(ptr_t ptr, uint nbytes) 7547c478bd9Sstevel@tonic-gate { 755*5d54f3d8Smuffin Freehdr *fpp; 756*5d54f3d8Smuffin Freehdr fp; 757*5d54f3d8Smuffin Dblk oldblk; 758*5d54f3d8Smuffin Dblk freeblk; 759*5d54f3d8Smuffin Dblk oldneighbor; 760*5d54f3d8Smuffin uint oldsize; 761*5d54f3d8Smuffin uint newsize; 762*5d54f3d8Smuffin uint oldneighborsize; 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate /* 7657c478bd9Sstevel@tonic-gate * Add SVR4 semantics for OS 5.x so /usr/lib librarys 7667c478bd9Sstevel@tonic-gate * work correctly when running in BCP mode 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate if (ptr == NULL) { 7697c478bd9Sstevel@tonic-gate return (malloc(nbytes)); 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * if rigorous checking was requested, do it. 7747c478bd9Sstevel@tonic-gate */ 7757c478bd9Sstevel@tonic-gate if (debug_level >= 2) { 7767c478bd9Sstevel@tonic-gate malloc_verify(); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate 7797c478bd9Sstevel@tonic-gate /* 7807c478bd9Sstevel@tonic-gate * Check the address of the old block. 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate if ( misaligned(ptr) || 7837c478bd9Sstevel@tonic-gate ptr < (ptr_t)_lbound || 7847c478bd9Sstevel@tonic-gate ptr > (ptr_t)_ubound ) { 7857c478bd9Sstevel@tonic-gate error("realloc: illegal address (%#x)\n", ptr); 7867c478bd9Sstevel@tonic-gate return(NULL); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate /* 7907c478bd9Sstevel@tonic-gate * check location and size of the old block and its 7917c478bd9Sstevel@tonic-gate * neighboring block to the right. If the old block is 7927c478bd9Sstevel@tonic-gate * at end of memory, the neighboring block is undefined. 7937c478bd9Sstevel@tonic-gate */ 7947c478bd9Sstevel@tonic-gate oldblk = (Dblk)((char*)ptr - ALIGNSIZ); 7957c478bd9Sstevel@tonic-gate oldsize = oldblk->size; 7967c478bd9Sstevel@tonic-gate if (badblksize(oldblk,oldsize)) { 7977c478bd9Sstevel@tonic-gate error("realloc: bad block size (%d) at %#x\n", 7987c478bd9Sstevel@tonic-gate oldsize, oldblk); 7997c478bd9Sstevel@tonic-gate return(NULL); 8007c478bd9Sstevel@tonic-gate } 8017c478bd9Sstevel@tonic-gate oldneighbor = nextblk(oldblk,oldsize); 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate /* *** tree search code pulled into separate subroutine *** */ 8047c478bd9Sstevel@tonic-gate if (reclaim(oldblk, oldsize, 1) == -1) { 8057c478bd9Sstevel@tonic-gate return(NULL); /* internal error */ 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate /* 8097c478bd9Sstevel@tonic-gate * At this point, we can guarantee that oldblk is out of free 8107c478bd9Sstevel@tonic-gate * space. What we do next depends on a comparison of the size 8117c478bd9Sstevel@tonic-gate * of the old block and the requested new block size. To do 8127c478bd9Sstevel@tonic-gate * this, first round up the new size request. 8137c478bd9Sstevel@tonic-gate */ 8147c478bd9Sstevel@tonic-gate newsize = nbytes + ALIGNSIZ; /* add size of a length word */ 8157c478bd9Sstevel@tonic-gate if (newsize < SMALLEST_BLK) { 8167c478bd9Sstevel@tonic-gate newsize = SMALLEST_BLK; 8177c478bd9Sstevel@tonic-gate } else { 8187c478bd9Sstevel@tonic-gate newsize = roundup(newsize, ALIGNSIZ); 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* 8227c478bd9Sstevel@tonic-gate * Next, examine the size of the old block, and compare it 8237c478bd9Sstevel@tonic-gate * with the requested new size. 8247c478bd9Sstevel@tonic-gate */ 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate if (oldsize >= newsize) { 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Block is to be made smaller. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate return(shrink(oldblk, oldsize, newsize)); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * Block is to be expanded. Look for adjacent free memory. 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate if ( oldneighbor < (Dblk)_ubound ) { 8377c478bd9Sstevel@tonic-gate /* 8387c478bd9Sstevel@tonic-gate * Search for the adjacent block in the free 8397c478bd9Sstevel@tonic-gate * space tree. Note that the tree may have been 8407c478bd9Sstevel@tonic-gate * modified in the earlier loop. 8417c478bd9Sstevel@tonic-gate */ 8427c478bd9Sstevel@tonic-gate fpp = &_root; 8437c478bd9Sstevel@tonic-gate fp = *fpp; 8447c478bd9Sstevel@tonic-gate oldneighborsize = oldneighbor->size; 8457c478bd9Sstevel@tonic-gate if ( badblksize(oldneighbor, oldneighborsize) ) { 8467c478bd9Sstevel@tonic-gate error("realloc: bad blocksize(%d) at %#x\n", 8477c478bd9Sstevel@tonic-gate oldneighborsize, oldneighbor); 8487c478bd9Sstevel@tonic-gate return(NULL); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate while ( weight(fp) >= oldneighborsize ) { 8517c478bd9Sstevel@tonic-gate freeblk = fp->block; 8527c478bd9Sstevel@tonic-gate if (oldneighbor < freeblk) { 8537c478bd9Sstevel@tonic-gate /* 8547c478bd9Sstevel@tonic-gate * search to the left 8557c478bd9Sstevel@tonic-gate */ 8567c478bd9Sstevel@tonic-gate fpp = &(fp->left); 8577c478bd9Sstevel@tonic-gate fp = *fpp; 8587c478bd9Sstevel@tonic-gate } 8597c478bd9Sstevel@tonic-gate else if (oldneighbor > freeblk) { 8607c478bd9Sstevel@tonic-gate /* 8617c478bd9Sstevel@tonic-gate * search to the right 8627c478bd9Sstevel@tonic-gate */ 8637c478bd9Sstevel@tonic-gate fpp = &(fp->right); 8647c478bd9Sstevel@tonic-gate fp = *fpp; 8657c478bd9Sstevel@tonic-gate } 8667c478bd9Sstevel@tonic-gate else { /* oldneighbor == freeblk */ 8677c478bd9Sstevel@tonic-gate /* 8687c478bd9Sstevel@tonic-gate * neighboring block is free; is it big enough? 8697c478bd9Sstevel@tonic-gate */ 8707c478bd9Sstevel@tonic-gate if (oldsize + oldneighborsize >= newsize) { 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * Big enough. Delete freeblk, join 8737c478bd9Sstevel@tonic-gate * oldblk to neighbor, return newsize 8747c478bd9Sstevel@tonic-gate * bytes to the caller, and return the 8757c478bd9Sstevel@tonic-gate * remainder to free storage. 8767c478bd9Sstevel@tonic-gate */ 8777c478bd9Sstevel@tonic-gate delete(fpp); 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate /* maintain statistics */ 8807c478bd9Sstevel@tonic-gate __mallinfo.ordblks--; 8817c478bd9Sstevel@tonic-gate __mallinfo.uordbytes += oldneighborsize; 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate oldsize += oldneighborsize; 8847c478bd9Sstevel@tonic-gate oldblk->size = oldsize; 8857c478bd9Sstevel@tonic-gate return(shrink(oldblk, oldsize, newsize)); 8867c478bd9Sstevel@tonic-gate } else { 8877c478bd9Sstevel@tonic-gate /* 8887c478bd9Sstevel@tonic-gate * Not big enough. Stop looking for a 8897c478bd9Sstevel@tonic-gate * free lunch. 8907c478bd9Sstevel@tonic-gate */ 8917c478bd9Sstevel@tonic-gate break; 8927c478bd9Sstevel@tonic-gate } /*else*/ 8937c478bd9Sstevel@tonic-gate } /*else*/ 8947c478bd9Sstevel@tonic-gate }/*while*/ 8957c478bd9Sstevel@tonic-gate } /*if*/ 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate /* 8987c478bd9Sstevel@tonic-gate * At this point, we know there is no free space in which to 8997c478bd9Sstevel@tonic-gate * expand. Malloc a new block, copy the old block to the new, 9007c478bd9Sstevel@tonic-gate * and free the old block, IN THAT ORDER. 9017c478bd9Sstevel@tonic-gate */ 9027c478bd9Sstevel@tonic-gate ptr = malloc(nbytes); 9037c478bd9Sstevel@tonic-gate if (ptr != NULL) { 9047c478bd9Sstevel@tonic-gate bcopy(oldblk->data, ptr, oldsize-ALIGNSIZ); 9057c478bd9Sstevel@tonic-gate free(oldblk->data); 9067c478bd9Sstevel@tonic-gate } 9077c478bd9Sstevel@tonic-gate return(ptr); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate } /* realloc */ 9107c478bd9Sstevel@tonic-gate 911*5d54f3d8Smuffin 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * *** The following code was pulled out of realloc() *** 9147c478bd9Sstevel@tonic-gate * 9157c478bd9Sstevel@tonic-gate * int 9167c478bd9Sstevel@tonic-gate * reclaim(oldblk, oldsize, flag) 9177c478bd9Sstevel@tonic-gate * If a block containing 'oldsize' bytes from 'oldblk' 9187c478bd9Sstevel@tonic-gate * is in the free list, remove it from the free list. 9197c478bd9Sstevel@tonic-gate * 'oldblk' and 'oldsize' are assumed to include the free block header. 9207c478bd9Sstevel@tonic-gate * 9217c478bd9Sstevel@tonic-gate * Returns 1 if block was successfully removed. 9227c478bd9Sstevel@tonic-gate * Returns 0 if block was not in free list. 9237c478bd9Sstevel@tonic-gate * Returns -1 if block spans a free/allocated boundary (error() called 9247c478bd9Sstevel@tonic-gate * if 'flag' == 1). 9257c478bd9Sstevel@tonic-gate */ 9267c478bd9Sstevel@tonic-gate static int 927*5d54f3d8Smuffin reclaim(Dblk oldblk, uint oldsize, int flag) 9287c478bd9Sstevel@tonic-gate { 929*5d54f3d8Smuffin Dblk oldneighbor; 930*5d54f3d8Smuffin Freehdr *fpp; 931*5d54f3d8Smuffin Freehdr fp; 932*5d54f3d8Smuffin Dblk freeblk; 933*5d54f3d8Smuffin uint size; 9347c478bd9Sstevel@tonic-gate 9357c478bd9Sstevel@tonic-gate /* 9367c478bd9Sstevel@tonic-gate * Search the free space list for a node describing oldblk, 9377c478bd9Sstevel@tonic-gate * or a node describing a block containing oldblk. Assuming 9387c478bd9Sstevel@tonic-gate * the size of blocks decreases monotonically with depth in 9397c478bd9Sstevel@tonic-gate * the tree, the loop may terminate as soon as a block smaller 9407c478bd9Sstevel@tonic-gate * than oldblk is encountered. 9417c478bd9Sstevel@tonic-gate */ 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate oldneighbor = nextblk(oldblk, oldsize); 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate fpp = &_root; 9467c478bd9Sstevel@tonic-gate fp = *fpp; 9477c478bd9Sstevel@tonic-gate while ( (size = weight(fp)) >= oldsize ) { 9487c478bd9Sstevel@tonic-gate freeblk = fp->block; 9497c478bd9Sstevel@tonic-gate if (badblksize(freeblk,size)) { 9507c478bd9Sstevel@tonic-gate error("realloc: bad block size (%d) at %#x\n", 9517c478bd9Sstevel@tonic-gate size, freeblk); 9527c478bd9Sstevel@tonic-gate return(-1); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate if ( oldblk == freeblk ) { 9557c478bd9Sstevel@tonic-gate /* 9567c478bd9Sstevel@tonic-gate * |<-- freeblk ... 9577c478bd9Sstevel@tonic-gate * _________________________________ 9587c478bd9Sstevel@tonic-gate * |<-- oldblk ... 9597c478bd9Sstevel@tonic-gate * --------------------------------- 9607c478bd9Sstevel@tonic-gate * Found oldblk in the free space tree; delete it. 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate delete(fpp); 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate /* maintain statistics */ 9657c478bd9Sstevel@tonic-gate __mallinfo.uordbytes += oldsize; 9667c478bd9Sstevel@tonic-gate __mallinfo.allocated++; 9677c478bd9Sstevel@tonic-gate return(1); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate else if (oldblk < freeblk) { 9707c478bd9Sstevel@tonic-gate /* 9717c478bd9Sstevel@tonic-gate * |<-- freeblk ... 9727c478bd9Sstevel@tonic-gate * _________________________________ 9737c478bd9Sstevel@tonic-gate * |<--oldblk ... 9747c478bd9Sstevel@tonic-gate * --------------------------------- 9757c478bd9Sstevel@tonic-gate * Search to the left for oldblk 9767c478bd9Sstevel@tonic-gate */ 9777c478bd9Sstevel@tonic-gate fpp = &fp->left; 9787c478bd9Sstevel@tonic-gate fp = *fpp; 9797c478bd9Sstevel@tonic-gate } 9807c478bd9Sstevel@tonic-gate else { 9817c478bd9Sstevel@tonic-gate /* 9827c478bd9Sstevel@tonic-gate * |<-- freeblk ... 9837c478bd9Sstevel@tonic-gate * _________________________________ 9847c478bd9Sstevel@tonic-gate * | |<--oldblk--->|<--oldneighbor 9857c478bd9Sstevel@tonic-gate * --------------------------------- 9867c478bd9Sstevel@tonic-gate * oldblk is somewhere to the right of freeblk. 9877c478bd9Sstevel@tonic-gate * Check to see if it lies within freeblk. 9887c478bd9Sstevel@tonic-gate */ 989*5d54f3d8Smuffin Dblk freeneighbor; 9907c478bd9Sstevel@tonic-gate freeneighbor = nextblk(freeblk, freeblk->size); 9917c478bd9Sstevel@tonic-gate if (oldblk >= freeneighbor) { 9927c478bd9Sstevel@tonic-gate /* 9937c478bd9Sstevel@tonic-gate * |<-- freeblk--->|<--- freeneighbor ... 9947c478bd9Sstevel@tonic-gate * _________________________________ 9957c478bd9Sstevel@tonic-gate * | |<--oldblk--->| 9967c478bd9Sstevel@tonic-gate * --------------------------------- 9977c478bd9Sstevel@tonic-gate * no such luck; search to the right. 9987c478bd9Sstevel@tonic-gate */ 9997c478bd9Sstevel@tonic-gate fpp = &fp->right; 10007c478bd9Sstevel@tonic-gate fp = *fpp; 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate else { 10037c478bd9Sstevel@tonic-gate /* 10047c478bd9Sstevel@tonic-gate * freeblk < oldblk < freeneighbor; 10057c478bd9Sstevel@tonic-gate * i.e., oldblk begins within freeblk. 10067c478bd9Sstevel@tonic-gate */ 10077c478bd9Sstevel@tonic-gate if (oldneighbor > freeneighbor) { 10087c478bd9Sstevel@tonic-gate /* 10097c478bd9Sstevel@tonic-gate * |<-- freeblk--->|<--- freeneighbor 10107c478bd9Sstevel@tonic-gate * _________________________________ 10117c478bd9Sstevel@tonic-gate * | |<--oldblk--->|<--oldneighbor 10127c478bd9Sstevel@tonic-gate * --------------------------------- 10137c478bd9Sstevel@tonic-gate * oldblk straddles a block boundary! 10147c478bd9Sstevel@tonic-gate */ 10157c478bd9Sstevel@tonic-gate if (flag) { 10167c478bd9Sstevel@tonic-gate error("realloc: block %#x straddles free block boundary\n", oldblk); 10177c478bd9Sstevel@tonic-gate } 10187c478bd9Sstevel@tonic-gate return(-1); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate else if ( oldneighbor == freeneighbor ) { 10217c478bd9Sstevel@tonic-gate /* 10227c478bd9Sstevel@tonic-gate * |<-------- freeblk------------->| 10237c478bd9Sstevel@tonic-gate * _________________________________ 10247c478bd9Sstevel@tonic-gate * | |<--oldblk--->| 10257c478bd9Sstevel@tonic-gate * --------------------------------- 10267c478bd9Sstevel@tonic-gate * Oldblk is on the right end of 10277c478bd9Sstevel@tonic-gate * freeblk. Delete freeblk, split 10287c478bd9Sstevel@tonic-gate * into two fragments, and return 10297c478bd9Sstevel@tonic-gate * the one on the left to free space. 10307c478bd9Sstevel@tonic-gate */ 10317c478bd9Sstevel@tonic-gate delete(fpp); 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* maintain statistics */ 10347c478bd9Sstevel@tonic-gate __mallinfo.ordblks++; 10357c478bd9Sstevel@tonic-gate __mallinfo.uordbytes += oldsize; 10367c478bd9Sstevel@tonic-gate __mallinfo.allocated += 2; 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate freeblk->size -= oldsize; 10397c478bd9Sstevel@tonic-gate free(freeblk->data); 10407c478bd9Sstevel@tonic-gate return(1); 10417c478bd9Sstevel@tonic-gate } 10427c478bd9Sstevel@tonic-gate else { 10437c478bd9Sstevel@tonic-gate /* 10447c478bd9Sstevel@tonic-gate * |<-------- freeblk------------->| 10457c478bd9Sstevel@tonic-gate * _________________________________ 10467c478bd9Sstevel@tonic-gate * | |oldblk | oldneighbor | 10477c478bd9Sstevel@tonic-gate * --------------------------------- 10487c478bd9Sstevel@tonic-gate * Oldblk is in the middle of freeblk. 10497c478bd9Sstevel@tonic-gate * Delete freeblk, split into three 10507c478bd9Sstevel@tonic-gate * fragments, and return the ones on 10517c478bd9Sstevel@tonic-gate * the ends to free space. 10527c478bd9Sstevel@tonic-gate */ 10537c478bd9Sstevel@tonic-gate delete(fpp); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate /* maintain statistics */ 10567c478bd9Sstevel@tonic-gate __mallinfo.ordblks += 2; 10577c478bd9Sstevel@tonic-gate __mallinfo.uordbytes += freeblk->size; 10587c478bd9Sstevel@tonic-gate __mallinfo.allocated += 3; 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate /* 10617c478bd9Sstevel@tonic-gate * split the left fragment by 10627c478bd9Sstevel@tonic-gate * subtracting the size of oldblk 10637c478bd9Sstevel@tonic-gate * and oldblk's neighbor 10647c478bd9Sstevel@tonic-gate */ 10657c478bd9Sstevel@tonic-gate freeblk->size -= 10667c478bd9Sstevel@tonic-gate ( (char*)freeneighbor 10677c478bd9Sstevel@tonic-gate - (char*)oldblk ); 10687c478bd9Sstevel@tonic-gate /* 10697c478bd9Sstevel@tonic-gate * split the right fragment by 10707c478bd9Sstevel@tonic-gate * setting oldblk's neighbor's size 10717c478bd9Sstevel@tonic-gate */ 10727c478bd9Sstevel@tonic-gate oldneighbor->size = 10737c478bd9Sstevel@tonic-gate (char*)freeneighbor 10747c478bd9Sstevel@tonic-gate - (char*)oldneighbor; 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * return the fragments to free space 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate free(freeblk->data); 10797c478bd9Sstevel@tonic-gate free(oldneighbor->data); 10807c478bd9Sstevel@tonic-gate return(1); 10817c478bd9Sstevel@tonic-gate } /*else*/ 10827c478bd9Sstevel@tonic-gate } /*else*/ 10837c478bd9Sstevel@tonic-gate } /* else */ 10847c478bd9Sstevel@tonic-gate } /*while*/ 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate return(0); /* free block not found */ 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate /* 10907c478bd9Sstevel@tonic-gate * bool 10917c478bd9Sstevel@tonic-gate * morecore(nbytes) 10927c478bd9Sstevel@tonic-gate * Add a block of at least nbytes from end-of-memory to the 10937c478bd9Sstevel@tonic-gate * free space tree. 10947c478bd9Sstevel@tonic-gate * 10957c478bd9Sstevel@tonic-gate * return value: 10967c478bd9Sstevel@tonic-gate * true if at least n bytes can be allocated 10977c478bd9Sstevel@tonic-gate * false otherwise 10987c478bd9Sstevel@tonic-gate * 10997c478bd9Sstevel@tonic-gate * remarks: 11007c478bd9Sstevel@tonic-gate * 11017c478bd9Sstevel@tonic-gate * -- free space (delimited by the extern variable _ubound) is 11027c478bd9Sstevel@tonic-gate * extended by an amount determined by rounding nbytes up to 11037c478bd9Sstevel@tonic-gate * a multiple of the system page size. 11047c478bd9Sstevel@tonic-gate * 11057c478bd9Sstevel@tonic-gate * -- The lower bound of the heap is determined the first time 11067c478bd9Sstevel@tonic-gate * this routine is entered. It does NOT necessarily begin at 11077c478bd9Sstevel@tonic-gate * the end of static data space, since startup code (e.g., for 11087c478bd9Sstevel@tonic-gate * profiling) may have invoked sbrk() before we got here. 11097c478bd9Sstevel@tonic-gate */ 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate static bool 1112*5d54f3d8Smuffin morecore(uint nbytes) 11137c478bd9Sstevel@tonic-gate { 11147c478bd9Sstevel@tonic-gate Dblk p; 11157c478bd9Sstevel@tonic-gate Freehdr newhdr; 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate if (nbpg == 0) { 11187c478bd9Sstevel@tonic-gate nbpg = getpagesize(); 11197c478bd9Sstevel@tonic-gate /* hack to avoid fragmenting the heap with the first 11207c478bd9Sstevel@tonic-gate freehdr page */ 11217c478bd9Sstevel@tonic-gate if ((newhdr = getfreehdr()) == NIL) { 11227c478bd9Sstevel@tonic-gate /* Error message returned by getfreehdr() */ 11237c478bd9Sstevel@tonic-gate return(false); 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate (void)putfreehdr(newhdr); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate nbytes = roundup(nbytes, nbpg); 11287c478bd9Sstevel@tonic-gate p = (Dblk) sbrk((int)nbytes); 11297c478bd9Sstevel@tonic-gate if (p == (Dblk) -1) { 11307c478bd9Sstevel@tonic-gate if (errno == EAGAIN) errno = ENOMEM; 11317c478bd9Sstevel@tonic-gate return(false); /* errno = ENOMEM */ 11327c478bd9Sstevel@tonic-gate } 11337c478bd9Sstevel@tonic-gate if (_lbound == NULL) /* set _lbound the first time through */ 11347c478bd9Sstevel@tonic-gate _lbound = (char*) p; 11357c478bd9Sstevel@tonic-gate _ubound = (char *) p + nbytes; 11367c478bd9Sstevel@tonic-gate p->size = nbytes; 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate /* maintain statistics */ 11397c478bd9Sstevel@tonic-gate __mallinfo.arena = _ubound - _lbound; 11407c478bd9Sstevel@tonic-gate __mallinfo.uordbytes += nbytes; 11417c478bd9Sstevel@tonic-gate __mallinfo.ordblks++; 11427c478bd9Sstevel@tonic-gate __mallinfo.allocated++; 11437c478bd9Sstevel@tonic-gate 11447c478bd9Sstevel@tonic-gate free(p->data); 11457c478bd9Sstevel@tonic-gate return(true); 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate } /*morecore*/ 11487c478bd9Sstevel@tonic-gate 1149*5d54f3d8Smuffin 11507c478bd9Sstevel@tonic-gate /* 11517c478bd9Sstevel@tonic-gate * Get a free block header from the free header list. 11527c478bd9Sstevel@tonic-gate * When the list is empty, allocate an array of headers. 11537c478bd9Sstevel@tonic-gate * When the array is empty, allocate another one. 11547c478bd9Sstevel@tonic-gate * When we can't allocate another array, we're in deep weeds. 11557c478bd9Sstevel@tonic-gate */ 11567c478bd9Sstevel@tonic-gate static Freehdr 1157*5d54f3d8Smuffin getfreehdr(void) 11587c478bd9Sstevel@tonic-gate { 11597c478bd9Sstevel@tonic-gate Freehdr r; 1160*5d54f3d8Smuffin Dblk blk; 1161*5d54f3d8Smuffin uint size; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate if (freehdrlist != NIL) { 11647c478bd9Sstevel@tonic-gate r = freehdrlist; 11657c478bd9Sstevel@tonic-gate freehdrlist = freehdrlist->left; 11667c478bd9Sstevel@tonic-gate return(r); 11677c478bd9Sstevel@tonic-gate } 11687c478bd9Sstevel@tonic-gate if (nfreehdrs <= 0) { 11697c478bd9Sstevel@tonic-gate size = NFREE_HDRS*sizeof(struct freehdr) + ALIGNSIZ; 11707c478bd9Sstevel@tonic-gate blk = (Dblk) sbrk(size); 11717c478bd9Sstevel@tonic-gate if ((int)blk == -1) { 11727c478bd9Sstevel@tonic-gate malloc_debug(1); 11737c478bd9Sstevel@tonic-gate error("getfreehdr: out of memory"); 11747c478bd9Sstevel@tonic-gate if (errno == EAGAIN) errno = ENOMEM; 11757c478bd9Sstevel@tonic-gate return(NIL); 11767c478bd9Sstevel@tonic-gate } 11777c478bd9Sstevel@tonic-gate if (_lbound == NULL) /* set _lbound on first allocation */ 11787c478bd9Sstevel@tonic-gate _lbound = (char*)blk; 11797c478bd9Sstevel@tonic-gate blk->size = size; 11807c478bd9Sstevel@tonic-gate freehdrptr = (Freehdr)blk->data; 11817c478bd9Sstevel@tonic-gate nfreehdrs = NFREE_HDRS; 11827c478bd9Sstevel@tonic-gate _ubound = (char*) nextblk(blk,size); 11837c478bd9Sstevel@tonic-gate 11847c478bd9Sstevel@tonic-gate /* maintain statistics */ 11857c478bd9Sstevel@tonic-gate __mallinfo.arena = _ubound - _lbound; 11867c478bd9Sstevel@tonic-gate __mallinfo.treeoverhead += size; 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate nfreehdrs--; 11897c478bd9Sstevel@tonic-gate return(freehdrptr++); 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate /* 11937c478bd9Sstevel@tonic-gate * Free a free block header 11947c478bd9Sstevel@tonic-gate * Add it to the list of available headers. 11957c478bd9Sstevel@tonic-gate */ 1196*5d54f3d8Smuffin static void 1197*5d54f3d8Smuffin putfreehdr(Freehdr p) 11987c478bd9Sstevel@tonic-gate { 11997c478bd9Sstevel@tonic-gate p->left = freehdrlist; 12007c478bd9Sstevel@tonic-gate freehdrlist = p; 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate #ifndef DEBUG /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate /* 12067c478bd9Sstevel@tonic-gate * stubs for error handling and diagnosis routines. These are what 12077c478bd9Sstevel@tonic-gate * you get in the standard C library; for non-placebo diagnostics 12087c478bd9Sstevel@tonic-gate * load /usr/lib/malloc.debug.o with your program. 12097c478bd9Sstevel@tonic-gate */ 12107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1211*5d54f3d8Smuffin static void 1212*5d54f3d8Smuffin error(char *fmt, ...) 12137c478bd9Sstevel@tonic-gate { 12147c478bd9Sstevel@tonic-gate errno = EINVAL; 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate 1217*5d54f3d8Smuffin #endif /* !DEBUG <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate #ifdef DEBUG /* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */ 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate /* 12237c478bd9Sstevel@tonic-gate * malloc_debug(level) 12247c478bd9Sstevel@tonic-gate * 12257c478bd9Sstevel@tonic-gate * description: 12267c478bd9Sstevel@tonic-gate * 12277c478bd9Sstevel@tonic-gate * Controls the level of error diagnosis and consistency checking 12287c478bd9Sstevel@tonic-gate * done by malloc() and free(). level is interpreted as follows: 12297c478bd9Sstevel@tonic-gate * 12307c478bd9Sstevel@tonic-gate * 0: malloc() and free() return 0 if error detected in arguments 12317c478bd9Sstevel@tonic-gate * (errno is set to EINVAL) 12327c478bd9Sstevel@tonic-gate * 1: malloc() and free() abort if errors detected in arguments 12337c478bd9Sstevel@tonic-gate * 2: same as 1, but scan entire heap for errors on every call 12347c478bd9Sstevel@tonic-gate * to malloc() or free() 12357c478bd9Sstevel@tonic-gate * 12367c478bd9Sstevel@tonic-gate * function result: 12377c478bd9Sstevel@tonic-gate * returns the previous level of error reporting. 12387c478bd9Sstevel@tonic-gate */ 12397c478bd9Sstevel@tonic-gate int 1240*5d54f3d8Smuffin malloc_debug(int level) 12417c478bd9Sstevel@tonic-gate { 12427c478bd9Sstevel@tonic-gate int old_level; 12437c478bd9Sstevel@tonic-gate old_level = debug_level; 12447c478bd9Sstevel@tonic-gate debug_level = level; 1245*5d54f3d8Smuffin return (old_level); 12467c478bd9Sstevel@tonic-gate } 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate /* 12497c478bd9Sstevel@tonic-gate * check a free space tree pointer. Should be in 12507c478bd9Sstevel@tonic-gate * the static free pool or somewhere in the heap. 12517c478bd9Sstevel@tonic-gate */ 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate #define chkblk(p)\ 12547c478bd9Sstevel@tonic-gate if ( misaligned(p)\ 12557c478bd9Sstevel@tonic-gate || ((Dblk)(p) < (Dblk)_lbound || (Dblk)(p) > (Dblk)_ubound)){\ 12567c478bd9Sstevel@tonic-gate blkerror(p);\ 12577c478bd9Sstevel@tonic-gate return 0;\ 12587c478bd9Sstevel@tonic-gate } 12597c478bd9Sstevel@tonic-gate 12607c478bd9Sstevel@tonic-gate #define chkhdr(p) chkblk(p) 12617c478bd9Sstevel@tonic-gate 1262*5d54f3d8Smuffin static 1263*5d54f3d8Smuffin blkerror(Freehdr p) 12647c478bd9Sstevel@tonic-gate { 12657c478bd9Sstevel@tonic-gate error("Illegal block address (%#x)\n", (p)); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate 12687c478bd9Sstevel@tonic-gate /* 12697c478bd9Sstevel@tonic-gate * cartesian(p) 12707c478bd9Sstevel@tonic-gate * returns 1 if free space tree p satisfies internal consistency 12717c478bd9Sstevel@tonic-gate * checks. 12727c478bd9Sstevel@tonic-gate */ 12737c478bd9Sstevel@tonic-gate 12747c478bd9Sstevel@tonic-gate static int 1275*5d54f3d8Smuffin cartesian(Freehdr p) 12767c478bd9Sstevel@tonic-gate { 1277*5d54f3d8Smuffin Freehdr probe; 1278*5d54f3d8Smuffin Dblk db,pdb; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate if (p == NIL) /* no tree to test */ 12817c478bd9Sstevel@tonic-gate return 1; 12827c478bd9Sstevel@tonic-gate /* 12837c478bd9Sstevel@tonic-gate * check that root has a data block 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate chkhdr(p); 12867c478bd9Sstevel@tonic-gate pdb = p->block; 12877c478bd9Sstevel@tonic-gate chkblk(pdb); 12887c478bd9Sstevel@tonic-gate 12897c478bd9Sstevel@tonic-gate /* 12907c478bd9Sstevel@tonic-gate * check that the child blocks are no larger than the parent block. 12917c478bd9Sstevel@tonic-gate */ 12927c478bd9Sstevel@tonic-gate probe = p->left; 12937c478bd9Sstevel@tonic-gate if (probe != NIL) { 12947c478bd9Sstevel@tonic-gate chkhdr(probe); 12957c478bd9Sstevel@tonic-gate db = probe->block; 12967c478bd9Sstevel@tonic-gate chkblk(db); 12977c478bd9Sstevel@tonic-gate if (probe->size > p->size) /* child larger than parent */ 12987c478bd9Sstevel@tonic-gate return 0; 12997c478bd9Sstevel@tonic-gate } 13007c478bd9Sstevel@tonic-gate probe = p->right; 13017c478bd9Sstevel@tonic-gate if (probe != NIL) { 13027c478bd9Sstevel@tonic-gate chkhdr(probe); 13037c478bd9Sstevel@tonic-gate db = probe->block; 13047c478bd9Sstevel@tonic-gate chkblk(db); 13057c478bd9Sstevel@tonic-gate if (probe->size > p->size) /* child larger than parent */ 13067c478bd9Sstevel@tonic-gate return 0; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate /* 13097c478bd9Sstevel@tonic-gate * test data addresses in the left subtree, 13107c478bd9Sstevel@tonic-gate * starting at the left subroot and probing to 13117c478bd9Sstevel@tonic-gate * the right. All data addresses must be < p->block. 13127c478bd9Sstevel@tonic-gate */ 13137c478bd9Sstevel@tonic-gate probe = p->left; 13147c478bd9Sstevel@tonic-gate while (probe != NIL) { 13157c478bd9Sstevel@tonic-gate chkhdr(probe); 13167c478bd9Sstevel@tonic-gate db = probe->block; 13177c478bd9Sstevel@tonic-gate chkblk(db); 13187c478bd9Sstevel@tonic-gate if ( nextblk(db, probe->size) >= pdb ) /* overlap */ 13197c478bd9Sstevel@tonic-gate return 0; 13207c478bd9Sstevel@tonic-gate probe = probe->right; 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate /* 13237c478bd9Sstevel@tonic-gate * test data addresses in the right subtree, 13247c478bd9Sstevel@tonic-gate * starting at the right subroot and probing to 13257c478bd9Sstevel@tonic-gate * the left. All addresses must be > nextblk(p->block). 13267c478bd9Sstevel@tonic-gate */ 13277c478bd9Sstevel@tonic-gate pdb = nextblk(pdb, p->size); 13287c478bd9Sstevel@tonic-gate probe = p->right; 13297c478bd9Sstevel@tonic-gate while (probe != NIL) { 13307c478bd9Sstevel@tonic-gate chkhdr(probe); 13317c478bd9Sstevel@tonic-gate db = probe->block; 13327c478bd9Sstevel@tonic-gate chkblk(db); 13337c478bd9Sstevel@tonic-gate if (db == NULL || db <= pdb) /* overlap */ 13347c478bd9Sstevel@tonic-gate return 0; 13357c478bd9Sstevel@tonic-gate probe = probe->left; 13367c478bd9Sstevel@tonic-gate } 13377c478bd9Sstevel@tonic-gate return (cartesian(p->left) && cartesian(p->right)); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate /* 13417c478bd9Sstevel@tonic-gate * malloc_verify() 13427c478bd9Sstevel@tonic-gate * 13437c478bd9Sstevel@tonic-gate * This is a verification routine. It walks through all blocks 13447c478bd9Sstevel@tonic-gate * in the heap (both free and busy) and checks for bad blocks. 13457c478bd9Sstevel@tonic-gate * malloc_verify returns 1 if the heap contains no detectably bad 13467c478bd9Sstevel@tonic-gate * blocks; otherwise it returns 0. 13477c478bd9Sstevel@tonic-gate */ 13487c478bd9Sstevel@tonic-gate 13497c478bd9Sstevel@tonic-gate int 1350*5d54f3d8Smuffin malloc_verify(void) 13517c478bd9Sstevel@tonic-gate { 1352*5d54f3d8Smuffin int maxsize; 1353*5d54f3d8Smuffin int hdrsize; 1354*5d54f3d8Smuffin int size; 1355*5d54f3d8Smuffin Dblk p; 13567c478bd9Sstevel@tonic-gate uint lb,ub; 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate extern char end[]; 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate if (_lbound == NULL) /* no allocation yet */ 13617c478bd9Sstevel@tonic-gate return 1; 13627c478bd9Sstevel@tonic-gate 13637c478bd9Sstevel@tonic-gate /* 13647c478bd9Sstevel@tonic-gate * first check heap bounds pointers 13657c478bd9Sstevel@tonic-gate */ 13667c478bd9Sstevel@tonic-gate lb = (uint)end; 13677c478bd9Sstevel@tonic-gate ub = (uint)sbrk(0); 13687c478bd9Sstevel@tonic-gate 13697c478bd9Sstevel@tonic-gate if ((uint)_lbound < lb || (uint)_lbound > ub) { 13707c478bd9Sstevel@tonic-gate error("malloc_verify: illegal heap lower bound (%#x)\n", 13717c478bd9Sstevel@tonic-gate _lbound); 13727c478bd9Sstevel@tonic-gate return 0; 13737c478bd9Sstevel@tonic-gate } 13747c478bd9Sstevel@tonic-gate if ((uint)_ubound < lb || (uint)_ubound > ub) { 13757c478bd9Sstevel@tonic-gate error("malloc_verify: illegal heap upper bound (%#x)\n", 13767c478bd9Sstevel@tonic-gate _ubound); 13777c478bd9Sstevel@tonic-gate return 0; 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate maxsize = heapsize(); 13807c478bd9Sstevel@tonic-gate p = (Dblk)_lbound; 13817c478bd9Sstevel@tonic-gate while (p < (Dblk) _ubound) { 13827c478bd9Sstevel@tonic-gate size = p->size; 13837c478bd9Sstevel@tonic-gate if ( (size) < SMALLEST_BLK 13847c478bd9Sstevel@tonic-gate || (size) & (ALIGNSIZ-1) 13857c478bd9Sstevel@tonic-gate || (size) > heapsize() 13867c478bd9Sstevel@tonic-gate || ((char*)(p))+(size) > _ubound ) { 13877c478bd9Sstevel@tonic-gate error("malloc_verify: bad block size (%d) at %#x\n", 13887c478bd9Sstevel@tonic-gate size, p); 13897c478bd9Sstevel@tonic-gate return(0); /* Badness */ 13907c478bd9Sstevel@tonic-gate } 13917c478bd9Sstevel@tonic-gate p = nextblk(p, size); 13927c478bd9Sstevel@tonic-gate } 13937c478bd9Sstevel@tonic-gate if (p > (Dblk) _ubound) { 13947c478bd9Sstevel@tonic-gate error("malloc_verify: heap corrupted\n"); 13957c478bd9Sstevel@tonic-gate return(0); 13967c478bd9Sstevel@tonic-gate } 13977c478bd9Sstevel@tonic-gate if (!cartesian(_root)){ 13987c478bd9Sstevel@tonic-gate error("malloc_verify: free space tree corrupted\n"); 13997c478bd9Sstevel@tonic-gate return(0); 14007c478bd9Sstevel@tonic-gate } 14017c478bd9Sstevel@tonic-gate return(1); 14027c478bd9Sstevel@tonic-gate } 14037c478bd9Sstevel@tonic-gate 14047c478bd9Sstevel@tonic-gate /* 14057c478bd9Sstevel@tonic-gate * The following is a kludge to avoid dependency on stdio, which 14067c478bd9Sstevel@tonic-gate * uses malloc() and free(), one of which probably got us here in 14077c478bd9Sstevel@tonic-gate * the first place. 14087c478bd9Sstevel@tonic-gate */ 14097c478bd9Sstevel@tonic-gate 14107c478bd9Sstevel@tonic-gate #define putchar(c) (*buf++ = (c)) 14117c478bd9Sstevel@tonic-gate extern int fileno(); /*bletch*/ 14127c478bd9Sstevel@tonic-gate #define stderr 2 /*bletch*/ 14137c478bd9Sstevel@tonic-gate #define LBUFSIZ 256 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate static char stderrbuf[LBUFSIZ]; 14167c478bd9Sstevel@tonic-gate 14177c478bd9Sstevel@tonic-gate /* 14187c478bd9Sstevel@tonic-gate * Error routine. 14197c478bd9Sstevel@tonic-gate * If debug_level == 0, does nothing except set errno = EINVAL. 14207c478bd9Sstevel@tonic-gate * Otherwise, prints an error message to stderr and generates a 14217c478bd9Sstevel@tonic-gate * core image. 14227c478bd9Sstevel@tonic-gate */ 1423*5d54f3d8Smuffin static void 1424*5d54f3d8Smuffin error(char *fmt, ...) 14257c478bd9Sstevel@tonic-gate { 1426*5d54f3d8Smuffin static int n = 0; /* prevents infinite recursion when using stdio */ 1427*5d54f3d8Smuffin int nbytes; 1428*5d54f3d8Smuffin va_list ap; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate errno = EINVAL; 14317c478bd9Sstevel@tonic-gate if (debug_level == 0) 14327c478bd9Sstevel@tonic-gate return; 14337c478bd9Sstevel@tonic-gate if (!n++) { 1434*5d54f3d8Smuffin va_start(ap, fmt); 1435*5d54f3d8Smuffin nbytes = vsprintf(stderrbuf, fmt, ap); 1436*5d54f3d8Smuffin va_end(ap); 14377c478bd9Sstevel@tonic-gate stderrbuf[nbytes++] = '\n'; 14387c478bd9Sstevel@tonic-gate stderrbuf[nbytes] = '\0'; 14397c478bd9Sstevel@tonic-gate write(fileno(stderr), stderrbuf, nbytes); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate abort(); 14427c478bd9Sstevel@tonic-gate } 14437c478bd9Sstevel@tonic-gate 1444*5d54f3d8Smuffin #endif /* DEBUG <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */ 1445