1 /********************************************************************/
2 /* */
3 /* heaputl.c Procedures for heap allocation and maintenance. */
4 /* Copyright (C) 1989 - 2011 Thomas Mertes */
5 /* */
6 /* This file is part of the Seed7 Runtime Library. */
7 /* */
8 /* The Seed7 Runtime Library is free software; you can */
9 /* redistribute it and/or modify it under the terms of the GNU */
10 /* Lesser General Public License as published by the Free Software */
11 /* Foundation; either version 2.1 of the License, or (at your */
12 /* option) any later version. */
13 /* */
14 /* The Seed7 Runtime Library is distributed in the hope that it */
15 /* will be useful, but WITHOUT ANY WARRANTY; without even the */
16 /* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
17 /* PURPOSE. See the GNU Lesser General Public License for more */
18 /* details. */
19 /* */
20 /* You should have received a copy of the GNU Lesser General */
21 /* Public License along with this program; if not, write to the */
22 /* Free Software Foundation, Inc., 51 Franklin Street, */
23 /* Fifth Floor, Boston, MA 02110-1301, USA. */
24 /* */
25 /* Module: Seed7 Runtime Library */
26 /* File: seed7/src/heaputl.c */
27 /* Changes: 1992 - 1994, 2008, 2010 Thomas Mertes */
28 /* Content: Procedures for heap allocation and maintenance. */
29 /* */
30 /********************************************************************/
31
32 #define LOG_FUNCTIONS 0
33 #define VERBOSE_EXCEPTIONS 0
34
35 #include "version.h"
36
37 #include "stdlib.h"
38 #include "stdio.h"
39 #if HAS_GETRLIMIT && defined STACK_SIZE
40 /* In FreeBSD it is necessary to include <sys/types.h> before <sys/resource.h> */
41 #include "sys/types.h"
42 #include "sys/resource.h"
43 #endif
44
45 #include "common.h"
46 #include "data_rtl.h"
47 #include "rtl_err.h"
48
49 #undef EXTERN
50 #define EXTERN
51 #define DO_INIT
52 #include "heaputl.h"
53
54 /* Some compilers/linkers only support determining the stack size */
55 /* by defining a global variable. This variable must be set to the */
56 /* desired stack size. In this case the makefile defines the macro */
57 /* STACK_SIZE_DEFINITION which contains this variable definition. */
58 #ifdef STACK_SIZE_DEFINITION
59 STACK_SIZE_DEFINITION;
60 #endif
61
62 #if CHECK_STACK
63 char *stack_base = 0;
64 memSizeType max_stack_size = 0;
65 boolType interpreter_exception = FALSE;
66 #else
67 extern boolType interpreter_exception;
68 #endif
69
70
71
72 /**
73 * Set the stack size of the program.
74 * On some operating systems the default stack size is too small.
75 * On such systems 'setupStack' is used to request a bigger stack.
76 */
setupStack(void)77 void setupStack (void)
78
79 {
80 #if HAS_GETRLIMIT && defined STACK_SIZE
81 struct rlimit rlim;
82 #endif
83 #if CHECK_STACK
84 char aVariable;
85 #endif
86
87 /* setupStack */
88 logFunction(printf("setupStack\n"););
89 #if HAS_GETRLIMIT && defined STACK_SIZE
90 /* printf("STACK_SIZE: %ld\n", STACK_SIZE); */
91 if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
92 /* printf("old stack limit: %ld/%ld\n", (long) rlim.rlim_cur, (long) rlim.rlim_max); */
93 if (rlim.rlim_cur != RLIM_INFINITY && (rlim_t) STACK_SIZE > rlim.rlim_cur) {
94 if (rlim.rlim_max == RLIM_INFINITY || (rlim_t) STACK_SIZE <= rlim.rlim_max) {
95 rlim.rlim_cur = (rlim_t) STACK_SIZE;
96 } else {
97 rlim.rlim_cur = rlim.rlim_max;
98 } /* if */
99 setrlimit(RLIMIT_STACK, &rlim);
100 /* if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
101 printf("new stack limit: %ld/%ld\n", (long) rlim.rlim_cur, (long) rlim.rlim_max);
102 } ** if */
103 } /* if */
104 } /* if */
105 #endif
106 #if CHECK_STACK
107 stack_base = &aVariable;
108 /* printf("base: " F_U_MEM(8) "\n", (memSizeType) stack_base); */
109 #endif
110 logFunction(printf("setupStack -->\n"););
111 } /* setupStack */
112
113
114
115 #if CHECK_STACK
checkStack(boolType inLogMacro)116 boolType checkStack (boolType inLogMacro)
117
118 {
119 char aVariable;
120 boolType stackOverflow = FALSE;
121
122 /* checkStack */
123 #if STACK_GROWS_UPWARD
124 if (&aVariable - stack_base > max_stack_size &&
125 stack_base != 0) {
126 max_stack_size = (memSizeType) (&aVariable - stack_base);
127 } /* if */
128 #else
129 if (stack_base - &aVariable > max_stack_size &&
130 stack_base != 0) {
131 max_stack_size = (memSizeType) (stack_base - &aVariable);
132 } /* if */
133 #endif
134 /* This check is outside the maximum check on purpose. */
135 /* A new maximum can occur from a logFunction, but the */
136 /* check for the stack size limit can happen later, */
137 /* when the function is called from the interpreter. */
138 if (unlikely(max_stack_size > CHECKED_STACK_SIZE_LIMIT &&
139 inLogMacro != interpreter_exception)) {
140 /* The logFunctions (if inLogMacro is TRUE) should */
141 /* only trigger an exception for compiled programs */
142 /* (if interpreter_exception is FALSE). In the */
143 /* interpreter the stack checking is called from the */
144 /* function exec_action() (in this case inLogMacro */
145 /* is FALSE and interpreter_exception is TRUE). */
146 printf("\n*** Stack size above limit\n");
147 printf("size: " F_U_MEM(8) "\n", max_stack_size);
148 printf("limit: " F_U_MEM(8) "\n", (memSizeType) CHECKED_STACK_SIZE_LIMIT);
149 printf("base: " F_U_MEM(8) "\n", (memSizeType) stack_base);
150 printf("current: " F_U_MEM(8) "\n", (memSizeType) &aVariable);
151 if (inLogMacro) {
152 raise_error(MEMORY_ERROR);
153 } /* if */
154 stackOverflow = TRUE;
155 } /* if */
156 return stackOverflow;
157 } /* checkStack */
158
159
160
getMaxStackSize(void)161 memSizeType getMaxStackSize (void)
162
163 { /* getMaxStackSize */
164 return max_stack_size;
165 } /* getMaxStackSize */
166
167 #endif
168
169
170
171 #if WITH_STRI_CAPACITY
172 /**
173 * Enlarge the capacity of a string.
174 * This function is called from the macro GROW_STRI, if the
175 * capacity of a string is not sufficient. GrowStri enlarges the
176 * capacity such that at least 'len' characters fit into it.
177 * It is assumed that 'stri' will grow further, therefore the
178 * capacity is usually doubled.
179 * @param stri String for which the capacity is enlarged.
180 * @param len Length of the string that will be assigned.
181 * @return the enlarged string, or NULL if the allocation failed.
182 */
growStri(striType stri,memSizeType len)183 striType growStri (striType stri, memSizeType len)
184
185 {
186 memSizeType newCapacity;
187 striType result;
188
189 /* growStri */
190 if (unlikely(len > MAX_STRI_LEN)) {
191 result = NULL;
192 } else {
193 if (2 * stri->capacity >= len) {
194 newCapacity = 2 * stri->capacity;
195 } else {
196 newCapacity = 2 * len;
197 } /* if */
198 if (newCapacity < MIN_GROW_SHRINK_CAPACITY) {
199 newCapacity = MIN_GROW_SHRINK_CAPACITY;
200 } else if (unlikely(newCapacity > MAX_STRI_LEN)) {
201 newCapacity = MAX_STRI_LEN;
202 } /* if */
203 /* printf("growStri(" FMT_X_MEM ", " FMT_U_MEM
204 ") size=" FMT_U_MEM ", capacity=" FMT_U_MEM ", newCapacity="
205 FMT_U_MEM ", siz_stri=" FMT_U_MEM ", sizeof=" FMT_U_MEM "\n",
206 (memSizeType) stri, len, stri->size, stri->capacity, newCapacity,
207 SIZ_STRI(newCapacity), sizeof(striRecord));
208 fflush(stdout); */
209 result = REALLOC_HEAP(stri, striType, SIZ_STRI(newCapacity));
210 if (unlikely(result == NULL)) {
211 do {
212 newCapacity = (newCapacity + len) / 2;
213 /* printf("newCapacity: " FMT_U_MEM ", siz_stri=" FMT_U_MEM "\n",
214 newCapacity, SIZ_STRI(newCapacity));
215 fflush(stdout); */
216 result = REALLOC_HEAP(stri, striType, SIZ_STRI(newCapacity));
217 } while (result == NULL && newCapacity != len);
218 } /* if */
219 if (likely(result != NULL)) {
220 #if ALLOW_STRITYPE_SLICES
221 result->mem = result->mem1;
222 #endif
223 COUNT3_STRI(result->capacity, newCapacity);
224 result->capacity = newCapacity;
225 } else {
226 logError(printf("growStri(" FMT_X_MEM " (capacity=" FMT_U_MEM "), "
227 FMT_U_MEM ") failed\n",
228 (memSizeType) stri, stri->capacity, len););
229 /* heapStatistic(); */
230 } /* if */
231 } /* if */
232 logFunction(printf("growStri --> " FMT_X_MEM "\n", (memSizeType) result);
233 fflush(stdout););
234 return result;
235 } /* growStri */
236
237
238
239 /**
240 * Reduce the capacity of a string.
241 * This function is called from the macro SHRINK_STRI, if the
242 * capacity of a string is much too large. ShrinkStri reduces the
243 * capacity, but it leaves room, such that it can grow again.
244 * @param stri String for which the capacity is reduced.
245 * @param len Length of the string that will be assigned.
246 * @return the reduced string.
247 */
shrinkStri(striType stri,memSizeType len)248 striType shrinkStri (striType stri, memSizeType len)
249
250 {
251 memSizeType newCapacity;
252 striType result;
253
254 /* shrinkStri */
255 newCapacity = 2 * len;
256 /* printf("shrinkStri(%lX, %lu) size=%u, capacity=%u, newCapacity=%u, siz_stri=%u, sizeof=%u\n",
257 stri, len, stri->size, stri->capacity, newCapacity, SIZ_STRI(newCapacity), sizeof(striRecord));
258 fflush(stdout); */
259 result = REALLOC_HEAP(stri, striType, SIZ_STRI(newCapacity));
260 #if ALLOW_STRITYPE_SLICES
261 result->mem = result->mem1;
262 #endif
263 COUNT3_STRI(result->capacity, newCapacity);
264 result->capacity = newCapacity;
265 return result;
266 } /* shrinkStri */
267 #endif
268
269
270
271 #ifdef OUT_OF_ORDER
freeStriFreelist(void)272 void freeStriFreelist (void)
273
274 {
275 freeListElemType elem;
276 striType stri;
277 #if WITH_STRI_CAPACITY
278 memSizeType capacity;
279 #endif
280
281 /* freeStriFreelist */
282 #if WITH_STRI_CAPACITY
283 for (capacity = 0; capacity < STRI_FREELIST_ARRAY_SIZE; capacity++) {
284 elem = sflist[capacity];
285 while (elem != NULL) {
286 stri = (striType) elem;
287 elem = elem->next;
288 HEAP_FREE_STRI(stri, capacity);
289 sflist_allowed[capacity]++;
290 } /* while */
291 sflist[capacity] = NULL;
292 } /* for */
293 #else
294 elem = sflist;
295 while (elem != NULL) {
296 stri = (striType) elem;
297 elem = elem->next;
298 HEAP_FREE_STRI(stri, 1);
299 sflist_allowed++;
300 } /* while */
301 sflist = NULL;
302 #endif
303 } /* freeStriFreelist */
304
305
306
freelistStatistic(void)307 void freelistStatistic (void)
308
309 {
310 freeListElemType elem;
311 #if WITH_STRI_CAPACITY
312 memSizeType capacity;
313 unsigned int sflist_size[STRI_FREELIST_ARRAY_SIZE];
314 #else
315 unsigned int sflist_size;
316 #endif
317
318 /* freelistStatistic */
319 #if WITH_STRI_CAPACITY
320 for (capacity = 0; capacity < STRI_FREELIST_ARRAY_SIZE; capacity++) {
321 sflist_size[capacity] = sflist_allowed[capacity];
322 elem = sflist[capacity];
323 while (elem != NULL) {
324 elem = elem->next;
325 sflist_size[capacity]++;
326 } /* while */
327 printf("sflist_size[" FMT_U_MEM "]: %u\n", capacity, sflist_size[capacity]);
328 } /* for */
329 #else
330 sflist_size = sflist_allowed;
331 elem = sflist;
332 while (elem != NULL) {
333 elem = elem->next;
334 sflist_size++;
335 } /* while */
336 printf("sflist_size: %u\n", sflist_size);
337 #endif
338 } /* freelistStatistic */
339 #endif
340
341
342
343 #if !DO_HEAP_STATISTIC
heapStatistic(void)344 void heapStatistic (void)
345
346 { /* heapStatistic */
347 printf("heap statistic not supported - Set DO_HEAP_STATISTIC in config.h, when you compile Seed7.\n");
348 } /* heapStatistic */
349 #endif
350