|
|
1.1 ! root 1: /* ! 2: alloca -- (mostly) portable public-domain implementation -- D A Gwyn ! 3: ! 4: last edit: 86/05/30 rms ! 5: include config.h, since on VMS it renames some symbols. ! 6: Use xmalloc instead of malloc. ! 7: ! 8: This implementation of the PWB library alloca() function, ! 9: which is used to allocate space off the run-time stack so ! 10: that it is automatically reclaimed upon procedure exit, ! 11: was inspired by discussions with J. Q. Johnson of Cornell. ! 12: ! 13: It should work under any C implementation that uses an ! 14: actual procedure stack (as opposed to a linked list of ! 15: frames). There are some preprocessor constants that can ! 16: be defined when compiling for your specific system, for ! 17: improved efficiency; however, the defaults should be okay. ! 18: ! 19: The general concept of this implementation is to keep ! 20: track of all alloca()-allocated blocks, and reclaim any ! 21: that are found to be deeper in the stack than the current ! 22: invocation. This heuristic does not reclaim storage as ! 23: soon as it becomes invalid, but it will do so eventually. ! 24: ! 25: As a special case, alloca(0) reclaims storage without ! 26: allocating any. It is a good idea to use alloca(0) in ! 27: your main control loop, etc. to force garbage collection. ! 28: */ ! 29: #ifndef lint ! 30: static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */ ! 31: #endif ! 32: ! 33: #ifdef emacs ! 34: #include "config.h" ! 35: #ifdef static ! 36: /* actually, only want this if static is defined as "" ! 37: -- this is for usg, in which emacs must undefine static ! 38: in order to make unexec workable ! 39: */ ! 40: #ifndef STACK_DIRECTION ! 41: you ! 42: lose ! 43: -- must know STACK_DIRECTION at compile-time ! 44: #endif /* STACK_DIRECTION undefined */ ! 45: #endif /* static */ ! 46: #endif /* emacs */ ! 47: ! 48: #ifndef alloca /* If compiling with GCC, this file's not needed. */ ! 49: ! 50: #ifdef __STDC__ ! 51: typedef void *pointer; /* generic pointer type */ ! 52: #else ! 53: typedef char *pointer; /* generic pointer type */ ! 54: #endif ! 55: ! 56: #define NULL 0 /* null pointer constant */ ! 57: ! 58: extern void free(); ! 59: extern pointer xmalloc(); ! 60: ! 61: /* ! 62: Define STACK_DIRECTION if you know the direction of stack ! 63: growth for your system; otherwise it will be automatically ! 64: deduced at run-time. ! 65: ! 66: STACK_DIRECTION > 0 => grows toward higher addresses ! 67: STACK_DIRECTION < 0 => grows toward lower addresses ! 68: STACK_DIRECTION = 0 => direction of growth unknown ! 69: */ ! 70: ! 71: #ifndef STACK_DIRECTION ! 72: #define STACK_DIRECTION 0 /* direction unknown */ ! 73: #endif ! 74: ! 75: #if STACK_DIRECTION != 0 ! 76: ! 77: #define STACK_DIR STACK_DIRECTION /* known at compile-time */ ! 78: ! 79: #else /* STACK_DIRECTION == 0; need run-time code */ ! 80: ! 81: static int stack_dir; /* 1 or -1 once known */ ! 82: #define STACK_DIR stack_dir ! 83: ! 84: static void ! 85: find_stack_direction (/* void */) ! 86: { ! 87: static char *addr = NULL; /* address of first ! 88: `dummy', once known */ ! 89: auto char dummy; /* to get stack address */ ! 90: ! 91: if (addr == NULL) ! 92: { /* initial entry */ ! 93: addr = &dummy; ! 94: ! 95: find_stack_direction (); /* recurse once */ ! 96: } ! 97: else /* second entry */ ! 98: if (&dummy > addr) ! 99: stack_dir = 1; /* stack grew upward */ ! 100: else ! 101: stack_dir = -1; /* stack grew downward */ ! 102: } ! 103: ! 104: #endif /* STACK_DIRECTION == 0 */ ! 105: ! 106: /* ! 107: An "alloca header" is used to: ! 108: (a) chain together all alloca()ed blocks; ! 109: (b) keep track of stack depth. ! 110: ! 111: It is very important that sizeof(header) agree with malloc() ! 112: alignment chunk size. The following default should work okay. ! 113: */ ! 114: ! 115: #ifndef ALIGN_SIZE ! 116: #define ALIGN_SIZE sizeof(double) ! 117: #endif ! 118: ! 119: typedef union hdr ! 120: { ! 121: char align[ALIGN_SIZE]; /* to force sizeof(header) */ ! 122: struct ! 123: { ! 124: union hdr *next; /* for chaining headers */ ! 125: char *deep; /* for stack depth measure */ ! 126: } h; ! 127: } header; ! 128: ! 129: /* ! 130: alloca( size ) returns a pointer to at least `size' bytes of ! 131: storage which will be automatically reclaimed upon exit from ! 132: the procedure that called alloca(). Originally, this space ! 133: was supposed to be taken from the current stack frame of the ! 134: caller, but that method cannot be made to work for some ! 135: implementations of C, for example under Gould's UTX/32. ! 136: */ ! 137: ! 138: static header *last_alloca_header = NULL; /* -> last alloca header */ ! 139: ! 140: pointer ! 141: alloca (size) /* returns pointer to storage */ ! 142: unsigned size; /* # bytes to allocate */ ! 143: { ! 144: auto char probe; /* probes stack depth: */ ! 145: register char *depth = &probe; ! 146: ! 147: #if STACK_DIRECTION == 0 ! 148: if (STACK_DIR == 0) /* unknown growth direction */ ! 149: find_stack_direction (); ! 150: #endif ! 151: ! 152: /* Reclaim garbage, defined as all alloca()ed storage that ! 153: was allocated from deeper in the stack than currently. */ ! 154: ! 155: { ! 156: register header *hp; /* traverses linked list */ ! 157: ! 158: for (hp = last_alloca_header; hp != NULL;) ! 159: if ((STACK_DIR > 0 && hp->h.deep > depth) ! 160: || (STACK_DIR < 0 && hp->h.deep < depth)) ! 161: { ! 162: register header *np = hp->h.next; ! 163: ! 164: free ((pointer) hp); /* collect garbage */ ! 165: ! 166: hp = np; /* -> next header */ ! 167: } ! 168: else ! 169: break; /* rest are not deeper */ ! 170: ! 171: last_alloca_header = hp; /* -> last valid storage */ ! 172: } ! 173: ! 174: if (size == 0) ! 175: return NULL; /* no allocation required */ ! 176: ! 177: /* Allocate combined header + user data storage. */ ! 178: ! 179: { ! 180: register pointer new = xmalloc (sizeof (header) + size); ! 181: /* address of header */ ! 182: ! 183: ((header *)new)->h.next = last_alloca_header; ! 184: ((header *)new)->h.deep = depth; ! 185: ! 186: last_alloca_header = (header *)new; ! 187: ! 188: /* User storage begins just after header. */ ! 189: ! 190: return (pointer)((char *)new + sizeof(header)); ! 191: } ! 192: } ! 193: ! 194: #endif /* no alloca */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.