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