*** empty log message ***
[bpt/guile.git] / libguile / gc-malloc.c
CommitLineData
c7743d02
HWN
1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42
43\f
44#include <stdio.h>
45#include <errno.h>
46#include <string.h>
47
48#ifdef __ia64__
49#include <ucontext.h>
50extern unsigned long * __libc_ia64_register_backing_store_base;
51#endif
52
53#include "libguile/_scm.h"
54#include "libguile/eval.h"
55#include "libguile/stime.h"
56#include "libguile/stackchk.h"
57#include "libguile/struct.h"
58#include "libguile/smob.h"
59#include "libguile/unif.h"
60#include "libguile/async.h"
61#include "libguile/ports.h"
62#include "libguile/root.h"
63#include "libguile/strings.h"
64#include "libguile/vectors.h"
65#include "libguile/weaks.h"
66#include "libguile/hashtab.h"
67#include "libguile/tags.h"
68
69#include "libguile/validate.h"
70#include "libguile/deprecation.h"
71#include "libguile/gc.h"
72
73#include "libguile/private-gc.h"
74
75#ifdef GUILE_DEBUG_MALLOC
76#include "libguile/debug-malloc.h"
77#endif
78
79#ifdef HAVE_MALLOC_H
80#include <malloc.h>
81#endif
82
83#ifdef HAVE_UNISTD_H
84#include <unistd.h>
85#endif
86
87/*
88 INIT_MALLOC_LIMIT is the initial amount of malloc usage which will
89 trigger a GC.
90
91 After startup (at the guile> prompt), we have approximately 100k of
92 alloced memory, which won't go away on GC. Let's set the init such
93 that we get a nice yield on the next allocation:
94*/
c2cbcc57 95#define SCM_DEFAULT_INIT_MALLOC_LIMIT 200*1024
c7743d02
HWN
96#define SCM_DEFAULT_MALLOC_MINYIELD 40
97
98
99static int scm_i_minyield_malloc;
100
101void
102scm_gc_init_malloc (void)
103{
104 scm_mtrigger = scm_getenv_int ("GUILE_INIT_MALLOC_LIMIT",
105 SCM_DEFAULT_INIT_MALLOC_LIMIT);
106 scm_i_minyield_malloc = scm_getenv_int ("GUILE_MIN_YIELD_MALLOC",
107 SCM_DEFAULT_MALLOC_MINYIELD);
108}
109
110
111\f
112/* Function for non-cell memory management.
113 */
114
c7743d02
HWN
115void *
116scm_realloc (void *mem, size_t size)
117{
118 void *ptr;
119
120 SCM_SYSCALL (ptr = realloc (mem, size));
121 if (ptr)
122 return ptr;
123
124 scm_i_sweep_all_segments ("realloc");
125
126 SCM_SYSCALL (ptr = realloc (mem, size));
127 if (ptr)
128 return ptr;
129
130 scm_igc ("realloc");
131 scm_i_sweep_all_segments ("realloc");
132
133 SCM_SYSCALL (ptr = realloc (mem, size));
134 if (ptr)
135 return ptr;
136
137 scm_memory_error ("realloc");
138}
139
39e8f371
HWN
140void *
141scm_malloc (size_t sz)
142{
143 return scm_realloc (NULL, sz);
144}
145
146
c7743d02
HWN
147char *
148scm_strndup (const char *str, size_t n)
149{
150 char *dst = scm_malloc (n+1);
151 memcpy (dst, str, n);
152 dst[n] = 0;
153 return dst;
154}
155
156char *
157scm_strdup (const char *str)
158{
159 return scm_strndup (str, strlen (str));
160}
161
162void
163scm_gc_register_collectable_memory (void *mem, size_t size, const char *what)
164{
165 scm_mallocated += size;
166
167 /*
168 we could finish the full sweep (without mark) here, but in
169 practice this turns out to be ineffective.
170 */
171
172 /*
173 A program that uses a lot of malloced collectable memory (vectors,
174 strings), will use a lot of memory off the cell-heap; it needs to
175 do GC more often (before cells are exhausted), otherwise swapping
176 and malloc management will tie it down.
177 */
178 if (scm_mallocated > scm_mtrigger)
179 {
180 long prev_alloced = scm_mallocated;
181 float yield;
182
183 scm_igc (what);
184 scm_i_sweep_all_segments("mtrigger");
185
c2cbcc57
HWN
186 yield = (prev_alloced - scm_mallocated) / (float) prev_alloced;
187 scm_gc_malloc_yield_percentage = (int) (100 * yield);
c7743d02
HWN
188 /*
189 fprintf (stderr, "prev %lud , now %lud, yield %4.2lf, want %d",
190 prev_alloced, scm_mallocated, 100.0*yield, scm_i_minyield_malloc);
191 */
192
193 if (yield < scm_i_minyield_malloc / 100.0)
194 {
195 /*
196 We make the trigger a little larger, even; If you have a
197 program that builds up a lot of data in strings, then the
198 desired yield will never be satisfied.
199
200 Instead of getting bogged down, we let the mtrigger grow
201 strongly with it.
202 */
203 scm_mtrigger = (scm_mallocated * 110) / (100 - scm_i_minyield_malloc);
204
205 /*
206 fprintf (stderr, "Mtrigger sweep: ineffective. New trigger %d\n", scm_mtrigger);
207 */
c7743d02 208 }
c2cbcc57
HWN
209
210
c7743d02
HWN
211 }
212
213#ifdef GUILE_DEBUG_MALLOC
214 if (mem)
215 scm_malloc_register (mem, what);
216#endif
217}
218
219void
220scm_gc_unregister_collectable_memory (void *mem, size_t size, const char *what)
221{
222 scm_mallocated -= size;
223 scm_gc_malloc_collected += size;
224
225#ifdef GUILE_DEBUG_MALLOC
226 if (mem)
227 scm_malloc_unregister (mem);
228#endif
229}
230
231void *
232scm_gc_malloc (size_t size, const char *what)
233{
234 /*
235 The straightforward implementation below has the problem
236 that it might call the GC twice, once in scm_malloc and then
237 again in scm_gc_register_collectable_memory. We don't really
238 want the second GC since it will not find new garbage.
239
240
241 Note: this is a theoretical peeve. In reality, malloc() never
242 returns NULL. Usually, memory is overcommitted, and when you try
243 to write it the program is killed with signal 11. --hwn
244 */
245
246 void *ptr = scm_malloc (size);
247 scm_gc_register_collectable_memory (ptr, size, what);
248 return ptr;
249}
250
39e8f371
HWN
251void *
252scm_gc_calloc (size_t size, const char *what)
253{
254 void *ptr = scm_gc_malloc (size, what);
255 memset (ptr, 0x0, size);
256 return ptr;
257}
258
259
c7743d02
HWN
260void *
261scm_gc_realloc (void *mem, size_t old_size, size_t new_size, const char *what)
262{
263 /* XXX - see scm_gc_malloc. */
264
265 void *ptr = scm_realloc (mem, new_size);
266 scm_gc_unregister_collectable_memory (mem, old_size, what);
267 scm_gc_register_collectable_memory (ptr, new_size, what);
268 return ptr;
269}
270
271void
272scm_gc_free (void *mem, size_t size, const char *what)
273{
274 scm_gc_unregister_collectable_memory (mem, size, what);
275 free (mem);
276}
277
278char *
279scm_gc_strndup (const char *str, size_t n, const char *what)
280{
281 char *dst = scm_gc_malloc (n+1, what);
282 memcpy (dst, str, n);
283 dst[n] = 0;
284 return dst;
285}
286
287char *
288scm_gc_strdup (const char *str, const char *what)
289{
290 return scm_gc_strndup (str, strlen (str), what);
291}
292
293#if SCM_ENABLE_DEPRECATED == 1
294
295/* {Deprecated front end to malloc}
296 *
297 * scm_must_malloc, scm_must_realloc, scm_must_free, scm_done_malloc,
298 * scm_done_free
299 *
300 * These functions provide services comparable to malloc, realloc, and
301 * free. They should be used when allocating memory that will be under
302 * control of the garbage collector, i.e., if the memory may be freed
303 * during garbage collection.
304 *
305 * They are deprecated because they weren't really used the way
306 * outlined above, and making sure to return the right amount from
307 * smob free routines was sometimes difficult when dealing with nested
308 * data structures. We basically want everybody to review their code
309 * and use the more symmetrical scm_gc_malloc/scm_gc_free functions
310 * instead. In some cases, where scm_must_malloc has been used
311 * incorrectly (i.e. for non-GC-able memory), use scm_malloc/free.
312 */
313
314void *
315scm_must_malloc (size_t size, const char *what)
316{
317 scm_c_issue_deprecation_warning
318 ("scm_must_malloc is deprecated. "
319 "Use scm_gc_malloc and scm_gc_free instead.");
320
321 return scm_gc_malloc (size, what);
322}
323
324void *
325scm_must_realloc (void *where,
326 size_t old_size,
327 size_t size,
328 const char *what)
329{
330 scm_c_issue_deprecation_warning
331 ("scm_must_realloc is deprecated. "
332 "Use scm_gc_realloc and scm_gc_free instead.");
333
334 return scm_gc_realloc (where, old_size, size, what);
335}
336
337char *
338scm_must_strndup (const char *str, size_t length)
339{
340 scm_c_issue_deprecation_warning
341 ("scm_must_strndup is deprecated. "
342 "Use scm_gc_strndup and scm_gc_free instead.");
343
344 return scm_gc_strndup (str, length, "string");
345}
346
347char *
348scm_must_strdup (const char *str)
349{
350 scm_c_issue_deprecation_warning
351 ("scm_must_strdup is deprecated. "
352 "Use scm_gc_strdup and scm_gc_free instead.");
353
354 return scm_gc_strdup (str, "string");
355}
356
357void
358scm_must_free (void *obj)
359#define FUNC_NAME "scm_must_free"
360{
361 scm_c_issue_deprecation_warning
362 ("scm_must_free is deprecated. "
363 "Use scm_gc_malloc and scm_gc_free instead.");
364
365#ifdef GUILE_DEBUG_MALLOC
366 scm_malloc_unregister (obj);
367#endif
368 if (obj)
369 free (obj);
370 else
371 SCM_MISC_ERROR ("freeing NULL pointer", SCM_EOL);
372}
373#undef FUNC_NAME
374
375
376void
377scm_done_malloc (long size)
378{
379 scm_c_issue_deprecation_warning
380 ("scm_done_malloc is deprecated. "
381 "Use scm_gc_register_collectable_memory instead.");
382
383 scm_gc_register_collectable_memory (NULL, size, "foreign mallocs");
384}
385
386void
387scm_done_free (long size)
388{
389 scm_c_issue_deprecation_warning
390 ("scm_done_free is deprecated. "
391 "Use scm_gc_unregister_collectable_memory instead.");
392
393 scm_gc_unregister_collectable_memory (NULL, size, "foreign mallocs");
394}
395
396#endif /* SCM_ENABLE_DEPRECATED == 1 */