|
|
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: #ifdef X3J11 ! 49: typedef void *pointer; /* generic pointer type */ ! 50: #else ! 51: typedef char *pointer; /* generic pointer type */ ! 52: #endif ! 53: ! 54: #define NULL 0 /* null pointer constant */ ! 55: ! 56: extern void free(); ! 57: extern pointer xmalloc(); ! 58: ! 59: /* ! 60: Define STACK_DIRECTION if you know the direction of stack ! 61: growth for your system; otherwise it will be automatically ! 62: deduced at run-time. ! 63: ! 64: STACK_DIRECTION > 0 => grows toward higher addresses ! 65: STACK_DIRECTION < 0 => grows toward lower addresses ! 66: STACK_DIRECTION = 0 => direction of growth unknown ! 67: */ ! 68: ! 69: #ifndef STACK_DIRECTION ! 70: #define STACK_DIRECTION 0 /* direction unknown */ ! 71: #endif ! 72: ! 73: #if STACK_DIRECTION != 0 ! 74: ! 75: #define STACK_DIR STACK_DIRECTION /* known at compile-time */ ! 76: ! 77: #else /* STACK_DIRECTION == 0; need run-time code */ ! 78: ! 79: static int stack_dir; /* 1 or -1 once known */ ! 80: #define STACK_DIR stack_dir ! 81: ! 82: static void ! 83: find_stack_direction (/* void */) ! 84: { ! 85: static char *addr = NULL; /* address of first ! 86: `dummy', once known */ ! 87: auto char dummy; /* to get stack address */ ! 88: ! 89: if (addr == NULL) ! 90: { /* initial entry */ ! 91: addr = &dummy; ! 92: ! 93: find_stack_direction (); /* recurse once */ ! 94: } ! 95: else /* second entry */ ! 96: if (&dummy > addr) ! 97: stack_dir = 1; /* stack grew upward */ ! 98: else ! 99: stack_dir = -1; /* stack grew downward */ ! 100: } ! 101: ! 102: #endif /* STACK_DIRECTION == 0 */ ! 103: ! 104: /* ! 105: An "alloca header" is used to: ! 106: (a) chain together all alloca()ed blocks; ! 107: (b) keep track of stack depth. ! 108: ! 109: It is very important that sizeof(header) agree with malloc() ! 110: alignment chunk size. The following default should work okay. ! 111: */ ! 112: ! 113: #ifndef ALIGN_SIZE ! 114: #define ALIGN_SIZE sizeof(double) ! 115: #endif ! 116: ! 117: typedef union hdr ! 118: { ! 119: char align[ALIGN_SIZE]; /* to force sizeof(header) */ ! 120: struct ! 121: { ! 122: union hdr *next; /* for chaining headers */ ! 123: char *deep; /* for stack depth measure */ ! 124: } h; ! 125: } header; ! 126: ! 127: /* ! 128: alloca( size ) returns a pointer to at least `size' bytes of ! 129: storage which will be automatically reclaimed upon exit from ! 130: the procedure that called alloca(). Originally, this space ! 131: was supposed to be taken from the current stack frame of the ! 132: caller, but that method cannot be made to work for some ! 133: implementations of C, for example under Gould's UTX/32. ! 134: */ ! 135: ! 136: static header *last_alloca_header = NULL; /* -> last alloca header */ ! 137: ! 138: pointer ! 139: alloca (size) /* returns pointer to storage */ ! 140: unsigned size; /* # bytes to allocate */ ! 141: { ! 142: auto char probe; /* probes stack depth: */ ! 143: register char *depth = &probe; ! 144: ! 145: #if STACK_DIRECTION == 0 ! 146: if (STACK_DIR == 0) /* unknown growth direction */ ! 147: find_stack_direction (); ! 148: #endif ! 149: ! 150: /* Reclaim garbage, defined as all alloca()ed storage that ! 151: was allocated from deeper in the stack than currently. */ ! 152: ! 153: { ! 154: register header *hp; /* traverses linked list */ ! 155: ! 156: for (hp = last_alloca_header; hp != NULL;) ! 157: if (STACK_DIR > 0 && hp->h.deep > depth ! 158: || STACK_DIR < 0 && hp->h.deep < depth) ! 159: { ! 160: register header *np = hp->h.next; ! 161: ! 162: free ((pointer) hp); /* collect garbage */ ! 163: ! 164: hp = np; /* -> next header */ ! 165: } ! 166: else ! 167: break; /* rest are not deeper */ ! 168: ! 169: last_alloca_header = hp; /* -> last valid storage */ ! 170: } ! 171: ! 172: if (size == 0) ! 173: return NULL; /* no allocation required */ ! 174: ! 175: /* Allocate combined header + user data storage. */ ! 176: ! 177: { ! 178: register pointer new = xmalloc (sizeof (header) + size); ! 179: /* address of header */ ! 180: ! 181: ((header *)new)->h.next = last_alloca_header; ! 182: ((header *)new)->h.deep = depth; ! 183: ! 184: last_alloca_header = (header *)new; ! 185: ! 186: /* User storage begins just after header. */ ! 187: ! 188: return (pointer)((char *)new + sizeof(header)); ! 189: } ! 190: } ! 191:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.