Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4973 | right-hear | 1 | /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */ |
2 | /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ |
||
3 | /* alloca.c -- allocate automatically reclaimed memory |
||
4 | (Mostly) portable public-domain implementation -- 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 | J.Otto Tennant |
||
11 | |||
12 | There are some preprocessor constants that can |
||
13 | be defined when compiling for your specific system, for |
||
14 | improved efficiency; however, the defaults should be okay. |
||
15 | |||
16 | The general concept of this implementation is to keep |
||
17 | track of all alloca-allocated blocks, and reclaim any |
||
18 | that are found to be deeper in the stack than the current |
||
19 | invocation. This heuristic does not reclaim storage as |
||
20 | soon as it becomes invalid, but it will do so eventually. |
||
21 | |||
22 | As a special case, alloca(0) reclaims storage without |
||
23 | allocating any. It is a good idea to use alloca(0) in |
||
24 | your main control loop, etc. to force garbage collection. */ |
||
25 | |||
26 | #include |
||
27 | |||
28 | #ifdef alloca |
||
29 | #undef alloca |
||
30 | #endif |
||
31 | |||
32 | /* If your stack is a linked list of frames, you have to |
||
33 | provide an "address metric" ADDRESS_FUNCTION macro. */ |
||
34 | |||
35 | #define ADDRESS_FUNCTION(arg) &(arg) |
||
36 | |||
37 | #define NULL 0 |
||
38 | |||
39 | /* Define STACK_DIRECTION if you know the direction of stack |
||
40 | growth for your system; otherwise it will be automatically |
||
41 | deduced at run-time. |
||
42 | |||
43 | STACK_DIRECTION > 0 => grows toward higher addresses |
||
44 | STACK_DIRECTION < 0 => grows toward lower addresses |
||
45 | STACK_DIRECTION = 0 => direction of growth unknown */ |
||
46 | |||
47 | #define STACK_DIRECTION -1 |
||
48 | |||
49 | #define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ |
||
50 | |||
51 | /* An "alloca header" is used to: |
||
52 | (a) chain together all alloca'ed blocks; |
||
53 | (b) keep track of stack depth. |
||
54 | |||
55 | It is very important that sizeof(header) agree with malloc |
||
56 | alignment chunk size. The following default should work okay. */ |
||
57 | |||
58 | #ifndef ALIGN_SIZE |
||
59 | #define ALIGN_SIZE sizeof(double) |
||
60 | #endif |
||
61 | |||
62 | typedef union hdr |
||
63 | { |
||
64 | char align[ALIGN_SIZE]; /* To force sizeof(header). */ |
||
65 | struct |
||
66 | { |
||
67 | union hdr *next; /* For chaining headers. */ |
||
68 | char *deep; /* For stack depth measure. */ |
||
69 | } h; |
||
70 | } header; |
||
71 | |||
72 | static header *last_alloca_header = NULL; /* -> last alloca header. */ |
||
73 | |||
74 | /* Return a pointer to at least SIZE bytes of storage, |
||
75 | which will be automatically reclaimed upon exit from |
||
76 | the procedure that called alloca. Originally, this space |
||
77 | was supposed to be taken from the current stack frame of the |
||
78 | caller, but that method cannot be made to work for some |
||
79 | implementations of C, for example under Gould's UTX/32. */ |
||
80 | |||
81 | void * |
||
82 | alloca(size_t size) |
||
83 | { |
||
84 | char probe; /* Probes stack depth: */ |
||
85 | char *depth = &probe; |
||
86 | |||
87 | /* Reclaim garbage, defined as all alloca storage that |
||
88 | was allocated from deeper in the stack than currently. */ |
||
89 | { |
||
90 | header *hp; /* Traverses linked list. */ |
||
91 | |||
92 | for (hp = last_alloca_header; hp != NULL;) |
||
93 | if ((STACK_DIR > 0 && hp->h.deep > depth) |
||
94 | || (STACK_DIR < 0 && hp->h.deep < depth)) |
||
95 | { |
||
96 | header *np = hp->h.next; |
||
97 | |||
98 | free ((void *) hp); /* Collect garbage. */ |
||
99 | |||
100 | hp = np; /* -> next header. */ |
||
101 | } |
||
102 | else |
||
103 | break; /* Rest are not deeper. */ |
||
104 | |||
105 | last_alloca_header = hp; /* -> last valid storage. */ |
||
106 | } |
||
107 | |||
108 | if (size == 0) |
||
109 | return NULL; /* No allocation required. */ |
||
110 | |||
111 | /* Allocate combined header + user data storage. */ |
||
112 | |||
113 | { |
||
114 | void * newp = malloc (sizeof (header) + size); |
||
115 | if (newp == 0) |
||
116 | abort(); |
||
117 | /* Address of header. */ |
||
118 | |||
119 | ((header *) newp)->h.next = last_alloca_header; |
||
120 | ((header *) newp)->h.deep = depth; |
||
121 | |||
122 | last_alloca_header = (header *) newp; |
||
123 | |||
124 | /* User storage begins just after header. */ |
||
125 | |||
126 | return (void *) ((char *) newp + sizeof (header)); |
||
127 | } |
||
128 | }>>> |