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 182 /* address of header */ 183 184 ((header *)new)->h.next = last_alloca_header; 185 ((header *)new)->h.deep = depth; 186 187 last_alloca_header = (header *)new; 188 189 /* User storage begins just after header. */ 190 191 return (pointer)((char *)new + sizeof(header)); 192 } 193 } 194 195 #endif /* no alloca */ 196