source: trunk/src/gcc/boehm-gc/misc.c@ 2013

Last change on this file since 2013 was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 29.9 KB
Line 
1/*
2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
4 * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
5 *
6 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
8 *
9 * Permission is hereby granted to use or copy this program
10 * for any purpose, provided the above notices are retained on all copies.
11 * Permission to modify the code and to distribute modified code is granted,
12 * provided the above notices are retained, and a notice that the code was
13 * modified is included with the above copyright notice.
14 */
15/* Boehm, July 31, 1995 5:02 pm PDT */
16
17
18#include <stdio.h>
19#include <limits.h>
20#ifndef _WIN32_WCE
21#include <signal.h>
22#endif
23
24#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */
25#include "private/gc_pmark.h"
26
27#ifdef GC_SOLARIS_THREADS
28# include <sys/syscall.h>
29#endif
30#if defined(MSWIN32) || defined(MSWINCE)
31# define WIN32_LEAN_AND_MEAN
32# define NOSERVICE
33# include <windows.h>
34# include <tchar.h>
35#endif
36
37# ifdef THREADS
38# ifdef PCR
39# include "il/PCR_IL.h"
40 PCR_Th_ML GC_allocate_ml;
41# else
42# ifdef SRC_M3
43 /* Critical section counter is defined in the M3 runtime */
44 /* That's all we use. */
45# else
46# ifdef GC_SOLARIS_THREADS
47 mutex_t GC_allocate_ml; /* Implicitly initialized. */
48# else
49# ifdef GC_WIN32_THREADS
50# if !defined(GC_NOT_DLL) && (defined(_DLL) || defined(GC_DLL))
51 __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
52# else
53 CRITICAL_SECTION GC_allocate_ml;
54# endif
55# else
56# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
57# if defined(USE_SPIN_LOCK)
58 pthread_t GC_lock_holder = NO_THREAD;
59# else
60 pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
61 pthread_t GC_lock_holder = NO_THREAD;
62 /* Used only for assertions, and to prevent */
63 /* recursive reentry in the system call wrapper. */
64# endif
65# else
66 --> declare allocator lock here
67# endif
68# endif
69# endif
70# endif
71# endif
72# endif
73
74#if defined(NOSYS) || defined(ECOS)
75#undef STACKBASE
76#endif
77
78/* Dont unnecessarily call GC_register_main_static_data() in case */
79/* dyn_load.c isn't linked in. */
80#ifdef DYNAMIC_LOADING
81# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
82#else
83# define GC_REGISTER_MAIN_STATIC_DATA() TRUE
84#endif
85
86GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
87
88
89GC_bool GC_debugging_started = FALSE;
90 /* defined here so we don't have to load debug_malloc.o */
91
92void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
93
94void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
95
96ptr_t GC_stackbottom = 0;
97
98#ifdef IA64
99 ptr_t GC_register_stackbottom = 0;
100#endif
101
102GC_bool GC_dont_gc = 0;
103
104GC_bool GC_dont_precollect = 0;
105
106GC_bool GC_quiet = 0;
107
108GC_bool GC_print_stats = 0;
109
110GC_bool GC_print_back_height = 0;
111
112#ifdef FIND_LEAK
113 int GC_find_leak = 1;
114#else
115 int GC_find_leak = 0;
116#endif
117
118#ifdef ALL_INTERIOR_POINTERS
119 int GC_all_interior_pointers = 1;
120#else
121 int GC_all_interior_pointers = 0;
122#endif
123
124long GC_large_alloc_warn_interval = 5;
125 /* Interval between unsuppressed warnings. */
126
127long GC_large_alloc_warn_suppressed = 0;
128 /* Number of warnings suppressed so far. */
129
130/*ARGSUSED*/
131GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
132{
133 return(0);
134}
135
136GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
137
138extern signed_word GC_mem_found;
139
140# ifdef MERGE_SIZES
141 /* Set things up so that GC_size_map[i] >= words(i), */
142 /* but not too much bigger */
143 /* and so that size_map contains relatively few distinct entries */
144 /* This is stolen from Russ Atkinson's Cedar quantization */
145 /* alogrithm (but we precompute it). */
146
147
148 void GC_init_size_map()
149 {
150 register unsigned i;
151
152 /* Map size 0 to something bigger. */
153 /* This avoids problems at lower levels. */
154 /* One word objects don't have to be 2 word aligned, */
155 /* unless we're using mark bytes. */
156 for (i = 0; i < sizeof(word); i++) {
157 GC_size_map[i] = MIN_WORDS;
158 }
159# if MIN_WORDS > 1
160 GC_size_map[sizeof(word)] = MIN_WORDS;
161# else
162 GC_size_map[sizeof(word)] = ROUNDED_UP_WORDS(sizeof(word));
163# endif
164 for (i = sizeof(word) + 1; i <= 8 * sizeof(word); i++) {
165 GC_size_map[i] = ALIGNED_WORDS(i);
166 }
167 for (i = 8*sizeof(word) + 1; i <= 16 * sizeof(word); i++) {
168 GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 1) & (~1);
169 }
170# ifdef GC_GCJ_SUPPORT
171 /* Make all sizes up to 32 words predictable, so that a */
172 /* compiler can statically perform the same computation, */
173 /* or at least a computation that results in similar size */
174 /* classes. */
175 for (i = 16*sizeof(word) + 1; i <= 32 * sizeof(word); i++) {
176 GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 3) & (~3);
177 }
178# endif
179 /* We leave the rest of the array to be filled in on demand. */
180 }
181
182 /* Fill in additional entries in GC_size_map, including the ith one */
183 /* We assume the ith entry is currently 0. */
184 /* Note that a filled in section of the array ending at n always */
185 /* has length at least n/4. */
186 void GC_extend_size_map(i)
187 word i;
188 {
189 word orig_word_sz = ROUNDED_UP_WORDS(i);
190 word word_sz = orig_word_sz;
191 register word byte_sz = WORDS_TO_BYTES(word_sz);
192 /* The size we try to preserve. */
193 /* Close to to i, unless this would */
194 /* introduce too many distinct sizes. */
195 word smaller_than_i = byte_sz - (byte_sz >> 3);
196 word much_smaller_than_i = byte_sz - (byte_sz >> 2);
197 register word low_limit; /* The lowest indexed entry we */
198 /* initialize. */
199 register word j;
200
201 if (GC_size_map[smaller_than_i] == 0) {
202 low_limit = much_smaller_than_i;
203 while (GC_size_map[low_limit] != 0) low_limit++;
204 } else {
205 low_limit = smaller_than_i + 1;
206 while (GC_size_map[low_limit] != 0) low_limit++;
207 word_sz = ROUNDED_UP_WORDS(low_limit);
208 word_sz += word_sz >> 3;
209 if (word_sz < orig_word_sz) word_sz = orig_word_sz;
210 }
211# ifdef ALIGN_DOUBLE
212 word_sz += 1;
213 word_sz &= ~1;
214# endif
215 if (word_sz > MAXOBJSZ) {
216 word_sz = MAXOBJSZ;
217 }
218 /* If we can fit the same number of larger objects in a block, */
219 /* do so. */
220 {
221 size_t number_of_objs = BODY_SZ/word_sz;
222 word_sz = BODY_SZ/number_of_objs;
223# ifdef ALIGN_DOUBLE
224 word_sz &= ~1;
225# endif
226 }
227 byte_sz = WORDS_TO_BYTES(word_sz);
228 if (GC_all_interior_pointers) {
229 /* We need one extra byte; don't fill in GC_size_map[byte_sz] */
230 byte_sz--;
231 }
232
233 for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;
234 }
235# endif
236
237
238/*
239 * The following is a gross hack to deal with a problem that can occur
240 * on machines that are sloppy about stack frame sizes, notably SPARC.
241 * Bogus pointers may be written to the stack and not cleared for
242 * a LONG time, because they always fall into holes in stack frames
243 * that are not written. We partially address this by clearing
244 * sections of the stack whenever we get control.
245 */
246word GC_stack_last_cleared = 0; /* GC_no when we last did this */
247# ifdef THREADS
248# define BIG_CLEAR_SIZE 2048 /* Clear this much now and then. */
249# define SMALL_CLEAR_SIZE 256 /* Clear this much every time. */
250# endif
251# define CLEAR_SIZE 213 /* Granularity for GC_clear_stack_inner */
252# define DEGRADE_RATE 50
253
254word GC_min_sp; /* Coolest stack pointer value from which we've */
255 /* already cleared the stack. */
256
257word GC_high_water;
258 /* "hottest" stack pointer value we have seen */
259 /* recently. Degrades over time. */
260
261word GC_words_allocd_at_reset;
262
263#if defined(ASM_CLEAR_CODE)
264 extern ptr_t GC_clear_stack_inner();
265#else
266/* Clear the stack up to about limit. Return arg. */
267/*ARGSUSED*/
268ptr_t GC_clear_stack_inner(arg, limit)
269ptr_t arg;
270word limit;
271{
272 word dummy[CLEAR_SIZE];
273
274 BZERO(dummy, CLEAR_SIZE*sizeof(word));
275 if ((word)(dummy) COOLER_THAN limit) {
276 (void) GC_clear_stack_inner(arg, limit);
277 }
278 /* Make sure the recursive call is not a tail call, and the bzero */
279 /* call is not recognized as dead code. */
280 GC_noop1((word)dummy);
281 return(arg);
282}
283#endif
284
285/* Clear some of the inaccessible part of the stack. Returns its */
286/* argument, so it can be used in a tail call position, hence clearing */
287/* another frame. */
288ptr_t GC_clear_stack(arg)
289ptr_t arg;
290{
291 register word sp = (word)GC_approx_sp(); /* Hotter than actual sp */
292# ifdef THREADS
293 word dummy[SMALL_CLEAR_SIZE];
294 static unsigned random_no = 0;
295 /* Should be more random than it is ... */
296 /* Used to occasionally clear a bigger */
297 /* chunk. */
298# endif
299 register word limit;
300
301# define SLOP 400
302 /* Extra bytes we clear every time. This clears our own */
303 /* activation record, and should cause more frequent */
304 /* clearing near the cold end of the stack, a good thing. */
305# define GC_SLOP 4000
306 /* We make GC_high_water this much hotter than we really saw */
307 /* saw it, to cover for GC noise etc. above our current frame. */
308# define CLEAR_THRESHOLD 100000
309 /* We restart the clearing process after this many bytes of */
310 /* allocation. Otherwise very heavily recursive programs */
311 /* with sparse stacks may result in heaps that grow almost */
312 /* without bounds. As the heap gets larger, collection */
313 /* frequency decreases, thus clearing frequency would decrease, */
314 /* thus more junk remains accessible, thus the heap gets */
315 /* larger ... */
316# ifdef THREADS
317 if (++random_no % 13 == 0) {
318 limit = sp;
319 MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
320 limit &= ~0xf; /* Make it sufficiently aligned for assembly */
321 /* implementations of GC_clear_stack_inner. */
322 return GC_clear_stack_inner(arg, limit);
323 } else {
324 BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word));
325 return arg;
326 }
327# else
328 if (GC_gc_no > GC_stack_last_cleared) {
329 /* Start things over, so we clear the entire stack again */
330 if (GC_stack_last_cleared == 0) GC_high_water = (word) GC_stackbottom;
331 GC_min_sp = GC_high_water;
332 GC_stack_last_cleared = GC_gc_no;
333 GC_words_allocd_at_reset = GC_words_allocd;
334 }
335 /* Adjust GC_high_water */
336 MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
337 if (sp HOTTER_THAN GC_high_water) {
338 GC_high_water = sp;
339 }
340 MAKE_HOTTER(GC_high_water, GC_SLOP);
341 limit = GC_min_sp;
342 MAKE_HOTTER(limit, SLOP);
343 if (sp COOLER_THAN limit) {
344 limit &= ~0xf; /* Make it sufficiently aligned for assembly */
345 /* implementations of GC_clear_stack_inner. */
346 GC_min_sp = sp;
347 return(GC_clear_stack_inner(arg, limit));
348 } else if (WORDS_TO_BYTES(GC_words_allocd - GC_words_allocd_at_reset)
349 > CLEAR_THRESHOLD) {
350 /* Restart clearing process, but limit how much clearing we do. */
351 GC_min_sp = sp;
352 MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
353 if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
354 GC_words_allocd_at_reset = GC_words_allocd;
355 }
356 return(arg);
357# endif
358}
359
360
361/* Return a pointer to the base address of p, given a pointer to a */
362/* an address within an object. Return 0 o.w. */
363# ifdef __STDC__
364 GC_PTR GC_base(GC_PTR p)
365# else
366 GC_PTR GC_base(p)
367 GC_PTR p;
368# endif
369{
370 register word r;
371 register struct hblk *h;
372 register bottom_index *bi;
373 register hdr *candidate_hdr;
374 register word limit;
375
376 r = (word)p;
377 if (!GC_is_initialized) return 0;
378 h = HBLKPTR(r);
379 GET_BI(r, bi);
380 candidate_hdr = HDR_FROM_BI(bi, r);
381 if (candidate_hdr == 0) return(0);
382 /* If it's a pointer to the middle of a large object, move it */
383 /* to the beginning. */
384 while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
385 h = FORWARDED_ADDR(h,candidate_hdr);
386 r = (word)h;
387 candidate_hdr = HDR(h);
388 }
389 if (candidate_hdr -> hb_map == GC_invalid_map) return(0);
390 /* Make sure r points to the beginning of the object */
391 r &= ~(WORDS_TO_BYTES(1) - 1);
392 {
393 register int offset = HBLKDISPL(r);
394 register signed_word sz = candidate_hdr -> hb_sz;
395 register signed_word map_entry;
396
397 map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset);
398 if (map_entry > CPP_MAX_OFFSET) {
399 map_entry = (signed_word)(BYTES_TO_WORDS(offset)) % sz;
400 }
401 r -= WORDS_TO_BYTES(map_entry);
402 limit = r + WORDS_TO_BYTES(sz);
403 if (limit > (word)(h + 1)
404 && sz <= BYTES_TO_WORDS(HBLKSIZE)) {
405 return(0);
406 }
407 if ((word)p >= limit) return(0);
408 }
409 return((GC_PTR)r);
410}
411
412
413/* Return the size of an object, given a pointer to its base. */
414/* (For small obects this also happens to work from interior pointers, */
415/* but that shouldn't be relied upon.) */
416# ifdef __STDC__
417 size_t GC_size(GC_PTR p)
418# else
419 size_t GC_size(p)
420 GC_PTR p;
421# endif
422{
423 register int sz;
424 register hdr * hhdr = HDR(p);
425
426 sz = WORDS_TO_BYTES(hhdr -> hb_sz);
427 return(sz);
428}
429
430size_t GC_get_heap_size GC_PROTO(())
431{
432 return ((size_t) GC_heapsize);
433}
434
435size_t GC_get_free_bytes GC_PROTO(())
436{
437 return ((size_t) GC_large_free_bytes);
438}
439
440size_t GC_get_bytes_since_gc GC_PROTO(())
441{
442 return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
443}
444
445size_t GC_get_total_bytes GC_PROTO(())
446{
447 return ((size_t) WORDS_TO_BYTES(GC_words_allocd+GC_words_allocd_before_gc));
448}
449
450GC_bool GC_is_initialized = FALSE;
451
452void GC_init()
453{
454 DCL_LOCK_STATE;
455
456 DISABLE_SIGNALS();
457
458#ifdef MSWIN32
459 if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
460#endif /* MSWIN32 */
461
462 LOCK();
463 GC_init_inner();
464 UNLOCK();
465 ENABLE_SIGNALS();
466
467# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
468 /* Make sure marker threads and started and thread local */
469 /* allocation is initialized, in case we didn't get */
470 /* called from GC_init_parallel(); */
471 {
472 extern void GC_init_parallel(void);
473 GC_init_parallel();
474 }
475# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
476}
477
478#if defined(MSWIN32) || defined(MSWINCE)
479 CRITICAL_SECTION GC_write_cs;
480#endif
481
482#ifdef MSWIN32
483 extern void GC_init_win32 GC_PROTO((void));
484#endif
485
486extern void GC_setpagesize();
487
488#ifdef UNIX_LIKE
489
490extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
491
492static void looping_handler(sig)
493int sig;
494{
495 GC_err_printf1("Caught signal %d: looping in handler\n", sig);
496 for(;;);
497}
498#endif
499
500#ifdef MSWIN32
501extern GC_bool GC_no_win32_dlls;
502#else
503# define GC_no_win32_dlls FALSE
504#endif
505
506void GC_init_inner()
507{
508# if !defined(THREADS) && defined(GC_ASSERTIONS)
509 word dummy;
510# endif
511 word initial_heap_sz = (word)MINHINCR;
512
513 if (GC_is_initialized) return;
514# ifdef PRINTSTATS
515 GC_print_stats = 1;
516# endif
517# if defined(MSWIN32) || defined(MSWINCE)
518 InitializeCriticalSection(&GC_write_cs);
519# endif
520
521 if (0 != GETENV("GC_PRINT_STATS")) {
522 GC_print_stats = 1;
523 }
524 if (0 != GETENV("GC_FIND_LEAK")) {
525 GC_find_leak = 1;
526 }
527 if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
528 GC_all_interior_pointers = 1;
529 }
530 if (0 != GETENV("GC_DONT_GC")) {
531 GC_dont_gc = 1;
532 }
533 if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
534 GC_print_back_height = 1;
535 }
536 if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
537 GC_large_alloc_warn_interval = LONG_MAX;
538 }
539 {
540 char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
541 if (0 != time_limit_string) {
542 long time_limit = atol(time_limit_string);
543 if (time_limit < 5) {
544 WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
545 "or bad syntax: Ignoring\n", 0);
546 } else {
547 GC_time_limit = time_limit;
548 }
549 }
550 }
551 {
552 char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
553 if (0 != interval_string) {
554 long interval = atol(interval_string);
555 if (interval <= 0) {
556 WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
557 "bad value: Ignoring\n", 0);
558 } else {
559 GC_large_alloc_warn_interval = interval;
560 }
561 }
562 }
563# ifdef UNIX_LIKE
564 if (0 != GETENV("GC_LOOP_ON_ABORT")) {
565 GC_set_and_save_fault_handler(looping_handler);
566 }
567# endif
568 /* Adjust normal object descriptor for extra allocation. */
569 if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
570 GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
571 }
572 GC_setpagesize();
573 GC_exclude_static_roots(beginGC_arrays, endGC_arrays);
574 GC_exclude_static_roots(beginGC_obj_kinds, endGC_obj_kinds);
575# ifdef SEPARATE_GLOBALS
576 GC_exclude_static_roots(beginGC_objfreelist, endGC_objfreelist);
577 GC_exclude_static_roots(beginGC_aobjfreelist, endGC_aobjfreelist);
578# endif
579# ifdef MSWIN32
580 GC_init_win32();
581# endif
582# if defined(SEARCH_FOR_DATA_START)
583 GC_init_linux_data_start();
584# endif
585# if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
586 GC_init_netbsd_elf();
587# endif
588# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
589 GC_thr_init();
590# endif
591# ifdef GC_SOLARIS_THREADS
592 /* We need dirty bits in order to find live stack sections. */
593 GC_dirty_init();
594# endif
595# if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
596 || defined(GC_SOLARIS_THREADS)
597 if (GC_stackbottom == 0) {
598 GC_stackbottom = GC_get_stack_base();
599# if defined(LINUX) && defined(IA64)
600 GC_register_stackbottom = GC_get_register_stack_base();
601# endif
602 }
603# endif
604 GC_ASSERT(sizeof (ptr_t) == sizeof(word));
605 GC_ASSERT(sizeof (signed_word) == sizeof(word));
606 GC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
607# ifndef THREADS
608# if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
609 ABORT(
610 "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
611# endif
612# if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
613 ABORT(
614 "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
615# endif
616# ifdef STACK_GROWS_DOWN
617 GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
618# else
619 GC_ASSERT((word)(&dummy) >= (word)GC_stackbottom);
620# endif
621# endif
622# if !defined(_AUX_SOURCE) || defined(__GNUC__)
623 GC_ASSERT((word)(-1) > (word)0);
624 /* word should be unsigned */
625# endif
626 GC_ASSERT((signed_word)(-1) < (signed_word)0);
627
628 /* Add initial guess of root sets. Do this first, since sbrk(0) */
629 /* might be used. */
630 if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments();
631 GC_init_headers();
632 GC_bl_init();
633 GC_mark_init();
634 {
635 char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
636 if (sz_str != NULL) {
637 initial_heap_sz = atoi(sz_str);
638 if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
639 WARN("Bad initial heap size %s - ignoring it.\n",
640 sz_str);
641 }
642 initial_heap_sz = divHBLKSZ(initial_heap_sz);
643 }
644 }
645 if (!GC_expand_hp_inner(initial_heap_sz)) {
646 GC_err_printf0("Can't start up: not enough memory\n");
647 EXIT();
648 }
649 /* Preallocate large object map. It's otherwise inconvenient to */
650 /* deal with failure. */
651 if (!GC_add_map_entry((word)0)) {
652 GC_err_printf0("Can't start up: not enough memory\n");
653 EXIT();
654 }
655 GC_register_displacement_inner(0L);
656# ifdef MERGE_SIZES
657 GC_init_size_map();
658# endif
659# ifdef PCR
660 if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
661 != PCR_ERes_okay) {
662 ABORT("Can't lock load state\n");
663 } else if (PCR_IL_Unlock() != PCR_ERes_okay) {
664 ABORT("Can't unlock load state\n");
665 }
666 PCR_IL_Unlock();
667 GC_pcr_install();
668# endif
669# if !defined(SMALL_CONFIG)
670 if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
671 GC_ASSERT(!GC_incremental);
672 GC_setpagesize();
673# ifndef GC_SOLARIS_THREADS
674 GC_dirty_init();
675# endif
676 GC_ASSERT(GC_words_allocd == 0)
677 GC_incremental = TRUE;
678 }
679# endif /* !SMALL_CONFIG */
680 /* Get black list set up and/or incrmental GC started */
681 if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
682 GC_is_initialized = TRUE;
683# ifdef STUBBORN_ALLOC
684 GC_stubborn_init();
685# endif
686 /* Convince lint that some things are used */
687# ifdef LINT
688 {
689 extern char * GC_copyright[];
690 extern int GC_read();
691 extern void GC_register_finalizer_no_order();
692
693 GC_noop(GC_copyright, GC_find_header,
694 GC_push_one, GC_call_with_alloc_lock, GC_read,
695 GC_dont_expand,
696# ifndef NO_DEBUGGING
697 GC_dump,
698# endif
699 GC_register_finalizer_no_order);
700 }
701# endif
702}
703
704void GC_enable_incremental GC_PROTO(())
705{
706# if !defined(SMALL_CONFIG)
707 if (!GC_find_leak) {
708 DCL_LOCK_STATE;
709
710 DISABLE_SIGNALS();
711 LOCK();
712 if (GC_incremental) goto out;
713 GC_setpagesize();
714 if (GC_no_win32_dlls) goto out;
715# ifndef GC_SOLARIS_THREADS
716 GC_dirty_init();
717# endif
718 if (!GC_is_initialized) {
719 GC_init_inner();
720 }
721 if (GC_incremental) goto out;
722 if (GC_dont_gc) {
723 /* Can't easily do it. */
724 UNLOCK();
725 ENABLE_SIGNALS();
726 return;
727 }
728 if (GC_words_allocd > 0) {
729 /* There may be unmarked reachable objects */
730 GC_gcollect_inner();
731 } /* else we're OK in assuming everything's */
732 /* clean since nothing can point to an */
733 /* unmarked object. */
734 GC_read_dirty();
735 GC_incremental = TRUE;
736out:
737 UNLOCK();
738 ENABLE_SIGNALS();
739 }
740# endif
741}
742
743
744#if defined(MSWIN32) || defined(MSWINCE)
745# define LOG_FILE _T("gc.log")
746
747 HANDLE GC_stdout = 0;
748
749 void GC_deinit()
750 {
751 if (GC_is_initialized) {
752 DeleteCriticalSection(&GC_write_cs);
753 }
754 }
755
756 int GC_write(buf, len)
757 GC_CONST char * buf;
758 size_t len;
759 {
760 BOOL tmp;
761 DWORD written;
762 if (len == 0)
763 return 0;
764 EnterCriticalSection(&GC_write_cs);
765 if (GC_stdout == INVALID_HANDLE_VALUE) {
766 return -1;
767 } else if (GC_stdout == 0) {
768 GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE,
769 FILE_SHARE_READ | FILE_SHARE_WRITE,
770 NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
771 NULL);
772 if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed");
773 }
774 tmp = WriteFile(GC_stdout, buf, len, &written, NULL);
775 if (!tmp)
776 DebugBreak();
777 LeaveCriticalSection(&GC_write_cs);
778 return tmp ? (int)written : -1;
779 }
780
781#endif
782
783#if defined(OS2) || defined(MACOS)
784FILE * GC_stdout = NULL;
785FILE * GC_stderr = NULL;
786int GC_tmp; /* Should really be local ... */
787
788 void GC_set_files()
789 {
790 if (GC_stdout == NULL) {
791 GC_stdout = stdout;
792 }
793 if (GC_stderr == NULL) {
794 GC_stderr = stderr;
795 }
796 }
797#endif
798
799#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
800 int GC_stdout = 1;
801 int GC_stderr = 2;
802# if !defined(AMIGA)
803# include <unistd.h>
804# endif
805#endif
806
807#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \
808 && !defined(MACOS) && !defined(ECOS) && !defined(NOSYS)
809int GC_write(fd, buf, len)
810int fd;
811GC_CONST char *buf;
812size_t len;
813{
814 register int bytes_written = 0;
815 register int result;
816
817 while (bytes_written < len) {
818# ifdef GC_SOLARIS_THREADS
819 result = syscall(SYS_write, fd, buf + bytes_written,
820 len - bytes_written);
821# else
822 result = write(fd, buf + bytes_written, len - bytes_written);
823# endif
824 if (-1 == result) return(result);
825 bytes_written += result;
826 }
827 return(bytes_written);
828}
829#endif /* UN*X */
830
831#ifdef ECOS
832int GC_write(fd, buf, len)
833{
834 _Jv_diag_write (buf, len);
835 return len;
836}
837#endif
838
839#ifdef NOSYS
840int GC_write(fd, buf, len)
841{
842 /* No writing. */
843 return len;
844}
845#endif
846
847
848#if defined(MSWIN32) || defined(MSWINCE)
849# define WRITE(f, buf, len) GC_write(buf, len)
850#else
851# if defined(OS2) || defined(MACOS)
852# define WRITE(f, buf, len) (GC_set_files(), \
853 GC_tmp = fwrite((buf), 1, (len), (f)), \
854 fflush(f), GC_tmp)
855# else
856# define WRITE(f, buf, len) GC_write((f), (buf), (len))
857# endif
858#endif
859
860/* A version of printf that is unlikely to call malloc, and is thus safer */
861/* to call from the collector in case malloc has been bound to GC_malloc. */
862/* Assumes that no more than 1023 characters are written at once. */
863/* Assumes that all arguments have been converted to something of the */
864/* same size as long, and that the format conversions expect something */
865/* of that size. */
866void GC_printf(format, a, b, c, d, e, f)
867GC_CONST char * format;
868long a, b, c, d, e, f;
869{
870 char buf[1025];
871
872 if (GC_quiet) return;
873 buf[1024] = 0x15;
874 (void) sprintf(buf, format, a, b, c, d, e, f);
875 if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
876 if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
877}
878
879void GC_err_printf(format, a, b, c, d, e, f)
880GC_CONST char * format;
881long a, b, c, d, e, f;
882{
883 char buf[1025];
884
885 buf[1024] = 0x15;
886 (void) sprintf(buf, format, a, b, c, d, e, f);
887 if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
888 if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
889}
890
891void GC_err_puts(s)
892GC_CONST char *s;
893{
894 if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
895}
896
897#if defined(LINUX) && !defined(SMALL_CONFIG)
898void GC_err_write(buf, len)
899GC_CONST char *buf;
900size_t len;
901{
902 if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
903}
904#endif
905
906# if defined(__STDC__) || defined(__cplusplus)
907 void GC_default_warn_proc(char *msg, GC_word arg)
908# else
909 void GC_default_warn_proc(msg, arg)
910 char *msg;
911 GC_word arg;
912# endif
913{
914 GC_err_printf1(msg, (unsigned long)arg);
915}
916
917GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
918
919# if defined(__STDC__) || defined(__cplusplus)
920 GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
921# else
922 GC_warn_proc GC_set_warn_proc(p)
923 GC_warn_proc p;
924# endif
925{
926 GC_warn_proc result;
927
928 LOCK();
929 result = GC_current_warn_proc;
930 GC_current_warn_proc = p;
931 UNLOCK();
932 return(result);
933}
934
935
936#ifndef PCR
937void GC_abort(msg)
938GC_CONST char * msg;
939{
940# if defined(MSWIN32)
941 (void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
942 DebugBreak();
943# else
944 GC_err_printf1("%s\n", msg);
945# endif
946 if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
947 /* In many cases it's easier to debug a running process. */
948 /* It's arguably nicer to sleep, but that makes it harder */
949 /* to look at the thread if the debugger doesn't know much */
950 /* about threads. */
951 for(;;) {}
952 }
953# ifdef MSWIN32
954 DebugBreak();
955# else
956 (void) abort();
957# endif
958}
959#endif
960
961#ifdef NEED_CALLINFO
962
963#ifdef HAVE_BUILTIN_BACKTRACE
964# include <execinfo.h>
965# ifdef LINUX
966# include <unistd.h>
967# endif
968#endif
969
970void GC_print_callers (info)
971struct callinfo info[NFRAMES];
972{
973 register int i;
974
975# if NFRAMES == 1
976 GC_err_printf0("\tCaller at allocation:\n");
977# else
978 GC_err_printf0("\tCall chain at allocation:\n");
979# endif
980 for (i = 0; i < NFRAMES; i++) {
981 if (info[i].ci_pc == 0) break;
982# if NARGS > 0
983 {
984 int j;
985
986 GC_err_printf0("\t\targs: ");
987 for (j = 0; j < NARGS; j++) {
988 if (j != 0) GC_err_printf0(", ");
989 GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
990 ~(info[i].ci_arg[j]));
991 }
992 GC_err_printf0("\n");
993 }
994# endif
995# if defined(HAVE_BUILTIN_BACKTRACE) && !defined(REDIRECT_MALLOC)
996 /* Unfortunately backtrace_symbols calls malloc, which makes */
997 /* it dangersous if that has been redirected. */
998 {
999 char **sym_name =
1000 backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
1001 char *name = sym_name[0];
1002 GC_bool found_it = (strchr(name, '(') != 0);
1003 FILE *pipe;
1004# ifdef LINUX
1005 if (!found_it) {
1006# define EXE_SZ 100
1007 static char exe_name[EXE_SZ];
1008# define CMD_SZ 200
1009 char cmd_buf[CMD_SZ];
1010# define RESULT_SZ 200
1011 static char result_buf[RESULT_SZ];
1012 size_t result_len;
1013 static GC_bool found_exe_name = FALSE;
1014 static GC_bool will_fail = FALSE;
1015 int ret_code;
1016 /* Unfortunately, this is the common case for the */
1017 /* main executable. */
1018 /* Try to get it via a hairy and expensive scheme. */
1019 /* First we get the name of the executable: */
1020 if (will_fail) goto out;
1021 if (!found_exe_name) {
1022 ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
1023 if (ret_code < 0 || ret_code >= EXE_SZ || exe_name[0] != '/') {
1024 will_fail = TRUE; /* Dont try again. */
1025 goto out;
1026 }
1027 exe_name[ret_code] = '\0';
1028 found_exe_name = TRUE;
1029 }
1030 /* Then we use popen to start addr2line -e <exe> <addr> */
1031 /* There are faster ways to do this, but hopefully this */
1032 /* isn't time critical. */
1033 sprintf(cmd_buf, "/usr/bin/addr2line -e %s 0x%lx", exe_name,
1034 (unsigned long)info[i].ci_pc);
1035 pipe = popen(cmd_buf, "r");
1036 if (pipe < 0 || fgets(result_buf, RESULT_SZ, pipe) == 0) {
1037 will_fail = TRUE;
1038 goto out;
1039 }
1040 result_len = strlen(result_buf);
1041 if (result_buf[result_len - 1] == '\n') --result_len;
1042 if (result_buf[0] == '?'
1043 || result_buf[result_len-2] == ':'
1044 && result_buf[result_len-1] == '0')
1045 goto out;
1046 if (result_len < RESULT_SZ - 25) {
1047 /* Add in hex address */
1048 sprintf(result_buf + result_len, " [0x%lx]",
1049 (unsigned long)info[i].ci_pc);
1050 }
1051 name = result_buf;
1052 pclose(pipe);
1053 out:
1054 }
1055# endif
1056 GC_err_printf1("\t\t%s\n", name);
1057 free(sym_name);
1058 }
1059# else
1060 GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
1061# endif
1062 }
1063}
1064
1065#endif /* SAVE_CALL_CHAIN */
1066
1067/* Needed by SRC_M3, gcj, and should perhaps be the official interface */
1068/* to GC_dont_gc. */
1069void GC_enable()
1070{
1071 GC_dont_gc--;
1072}
1073
1074void GC_disable()
1075{
1076 GC_dont_gc++;
1077}
1078
1079#if !defined(NO_DEBUGGING)
1080
1081void GC_dump()
1082{
1083 GC_printf0("***Static roots:\n");
1084 GC_print_static_roots();
1085 GC_printf0("\n***Heap sections:\n");
1086 GC_print_heap_sects();
1087 GC_printf0("\n***Free blocks:\n");
1088 GC_print_hblkfreelist();
1089 GC_printf0("\n***Blocks in use:\n");
1090 GC_print_block_list();
1091}
1092
1093#endif /* NO_DEBUGGING */
Note: See TracBrowser for help on using the repository browser.