|
|
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.