* Makefile.in (rtlanal.o): Depend on $(TM_P_H).
[official-gcc.git] / boehm-gc / os_dep.c
blobcc816dff07f84287b218c27faf31e763754af5c8
1 /*
2 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3 * Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
4 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
5 * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
7 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
8 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
10 * Permission is hereby granted to use or copy this program
11 * for any purpose, provided the above notices are retained on all copies.
12 * Permission to modify the code and to distribute modified code is granted,
13 * provided the above notices are retained, and a notice that the code was
14 * modified is included with the above copyright notice.
17 # include "private/gc_priv.h"
19 # if defined(LINUX) && !defined(POWERPC)
20 # include <linux/version.h>
21 # if (LINUX_VERSION_CODE <= 0x10400)
22 /* Ugly hack to get struct sigcontext_struct definition. Required */
23 /* for some early 1.3.X releases. Will hopefully go away soon. */
24 /* in some later Linux releases, asm/sigcontext.h may have to */
25 /* be included instead. */
26 # define __KERNEL__
27 # include <asm/signal.h>
28 # undef __KERNEL__
29 # else
30 /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
31 /* struct sigcontext. libc6 (glibc2) uses "struct sigcontext" in */
32 /* prototypes, so we have to include the top-level sigcontext.h to */
33 /* make sure the former gets defined to be the latter if appropriate. */
34 # include <features.h>
35 # if 2 <= __GLIBC__
36 # if 2 == __GLIBC__ && 0 == __GLIBC_MINOR__
37 /* glibc 2.1 no longer has sigcontext.h. But signal.h */
38 /* has the right declaration for glibc 2.1. */
39 # include <sigcontext.h>
40 # endif /* 0 == __GLIBC_MINOR__ */
41 # else /* not 2 <= __GLIBC__ */
42 /* libc5 doesn't have <sigcontext.h>: go directly with the kernel */
43 /* one. Check LINUX_VERSION_CODE to see which we should reference. */
44 # include <asm/sigcontext.h>
45 # endif /* 2 <= __GLIBC__ */
46 # endif
47 # endif
48 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
49 && !defined(MSWINCE)
50 # include <sys/types.h>
51 # if !defined(MSWIN32) && !defined(SUNOS4)
52 # include <unistd.h>
53 # endif
54 # endif
56 # include <stdio.h>
57 # if defined(MSWINCE)
58 # define SIGSEGV 0 /* value is irrelevant */
59 # else
60 # include <signal.h>
61 # endif
63 /* Blatantly OS dependent routines, except for those that are related */
64 /* to dynamic loading. */
66 # if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
67 # define NEED_FIND_LIMIT
68 # endif
70 # if !defined(STACKBOTTOM) && defined(HEURISTIC2)
71 # define NEED_FIND_LIMIT
72 # endif
74 # if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
75 # define NEED_FIND_LIMIT
76 # endif
78 # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
79 || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
80 # define NEED_FIND_LIMIT
81 # endif
83 #ifdef NEED_FIND_LIMIT
84 # include <setjmp.h>
85 #endif
87 #ifdef FREEBSD
88 # include <machine/trap.h>
89 #endif
91 #ifdef AMIGA
92 # define GC_AMIGA_DEF
93 # include "AmigaOS.c"
94 # undef GC_AMIGA_DEF
95 #endif
97 #if defined(MSWIN32) || defined(MSWINCE)
98 # define WIN32_LEAN_AND_MEAN
99 # define NOSERVICE
100 # include <windows.h>
101 #endif
103 #ifdef MACOS
104 # include <Processes.h>
105 #endif
107 #ifdef IRIX5
108 # include <sys/uio.h>
109 # include <malloc.h> /* for locking */
110 #endif
111 #ifdef USE_MMAP
112 # include <sys/types.h>
113 # include <sys/mman.h>
114 # include <sys/stat.h>
115 #endif
117 #ifdef UNIX_LIKE
118 # include <fcntl.h>
119 #endif
121 #if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX)
122 # ifdef SUNOS5SIGS
123 # include <sys/siginfo.h>
124 # endif
125 # undef setjmp
126 # undef longjmp
127 # define setjmp(env) sigsetjmp(env, 1)
128 # define longjmp(env, val) siglongjmp(env, val)
129 # define jmp_buf sigjmp_buf
130 #endif
132 #ifdef DJGPP
133 /* Apparently necessary for djgpp 2.01. May cause problems with */
134 /* other versions. */
135 typedef long unsigned int caddr_t;
136 #endif
138 #ifdef PCR
139 # include "il/PCR_IL.h"
140 # include "th/PCR_ThCtl.h"
141 # include "mm/PCR_MM.h"
142 #endif
144 #if !defined(NO_EXECUTE_PERMISSION)
145 # define OPT_PROT_EXEC PROT_EXEC
146 #else
147 # define OPT_PROT_EXEC 0
148 #endif
150 #if defined(SEARCH_FOR_DATA_START)
151 /* The I386 case can be handled without a search. The Alpha case */
152 /* used to be handled differently as well, but the rules changed */
153 /* for recent Linux versions. This seems to be the easiest way to */
154 /* cover all versions. */
156 # ifdef LINUX
157 # pragma weak __data_start
158 extern int __data_start;
159 # pragma weak data_start
160 extern int data_start;
161 # endif /* LINUX */
162 extern int _end;
164 ptr_t GC_data_start;
166 void GC_init_linux_data_start()
168 extern ptr_t GC_find_limit();
170 # ifdef LINUX
171 /* Try the easy approaches first: */
172 if (&__data_start != 0) {
173 GC_data_start = (ptr_t)(&__data_start);
174 return;
176 if (&data_start != 0) {
177 GC_data_start = (ptr_t)(&data_start);
178 return;
180 # endif /* LINUX */
181 GC_data_start = GC_find_limit((ptr_t)(&_end), FALSE);
183 #endif
185 # ifdef ECOS
187 # ifndef ECOS_GC_MEMORY_SIZE
188 # define ECOS_GC_MEMORY_SIZE (448 * 1024)
189 # endif /* ECOS_GC_MEMORY_SIZE */
191 // setjmp() function, as described in ANSI para 7.6.1.1
192 #define setjmp( __env__ ) hal_setjmp( __env__ )
194 // FIXME: This is a simple way of allocating memory which is
195 // compatible with ECOS early releases. Later releases use a more
196 // sophisticated means of allocating memory than this simple static
197 // allocator, but this method is at least bound to work.
198 static char memory[ECOS_GC_MEMORY_SIZE];
199 static char *brk = memory;
201 static void *tiny_sbrk(ptrdiff_t increment)
203 void *p = brk;
205 brk += increment;
207 if (brk > memory + sizeof memory)
209 brk -= increment;
210 return NULL;
213 return p;
215 #define sbrk tiny_sbrk
216 # endif /* ECOS */
218 #if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
219 ptr_t GC_data_start;
221 void GC_init_netbsd_elf()
223 extern ptr_t GC_find_limit();
224 extern char **environ;
225 /* This may need to be environ, without the underscore, for */
226 /* some versions. */
227 GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
229 #endif
231 # ifdef OS2
233 # include <stddef.h>
235 # if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */
237 struct exe_hdr {
238 unsigned short magic_number;
239 unsigned short padding[29];
240 long new_exe_offset;
243 #define E_MAGIC(x) (x).magic_number
244 #define EMAGIC 0x5A4D
245 #define E_LFANEW(x) (x).new_exe_offset
247 struct e32_exe {
248 unsigned char magic_number[2];
249 unsigned char byte_order;
250 unsigned char word_order;
251 unsigned long exe_format_level;
252 unsigned short cpu;
253 unsigned short os;
254 unsigned long padding1[13];
255 unsigned long object_table_offset;
256 unsigned long object_count;
257 unsigned long padding2[31];
260 #define E32_MAGIC1(x) (x).magic_number[0]
261 #define E32MAGIC1 'L'
262 #define E32_MAGIC2(x) (x).magic_number[1]
263 #define E32MAGIC2 'X'
264 #define E32_BORDER(x) (x).byte_order
265 #define E32LEBO 0
266 #define E32_WORDER(x) (x).word_order
267 #define E32LEWO 0
268 #define E32_CPU(x) (x).cpu
269 #define E32CPU286 1
270 #define E32_OBJTAB(x) (x).object_table_offset
271 #define E32_OBJCNT(x) (x).object_count
273 struct o32_obj {
274 unsigned long size;
275 unsigned long base;
276 unsigned long flags;
277 unsigned long pagemap;
278 unsigned long mapsize;
279 unsigned long reserved;
282 #define O32_FLAGS(x) (x).flags
283 #define OBJREAD 0x0001L
284 #define OBJWRITE 0x0002L
285 #define OBJINVALID 0x0080L
286 #define O32_SIZE(x) (x).size
287 #define O32_BASE(x) (x).base
289 # else /* IBM's compiler */
291 /* A kludge to get around what appears to be a header file bug */
292 # ifndef WORD
293 # define WORD unsigned short
294 # endif
295 # ifndef DWORD
296 # define DWORD unsigned long
297 # endif
299 # define EXE386 1
300 # include <newexe.h>
301 # include <exe386.h>
303 # endif /* __IBMC__ */
305 # define INCL_DOSEXCEPTIONS
306 # define INCL_DOSPROCESS
307 # define INCL_DOSERRORS
308 # define INCL_DOSMODULEMGR
309 # define INCL_DOSMEMMGR
310 # include <os2.h>
313 /* Disable and enable signals during nontrivial allocations */
315 void GC_disable_signals(void)
317 ULONG nest;
319 DosEnterMustComplete(&nest);
320 if (nest != 1) ABORT("nested GC_disable_signals");
323 void GC_enable_signals(void)
325 ULONG nest;
327 DosExitMustComplete(&nest);
328 if (nest != 0) ABORT("GC_enable_signals");
332 # else
334 # if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
335 && !defined(MSWINCE) \
336 && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)
338 # if defined(sigmask) && !defined(UTS4) && !defined(HURD)
339 /* Use the traditional BSD interface */
340 # define SIGSET_T int
341 # define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
342 # define SIG_FILL(set) (set) = 0x7fffffff
343 /* Setting the leading bit appears to provoke a bug in some */
344 /* longjmp implementations. Most systems appear not to have */
345 /* a signal 32. */
346 # define SIGSETMASK(old, new) (old) = sigsetmask(new)
347 # else
348 /* Use POSIX/SYSV interface */
349 # define SIGSET_T sigset_t
350 # define SIG_DEL(set, signal) sigdelset(&(set), (signal))
351 # define SIG_FILL(set) sigfillset(&set)
352 # define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
353 # endif
355 static GC_bool mask_initialized = FALSE;
357 static SIGSET_T new_mask;
359 static SIGSET_T old_mask;
361 static SIGSET_T dummy;
363 #if defined(PRINTSTATS) && !defined(THREADS)
364 # define CHECK_SIGNALS
365 int GC_sig_disabled = 0;
366 #endif
368 void GC_disable_signals()
370 if (!mask_initialized) {
371 SIG_FILL(new_mask);
373 SIG_DEL(new_mask, SIGSEGV);
374 SIG_DEL(new_mask, SIGILL);
375 SIG_DEL(new_mask, SIGQUIT);
376 # ifdef SIGBUS
377 SIG_DEL(new_mask, SIGBUS);
378 # endif
379 # ifdef SIGIOT
380 SIG_DEL(new_mask, SIGIOT);
381 # endif
382 # ifdef SIGEMT
383 SIG_DEL(new_mask, SIGEMT);
384 # endif
385 # ifdef SIGTRAP
386 SIG_DEL(new_mask, SIGTRAP);
387 # endif
388 mask_initialized = TRUE;
390 # ifdef CHECK_SIGNALS
391 if (GC_sig_disabled != 0) ABORT("Nested disables");
392 GC_sig_disabled++;
393 # endif
394 SIGSETMASK(old_mask,new_mask);
397 void GC_enable_signals()
399 # ifdef CHECK_SIGNALS
400 if (GC_sig_disabled != 1) ABORT("Unmatched enable");
401 GC_sig_disabled--;
402 # endif
403 SIGSETMASK(dummy,old_mask);
406 # endif /* !PCR */
408 # endif /*!OS/2 */
410 /* Ivan Demakov: simplest way (to me) */
411 #if defined (DOS4GW)
412 void GC_disable_signals() { }
413 void GC_enable_signals() { }
414 #endif
416 /* Find the page size */
417 word GC_page_size;
419 # if defined(MSWIN32) || defined(MSWINCE)
420 void GC_setpagesize()
422 GetSystemInfo(&GC_sysinfo);
423 GC_page_size = GC_sysinfo.dwPageSize;
426 # else
427 # if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP) \
428 || defined(USE_MUNMAP)
429 void GC_setpagesize()
431 GC_page_size = GETPAGESIZE();
433 # else
434 /* It's acceptable to fake it. */
435 void GC_setpagesize()
437 GC_page_size = HBLKSIZE;
439 # endif
440 # endif
443 * Find the base of the stack.
444 * Used only in single-threaded environment.
445 * With threads, GC_mark_roots needs to know how to do this.
446 * Called with allocator lock held.
448 # if defined(MSWIN32) || defined(MSWINCE)
449 # define is_writable(prot) ((prot) == PAGE_READWRITE \
450 || (prot) == PAGE_WRITECOPY \
451 || (prot) == PAGE_EXECUTE_READWRITE \
452 || (prot) == PAGE_EXECUTE_WRITECOPY)
453 /* Return the number of bytes that are writable starting at p. */
454 /* The pointer p is assumed to be page aligned. */
455 /* If base is not 0, *base becomes the beginning of the */
456 /* allocation region containing p. */
457 word GC_get_writable_length(ptr_t p, ptr_t *base)
459 MEMORY_BASIC_INFORMATION buf;
460 word result;
461 word protect;
463 result = VirtualQuery(p, &buf, sizeof(buf));
464 if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
465 if (base != 0) *base = (ptr_t)(buf.AllocationBase);
466 protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
467 if (!is_writable(protect)) {
468 return(0);
470 if (buf.State != MEM_COMMIT) return(0);
471 return(buf.RegionSize);
474 ptr_t GC_get_stack_base()
476 int dummy;
477 ptr_t sp = (ptr_t)(&dummy);
478 ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
479 word size = GC_get_writable_length(trunc_sp, 0);
481 return(trunc_sp + size);
485 # endif /* MS Windows */
487 # ifdef BEOS
488 # include <kernel/OS.h>
489 ptr_t GC_get_stack_base(){
490 thread_info th;
491 get_thread_info(find_thread(NULL),&th);
492 return th.stack_end;
494 # endif /* BEOS */
497 # ifdef OS2
499 ptr_t GC_get_stack_base()
501 PTIB ptib;
502 PPIB ppib;
504 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
505 GC_err_printf0("DosGetInfoBlocks failed\n");
506 ABORT("DosGetInfoBlocks failed\n");
508 return((ptr_t)(ptib -> tib_pstacklimit));
511 # endif /* OS2 */
513 # ifdef AMIGA
514 # define GC_AMIGA_SB
515 # include "AmigaOS.c"
516 # undef GC_AMIGA_SB
517 # endif /* AMIGA */
519 # if defined(NEED_FIND_LIMIT) || (defined(UNIX_LIKE) && !defined(ECOS))
521 # ifdef __STDC__
522 typedef void (*handler)(int);
523 # else
524 typedef void (*handler)();
525 # endif
527 # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) || defined(HURD)
528 static struct sigaction old_segv_act;
529 # if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) || defined(HURD)
530 static struct sigaction old_bus_act;
531 # endif
532 # else
533 static handler old_segv_handler, old_bus_handler;
534 # endif
536 # ifdef __STDC__
537 void GC_set_and_save_fault_handler(handler h)
538 # else
539 void GC_set_and_save_fault_handler(h)
540 handler h;
541 # endif
543 # ifndef ECOS
544 # if defined(SUNOS5SIGS) || defined(IRIX5) \
545 || defined(OSF1) || defined(HURD)
546 struct sigaction act;
548 act.sa_handler = h;
549 # ifdef SUNOS5SIGS
550 act.sa_flags = SA_RESTART | SA_NODEFER;
551 # else
552 act.sa_flags = SA_RESTART;
553 # endif
554 /* The presence of SA_NODEFER represents yet another gross */
555 /* hack. Under Solaris 2.3, siglongjmp doesn't appear to */
556 /* interact correctly with -lthread. We hide the confusion */
557 /* by making sure that signal handling doesn't affect the */
558 /* signal mask. */
560 (void) sigemptyset(&act.sa_mask);
561 # ifdef GC_IRIX_THREADS
562 /* Older versions have a bug related to retrieving and */
563 /* and setting a handler at the same time. */
564 (void) sigaction(SIGSEGV, 0, &old_segv_act);
565 (void) sigaction(SIGSEGV, &act, 0);
566 # else
567 (void) sigaction(SIGSEGV, &act, &old_segv_act);
568 # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
569 || defined(HPUX) || defined(HURD)
570 /* Under Irix 5.x or HP/UX, we may get SIGBUS. */
571 /* Pthreads doesn't exist under Irix 5.x, so we */
572 /* don't have to worry in the threads case. */
573 (void) sigaction(SIGBUS, &act, &old_bus_act);
574 # endif
575 # endif /* GC_IRIX_THREADS */
576 # else
577 old_segv_handler = signal(SIGSEGV, h);
578 # ifdef SIGBUS
579 old_bus_handler = signal(SIGBUS, h);
580 # endif
581 # endif
582 # endif /* ECOS */
584 # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
586 # ifdef NEED_FIND_LIMIT
587 /* Some tools to implement HEURISTIC2 */
588 # define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
589 /* static */ jmp_buf GC_jmp_buf;
591 /*ARGSUSED*/
592 void GC_fault_handler(sig)
593 int sig;
595 longjmp(GC_jmp_buf, 1);
598 void GC_setup_temporary_fault_handler()
600 GC_set_and_save_fault_handler(GC_fault_handler);
603 void GC_reset_fault_handler()
605 # ifndef ECOS
606 # if defined(SUNOS5SIGS) || defined(IRIX5) \
607 || defined(OSF1) || defined(HURD)
608 (void) sigaction(SIGSEGV, &old_segv_act, 0);
609 # if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
610 || defined(HPUX) || defined(HURD)
611 (void) sigaction(SIGBUS, &old_bus_act, 0);
612 # endif
613 # else
614 (void) signal(SIGSEGV, old_segv_handler);
615 # ifdef SIGBUS
616 (void) signal(SIGBUS, old_bus_handler);
617 # endif
618 # endif
619 # endif /* ECOS */
622 /* Return the first nonaddressible location > p (up) or */
623 /* the smallest location q s.t. [q,p] is addressible (!up). */
624 ptr_t GC_find_limit(p, up)
625 ptr_t p;
626 GC_bool up;
628 # ifndef ECOS
629 static VOLATILE ptr_t result;
630 /* Needs to be static, since otherwise it may not be */
631 /* preserved across the longjmp. Can safely be */
632 /* static since it's only called once, with the */
633 /* allocation lock held. */
636 GC_setup_temporary_fault_handler();
637 if (setjmp(GC_jmp_buf) == 0) {
638 result = (ptr_t)(((word)(p))
639 & ~(MIN_PAGE_SIZE-1));
640 for (;;) {
641 if (up) {
642 result += MIN_PAGE_SIZE;
643 } else {
644 result -= MIN_PAGE_SIZE;
646 GC_noop1((word)(*result));
649 GC_reset_fault_handler();
650 if (!up) {
651 result += MIN_PAGE_SIZE;
653 return(result);
654 # else /* ECOS */
655 abort();
656 # endif /* ECOS */
658 # endif
660 # ifndef ECOS
662 #ifdef LINUX_STACKBOTTOM
664 #include <sys/types.h>
665 #include <sys/stat.h>
667 # define STAT_SKIP 27 /* Number of fields preceding startstack */
668 /* field in /proc/self/stat */
670 # pragma weak __libc_stack_end
671 extern ptr_t __libc_stack_end;
673 # ifdef IA64
674 # pragma weak __libc_ia64_register_backing_store_base
675 extern ptr_t __libc_ia64_register_backing_store_base;
677 ptr_t GC_get_register_stack_base(void)
679 if (0 != &__libc_ia64_register_backing_store_base
680 && 0 != __libc_ia64_register_backing_store_base) {
681 /* Glibc 2.2.4 has a bug such that for dynamically linked */
682 /* executables __libc_ia64_register_backing_store_base is */
683 /* defined but ininitialized during constructor calls. */
684 /* Hence we check for both nonzero address and value. */
685 return __libc_ia64_register_backing_store_base;
686 } else {
687 word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
688 result += BACKING_STORE_ALIGNMENT - 1;
689 result &= ~(BACKING_STORE_ALIGNMENT - 1);
690 return (ptr_t)result;
693 # endif
695 ptr_t GC_linux_stack_base(void)
697 /* We read the stack base value from /proc/self/stat. We do this */
698 /* using direct I/O system calls in order to avoid calling malloc */
699 /* in case REDIRECT_MALLOC is defined. */
700 # define STAT_BUF_SIZE 4096
701 # if defined(GC_USE_LD_WRAP)
702 # define STAT_READ __real_read
703 # else
704 # define STAT_READ read
705 # endif
706 char stat_buf[STAT_BUF_SIZE];
707 int f;
708 char c;
709 word result = 0;
710 size_t i, buf_offset = 0;
712 /* First try the easy way. This should work for glibc 2.2 */
713 if (0 != &__libc_stack_end) {
714 return __libc_stack_end;
716 f = open("/proc/self/stat", O_RDONLY);
717 if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
718 ABORT("Couldn't read /proc/self/stat");
720 c = stat_buf[buf_offset++];
721 /* Skip the required number of fields. This number is hopefully */
722 /* constant across all Linux implementations. */
723 for (i = 0; i < STAT_SKIP; ++i) {
724 while (isspace(c)) c = stat_buf[buf_offset++];
725 while (!isspace(c)) c = stat_buf[buf_offset++];
727 while (isspace(c)) c = stat_buf[buf_offset++];
728 while (isdigit(c)) {
729 result *= 10;
730 result += c - '0';
731 c = stat_buf[buf_offset++];
733 close(f);
734 if (result < 0x10000000) ABORT("Absurd stack bottom value");
735 return (ptr_t)result;
738 #endif /* LINUX_STACKBOTTOM */
740 #ifdef FREEBSD_STACKBOTTOM
742 /* This uses an undocumented sysctl call, but at least one expert */
743 /* believes it will stay. */
745 #include <unistd.h>
746 #include <sys/types.h>
747 #include <sys/sysctl.h>
749 ptr_t GC_freebsd_stack_base(void)
751 int nm[2] = { CTL_KERN, KERN_USRSTACK}, base, len, r;
753 len = sizeof(int);
754 r = sysctl(nm, 2, &base, &len, NULL, 0);
756 if (r) ABORT("Error getting stack base");
758 return (ptr_t)base;
761 #endif /* FREEBSD_STACKBOTTOM */
763 #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
764 && !defined(MSWINCE) && !defined(OS2) && !defined(ECOS)
766 ptr_t GC_get_stack_base()
768 word dummy;
769 ptr_t result;
771 # define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
773 # ifdef STACKBOTTOM
774 return(STACKBOTTOM);
775 # else
776 # ifdef HEURISTIC1
777 # ifdef STACK_GROWS_DOWN
778 result = (ptr_t)((((word)(&dummy))
779 + STACKBOTTOM_ALIGNMENT_M1)
780 & ~STACKBOTTOM_ALIGNMENT_M1);
781 # else
782 result = (ptr_t)(((word)(&dummy))
783 & ~STACKBOTTOM_ALIGNMENT_M1);
784 # endif
785 # endif /* HEURISTIC1 */
786 # ifdef LINUX_STACKBOTTOM
787 result = GC_linux_stack_base();
788 # endif
789 # ifdef FREEBSD_STACKBOTTOM
790 result = GC_freebsd_stack_base();
791 # endif
792 # ifdef HEURISTIC2
793 # ifdef STACK_GROWS_DOWN
794 result = GC_find_limit((ptr_t)(&dummy), TRUE);
795 # ifdef HEURISTIC2_LIMIT
796 if (result > HEURISTIC2_LIMIT
797 && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
798 result = HEURISTIC2_LIMIT;
800 # endif
801 # else
802 result = GC_find_limit((ptr_t)(&dummy), FALSE);
803 # ifdef HEURISTIC2_LIMIT
804 if (result < HEURISTIC2_LIMIT
805 && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
806 result = HEURISTIC2_LIMIT;
808 # endif
809 # endif
811 # endif /* HEURISTIC2 */
812 # ifdef STACK_GROWS_DOWN
813 if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t));
814 # endif
815 return(result);
816 # endif /* STACKBOTTOM */
818 # endif /* ECOS */
820 # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS */
823 * Register static data segment(s) as roots.
824 * If more data segments are added later then they need to be registered
825 * add that point (as we do with SunOS dynamic loading),
826 * or GC_mark_roots needs to check for them (as we do with PCR).
827 * Called with allocator lock held.
830 # ifdef OS2
832 void GC_register_data_segments()
834 PTIB ptib;
835 PPIB ppib;
836 HMODULE module_handle;
837 # define PBUFSIZ 512
838 UCHAR path[PBUFSIZ];
839 FILE * myexefile;
840 struct exe_hdr hdrdos; /* MSDOS header. */
841 struct e32_exe hdr386; /* Real header for my executable */
842 struct o32_obj seg; /* Currrent segment */
843 int nsegs;
846 if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
847 GC_err_printf0("DosGetInfoBlocks failed\n");
848 ABORT("DosGetInfoBlocks failed\n");
850 module_handle = ppib -> pib_hmte;
851 if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
852 GC_err_printf0("DosQueryModuleName failed\n");
853 ABORT("DosGetInfoBlocks failed\n");
855 myexefile = fopen(path, "rb");
856 if (myexefile == 0) {
857 GC_err_puts("Couldn't open executable ");
858 GC_err_puts(path); GC_err_puts("\n");
859 ABORT("Failed to open executable\n");
861 if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
862 GC_err_puts("Couldn't read MSDOS header from ");
863 GC_err_puts(path); GC_err_puts("\n");
864 ABORT("Couldn't read MSDOS header");
866 if (E_MAGIC(hdrdos) != EMAGIC) {
867 GC_err_puts("Executable has wrong DOS magic number: ");
868 GC_err_puts(path); GC_err_puts("\n");
869 ABORT("Bad DOS magic number");
871 if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
872 GC_err_puts("Seek to new header failed in ");
873 GC_err_puts(path); GC_err_puts("\n");
874 ABORT("Bad DOS magic number");
876 if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) {
877 GC_err_puts("Couldn't read MSDOS header from ");
878 GC_err_puts(path); GC_err_puts("\n");
879 ABORT("Couldn't read OS/2 header");
881 if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
882 GC_err_puts("Executable has wrong OS/2 magic number:");
883 GC_err_puts(path); GC_err_puts("\n");
884 ABORT("Bad OS/2 magic number");
886 if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
887 GC_err_puts("Executable %s has wrong byte order: ");
888 GC_err_puts(path); GC_err_puts("\n");
889 ABORT("Bad byte order");
891 if ( E32_CPU(hdr386) == E32CPU286) {
892 GC_err_puts("GC can't handle 80286 executables: ");
893 GC_err_puts(path); GC_err_puts("\n");
894 EXIT();
896 if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
897 SEEK_SET) != 0) {
898 GC_err_puts("Seek to object table failed: ");
899 GC_err_puts(path); GC_err_puts("\n");
900 ABORT("Seek to object table failed");
902 for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
903 int flags;
904 if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) {
905 GC_err_puts("Couldn't read obj table entry from ");
906 GC_err_puts(path); GC_err_puts("\n");
907 ABORT("Couldn't read obj table entry");
909 flags = O32_FLAGS(seg);
910 if (!(flags & OBJWRITE)) continue;
911 if (!(flags & OBJREAD)) continue;
912 if (flags & OBJINVALID) {
913 GC_err_printf0("Object with invalid pages?\n");
914 continue;
916 GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
920 # else /* !OS2 */
922 # if defined(MSWIN32) || defined(MSWINCE)
924 # ifdef MSWIN32
925 /* Unfortunately, we have to handle win32s very differently from NT, */
926 /* Since VirtualQuery has very different semantics. In particular, */
927 /* under win32s a VirtualQuery call on an unmapped page returns an */
928 /* invalid result. Under GC_register_data_segments is a noop and */
929 /* all real work is done by GC_register_dynamic_libraries. Under */
930 /* win32s, we cannot find the data segments associated with dll's. */
931 /* We rgister the main data segment here. */
932 GC_bool GC_win32s = FALSE; /* We're running under win32s. */
934 GC_bool GC_is_win32s()
936 DWORD v = GetVersion();
938 /* Check that this is not NT, and Windows major version <= 3 */
939 return ((v & 0x80000000) && (v & 0xff) <= 3);
942 void GC_init_win32()
944 GC_win32s = GC_is_win32s();
947 /* Return the smallest address a such that VirtualQuery */
948 /* returns correct results for all addresses between a and start. */
949 /* Assumes VirtualQuery returns correct information for start. */
950 ptr_t GC_least_described_address(ptr_t start)
952 MEMORY_BASIC_INFORMATION buf;
953 DWORD result;
954 LPVOID limit;
955 ptr_t p;
956 LPVOID q;
958 limit = GC_sysinfo.lpMinimumApplicationAddress;
959 p = (ptr_t)((word)start & ~(GC_page_size - 1));
960 for (;;) {
961 q = (LPVOID)(p - GC_page_size);
962 if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
963 result = VirtualQuery(q, &buf, sizeof(buf));
964 if (result != sizeof(buf) || buf.AllocationBase == 0) break;
965 p = (ptr_t)(buf.AllocationBase);
967 return(p);
969 # endif
971 /* Is p the start of either the malloc heap, or of one of our */
972 /* heap sections? */
973 GC_bool GC_is_heap_base (ptr_t p)
976 register unsigned i;
978 # ifndef REDIRECT_MALLOC
979 static ptr_t malloc_heap_pointer = 0;
981 if (0 == malloc_heap_pointer) {
982 MEMORY_BASIC_INFORMATION buf;
983 void *pTemp = malloc( 1 );
984 register DWORD result = VirtualQuery(pTemp, &buf, sizeof(buf));
986 free( pTemp );
989 if (result != sizeof(buf)) {
990 ABORT("Weird VirtualQuery result");
992 malloc_heap_pointer = (ptr_t)(buf.AllocationBase);
994 if (p == malloc_heap_pointer) return(TRUE);
995 # endif
996 for (i = 0; i < GC_n_heap_bases; i++) {
997 if (GC_heap_bases[i] == p) return(TRUE);
999 return(FALSE);
1002 # ifdef MSWIN32
1003 void GC_register_root_section(ptr_t static_root)
1005 MEMORY_BASIC_INFORMATION buf;
1006 DWORD result;
1007 DWORD protect;
1008 LPVOID p;
1009 char * base;
1010 char * limit, * new_limit;
1012 if (!GC_win32s) return;
1013 p = base = limit = GC_least_described_address(static_root);
1014 while (p < GC_sysinfo.lpMaximumApplicationAddress) {
1015 result = VirtualQuery(p, &buf, sizeof(buf));
1016 if (result != sizeof(buf) || buf.AllocationBase == 0
1017 || GC_is_heap_base(buf.AllocationBase)) break;
1018 new_limit = (char *)p + buf.RegionSize;
1019 protect = buf.Protect;
1020 if (buf.State == MEM_COMMIT
1021 && is_writable(protect)) {
1022 if ((char *)p == limit) {
1023 limit = new_limit;
1024 } else {
1025 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
1026 base = p;
1027 limit = new_limit;
1030 if (p > (LPVOID)new_limit /* overflow */) break;
1031 p = (LPVOID)new_limit;
1033 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
1035 #endif
1037 void GC_register_data_segments()
1039 # ifdef MSWIN32
1040 static char dummy;
1041 GC_register_root_section((ptr_t)(&dummy));
1042 # endif
1045 # else /* !OS2 && !Windows */
1047 # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
1048 || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
1049 char * GC_SysVGetDataStart(max_page_size, etext_addr)
1050 int max_page_size;
1051 int * etext_addr;
1053 word text_end = ((word)(etext_addr) + sizeof(word) - 1)
1054 & ~(sizeof(word) - 1);
1055 /* etext rounded to word boundary */
1056 word next_page = ((text_end + (word)max_page_size - 1)
1057 & ~((word)max_page_size - 1));
1058 word page_offset = (text_end & ((word)max_page_size - 1));
1059 VOLATILE char * result = (char *)(next_page + page_offset);
1060 /* Note that this isnt equivalent to just adding */
1061 /* max_page_size to &etext if &etext is at a page boundary */
1063 GC_setup_temporary_fault_handler();
1064 if (setjmp(GC_jmp_buf) == 0) {
1065 /* Try writing to the address. */
1066 *result = *result;
1067 GC_reset_fault_handler();
1068 } else {
1069 GC_reset_fault_handler();
1070 /* We got here via a longjmp. The address is not readable. */
1071 /* This is known to happen under Solaris 2.4 + gcc, which place */
1072 /* string constants in the text segment, but after etext. */
1073 /* Use plan B. Note that we now know there is a gap between */
1074 /* text and data segments, so plan A bought us something. */
1075 result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);
1077 return((char *)result);
1079 # endif
1082 #ifdef AMIGA
1084 # define GC_AMIGA_DS
1085 # include "AmigaOS.c"
1086 # undef GC_AMIGA_DS
1088 #else /* !OS2 && !Windows && !AMIGA */
1090 void GC_register_data_segments()
1092 # if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \
1093 && !defined(MACOSX)
1094 # if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
1095 /* As of Solaris 2.3, the Solaris threads implementation */
1096 /* allocates the data structure for the initial thread with */
1097 /* sbrk at process startup. It needs to be scanned, so that */
1098 /* we don't lose some malloc allocated data structures */
1099 /* hanging from it. We're on thin ice here ... */
1100 extern caddr_t sbrk();
1102 GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
1103 # else
1104 GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
1105 # endif
1106 # endif
1107 # if !defined(PCR) && (defined(NEXT) || defined(MACOSX))
1108 GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE);
1109 # endif
1110 # if defined(MACOS)
1112 # if defined(THINK_C)
1113 extern void* GC_MacGetDataStart(void);
1114 /* globals begin above stack and end at a5. */
1115 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
1116 (ptr_t)LMGetCurrentA5(), FALSE);
1117 # else
1118 # if defined(__MWERKS__)
1119 # if !__POWERPC__
1120 extern void* GC_MacGetDataStart(void);
1121 /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
1122 # if __option(far_data)
1123 extern void* GC_MacGetDataEnd(void);
1124 # endif
1125 /* globals begin above stack and end at a5. */
1126 GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
1127 (ptr_t)LMGetCurrentA5(), FALSE);
1128 /* MATTHEW: Handle Far Globals */
1129 # if __option(far_data)
1130 /* Far globals follow he QD globals: */
1131 GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
1132 (ptr_t)GC_MacGetDataEnd(), FALSE);
1133 # endif
1134 # else
1135 extern char __data_start__[], __data_end__[];
1136 GC_add_roots_inner((ptr_t)&__data_start__,
1137 (ptr_t)&__data_end__, FALSE);
1138 # endif /* __POWERPC__ */
1139 # endif /* __MWERKS__ */
1140 # endif /* !THINK_C */
1142 # endif /* MACOS */
1144 /* Dynamic libraries are added at every collection, since they may */
1145 /* change. */
1148 # endif /* ! AMIGA */
1149 # endif /* ! MSWIN32 && ! MSWINCE*/
1150 # endif /* ! OS2 */
1153 * Auxiliary routines for obtaining memory from OS.
1156 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
1157 && !defined(MSWIN32) && !defined(MSWINCE) \
1158 && !defined(MACOS) && !defined(DOS4GW)
1160 # ifdef SUNOS4
1161 extern caddr_t sbrk();
1162 # endif
1163 # ifdef __STDC__
1164 # define SBRK_ARG_T ptrdiff_t
1165 # else
1166 # define SBRK_ARG_T int
1167 # endif
1170 # ifdef RS6000
1171 /* The compiler seems to generate speculative reads one past the end of */
1172 /* an allocated object. Hence we need to make sure that the page */
1173 /* following the last heap page is also mapped. */
1174 ptr_t GC_unix_get_mem(bytes)
1175 word bytes;
1177 caddr_t cur_brk = (caddr_t)sbrk(0);
1178 caddr_t result;
1179 SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
1180 static caddr_t my_brk_val = 0;
1182 if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
1183 if (lsbs != 0) {
1184 if((caddr_t)(sbrk(GC_page_size - lsbs)) == (caddr_t)(-1)) return(0);
1186 if (cur_brk == my_brk_val) {
1187 /* Use the extra block we allocated last time. */
1188 result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
1189 if (result == (caddr_t)(-1)) return(0);
1190 result -= GC_page_size;
1191 } else {
1192 result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
1193 if (result == (caddr_t)(-1)) return(0);
1195 my_brk_val = result + bytes + GC_page_size; /* Always page aligned */
1196 return((ptr_t)result);
1199 #else /* Not RS6000 */
1201 #if defined(USE_MMAP)
1202 /* Tested only under Linux, IRIX5 and Solaris 2 */
1204 #ifdef USE_MMAP_FIXED
1205 # define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
1206 /* Seems to yield better performance on Solaris 2, but can */
1207 /* be unreliable if something is already mapped at the address. */
1208 #else
1209 # define GC_MMAP_FLAGS MAP_PRIVATE
1210 #endif
1212 #ifndef HEAP_START
1213 # define HEAP_START 0
1214 #endif
1216 ptr_t GC_unix_get_mem(bytes)
1217 word bytes;
1219 static GC_bool initialized = FALSE;
1220 static int fd;
1221 void *result;
1222 static ptr_t last_addr = HEAP_START;
1224 if (!initialized) {
1225 fd = open("/dev/zero", O_RDONLY);
1226 initialized = TRUE;
1228 if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
1229 result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
1230 GC_MMAP_FLAGS, fd, 0/* offset */);
1231 if (result == MAP_FAILED) return(0);
1232 last_addr = (ptr_t)result + bytes + GC_page_size - 1;
1233 last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
1234 # if !defined(LINUX)
1235 if (last_addr == 0) {
1236 /* Oops. We got the end of the address space. This isn't */
1237 /* usable by arbitrary C code, since one-past-end pointers */
1238 /* don't work, so we discard it and try again. */
1239 munmap(result, (size_t)(-GC_page_size) - (size_t)result);
1240 /* Leave last page mapped, so we can't repeat. */
1241 return GC_unix_get_mem(bytes);
1243 # else
1244 GC_ASSERT(last_addr != 0);
1245 # endif
1246 return((ptr_t)result);
1249 #else /* Not RS6000, not USE_MMAP */
1250 ptr_t GC_unix_get_mem(bytes)
1251 word bytes;
1253 ptr_t result;
1254 # ifdef IRIX5
1255 /* Bare sbrk isn't thread safe. Play by malloc rules. */
1256 /* The equivalent may be needed on other systems as well. */
1257 __LOCK_MALLOC();
1258 # endif
1260 ptr_t cur_brk = (ptr_t)sbrk(0);
1261 SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
1263 if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
1264 if (lsbs != 0) {
1265 if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) return(0);
1267 result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
1268 if (result == (ptr_t)(-1)) result = 0;
1270 # ifdef IRIX5
1271 __UNLOCK_MALLOC();
1272 # endif
1273 return(result);
1276 #endif /* Not USE_MMAP */
1277 #endif /* Not RS6000 */
1279 # endif /* UN*X */
1281 # ifdef OS2
1283 void * os2_alloc(size_t bytes)
1285 void * result;
1287 if (DosAllocMem(&result, bytes, PAG_EXECUTE | PAG_READ |
1288 PAG_WRITE | PAG_COMMIT)
1289 != NO_ERROR) {
1290 return(0);
1292 if (result == 0) return(os2_alloc(bytes));
1293 return(result);
1296 # endif /* OS2 */
1299 # if defined(MSWIN32) || defined(MSWINCE)
1300 SYSTEM_INFO GC_sysinfo;
1301 # endif
1304 # ifdef MSWIN32
1305 word GC_n_heap_bases = 0;
1307 ptr_t GC_win32_get_mem(bytes)
1308 word bytes;
1310 ptr_t result;
1312 if (GC_win32s) {
1313 /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE. */
1314 /* There are also unconfirmed rumors of other */
1315 /* problems, so we dodge the issue. */
1316 result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
1317 result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
1318 } else {
1319 result = (ptr_t) VirtualAlloc(NULL, bytes,
1320 MEM_COMMIT | MEM_RESERVE,
1321 PAGE_EXECUTE_READWRITE);
1323 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
1324 /* If I read the documentation correctly, this can */
1325 /* only happen if HBLKSIZE > 64k or not a power of 2. */
1326 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
1327 GC_heap_bases[GC_n_heap_bases++] = result;
1328 return(result);
1331 void GC_win32_free_heap ()
1333 if (GC_win32s) {
1334 while (GC_n_heap_bases > 0) {
1335 GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
1336 GC_heap_bases[GC_n_heap_bases] = 0;
1340 # endif
1342 #ifdef AMIGA
1343 # define GC_AMIGA_AM
1344 # include "AmigaOS.c"
1345 # undef GC_AMIGA_AM
1346 #endif
1349 # ifdef MSWINCE
1350 word GC_n_heap_bases = 0;
1352 ptr_t GC_wince_get_mem(bytes)
1353 word bytes;
1355 ptr_t result;
1356 word i;
1358 /* Round up allocation size to multiple of page size */
1359 bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
1361 /* Try to find reserved, uncommitted pages */
1362 for (i = 0; i < GC_n_heap_bases; i++) {
1363 if (((word)(-(signed_word)GC_heap_lengths[i])
1364 & (GC_sysinfo.dwAllocationGranularity-1))
1365 >= bytes) {
1366 result = GC_heap_bases[i] + GC_heap_lengths[i];
1367 break;
1371 if (i == GC_n_heap_bases) {
1372 /* Reserve more pages */
1373 word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
1374 & ~(GC_sysinfo.dwAllocationGranularity-1);
1375 result = (ptr_t) VirtualAlloc(NULL, res_bytes,
1376 MEM_RESERVE | MEM_TOP_DOWN,
1377 PAGE_EXECUTE_READWRITE);
1378 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
1379 /* If I read the documentation correctly, this can */
1380 /* only happen if HBLKSIZE > 64k or not a power of 2. */
1381 if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
1382 GC_heap_bases[GC_n_heap_bases] = result;
1383 GC_heap_lengths[GC_n_heap_bases] = 0;
1384 GC_n_heap_bases++;
1387 /* Commit pages */
1388 result = (ptr_t) VirtualAlloc(result, bytes,
1389 MEM_COMMIT,
1390 PAGE_EXECUTE_READWRITE);
1391 if (result != NULL) {
1392 if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
1393 GC_heap_lengths[i] += bytes;
1396 return(result);
1398 # endif
1400 #ifdef USE_MUNMAP
1402 /* For now, this only works on Win32/WinCE and some Unix-like */
1403 /* systems. If you have something else, don't define */
1404 /* USE_MUNMAP. */
1405 /* We assume ANSI C to support this feature. */
1407 #if !defined(MSWIN32) && !defined(MSWINCE)
1409 #include <unistd.h>
1410 #include <sys/mman.h>
1411 #include <sys/stat.h>
1412 #include <sys/types.h>
1414 #endif
1416 /* Compute a page aligned starting address for the unmap */
1417 /* operation on a block of size bytes starting at start. */
1418 /* Return 0 if the block is too small to make this feasible. */
1419 ptr_t GC_unmap_start(ptr_t start, word bytes)
1421 ptr_t result = start;
1422 /* Round start to next page boundary. */
1423 result += GC_page_size - 1;
1424 result = (ptr_t)((word)result & ~(GC_page_size - 1));
1425 if (result + GC_page_size > start + bytes) return 0;
1426 return result;
1429 /* Compute end address for an unmap operation on the indicated */
1430 /* block. */
1431 ptr_t GC_unmap_end(ptr_t start, word bytes)
1433 ptr_t end_addr = start + bytes;
1434 end_addr = (ptr_t)((word)end_addr & ~(GC_page_size - 1));
1435 return end_addr;
1438 /* Under Win32/WinCE we commit (map) and decommit (unmap) */
1439 /* memory using VirtualAlloc and VirtualFree. These functions */
1440 /* work on individual allocations of virtual memory, made */
1441 /* previously using VirtualAlloc with the MEM_RESERVE flag. */
1442 /* The ranges we need to (de)commit may span several of these */
1443 /* allocations; therefore we use VirtualQuery to check */
1444 /* allocation lengths, and split up the range as necessary. */
1446 /* We assume that GC_remap is called on exactly the same range */
1447 /* as a previous call to GC_unmap. It is safe to consistently */
1448 /* round the endpoints in both places. */
1449 void GC_unmap(ptr_t start, word bytes)
1451 ptr_t start_addr = GC_unmap_start(start, bytes);
1452 ptr_t end_addr = GC_unmap_end(start, bytes);
1453 word len = end_addr - start_addr;
1454 if (0 == start_addr) return;
1455 # if defined(MSWIN32) || defined(MSWINCE)
1456 while (len != 0) {
1457 MEMORY_BASIC_INFORMATION mem_info;
1458 GC_word free_len;
1459 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
1460 != sizeof(mem_info))
1461 ABORT("Weird VirtualQuery result");
1462 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
1463 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
1464 ABORT("VirtualFree failed");
1465 GC_unmapped_bytes += free_len;
1466 start_addr += free_len;
1467 len -= free_len;
1469 # else
1470 if (munmap(start_addr, len) != 0) ABORT("munmap failed");
1471 GC_unmapped_bytes += len;
1472 # endif
1476 void GC_remap(ptr_t start, word bytes)
1478 static int zero_descr = -1;
1479 ptr_t start_addr = GC_unmap_start(start, bytes);
1480 ptr_t end_addr = GC_unmap_end(start, bytes);
1481 word len = end_addr - start_addr;
1482 ptr_t result;
1484 # if defined(MSWIN32) || defined(MSWINCE)
1485 if (0 == start_addr) return;
1486 while (len != 0) {
1487 MEMORY_BASIC_INFORMATION mem_info;
1488 GC_word alloc_len;
1489 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
1490 != sizeof(mem_info))
1491 ABORT("Weird VirtualQuery result");
1492 alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
1493 result = VirtualAlloc(start_addr, alloc_len,
1494 MEM_COMMIT,
1495 PAGE_EXECUTE_READWRITE);
1496 if (result != start_addr) {
1497 ABORT("VirtualAlloc remapping failed");
1499 GC_unmapped_bytes -= alloc_len;
1500 start_addr += alloc_len;
1501 len -= alloc_len;
1503 # else
1504 if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);
1505 if (0 == start_addr) return;
1506 result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
1507 MAP_FIXED | MAP_PRIVATE, zero_descr, 0);
1508 if (result != start_addr) {
1509 ABORT("mmap remapping failed");
1511 GC_unmapped_bytes -= len;
1512 # endif
1515 /* Two adjacent blocks have already been unmapped and are about to */
1516 /* be merged. Unmap the whole block. This typically requires */
1517 /* that we unmap a small section in the middle that was not previously */
1518 /* unmapped due to alignment constraints. */
1519 void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t start2, word bytes2)
1521 ptr_t start1_addr = GC_unmap_start(start1, bytes1);
1522 ptr_t end1_addr = GC_unmap_end(start1, bytes1);
1523 ptr_t start2_addr = GC_unmap_start(start2, bytes2);
1524 ptr_t end2_addr = GC_unmap_end(start2, bytes2);
1525 ptr_t start_addr = end1_addr;
1526 ptr_t end_addr = start2_addr;
1527 word len;
1528 GC_ASSERT(start1 + bytes1 == start2);
1529 if (0 == start1_addr) start_addr = GC_unmap_start(start1, bytes1 + bytes2);
1530 if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
1531 if (0 == start_addr) return;
1532 len = end_addr - start_addr;
1533 # if defined(MSWIN32) || defined(MSWINCE)
1534 while (len != 0) {
1535 MEMORY_BASIC_INFORMATION mem_info;
1536 GC_word free_len;
1537 if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
1538 != sizeof(mem_info))
1539 ABORT("Weird VirtualQuery result");
1540 free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
1541 if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
1542 ABORT("VirtualFree failed");
1543 GC_unmapped_bytes += free_len;
1544 start_addr += free_len;
1545 len -= free_len;
1547 # else
1548 if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed");
1549 GC_unmapped_bytes += len;
1550 # endif
1553 #endif /* USE_MUNMAP */
1555 /* Routine for pushing any additional roots. In THREADS */
1556 /* environment, this is also responsible for marking from */
1557 /* thread stacks. */
1558 #ifndef THREADS
1559 void (*GC_push_other_roots)() = 0;
1560 #else /* THREADS */
1562 # ifdef PCR
1563 PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
1565 struct PCR_ThCtl_TInfoRep info;
1566 PCR_ERes result;
1568 info.ti_stkLow = info.ti_stkHi = 0;
1569 result = PCR_ThCtl_GetInfo(t, &info);
1570 GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
1571 return(result);
1574 /* Push the contents of an old object. We treat this as stack */
1575 /* data only becasue that makes it robust against mark stack */
1576 /* overflow. */
1577 PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
1579 GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
1580 return(PCR_ERes_okay);
1584 void GC_default_push_other_roots GC_PROTO((void))
1586 /* Traverse data allocated by previous memory managers. */
1588 extern struct PCR_MM_ProcsRep * GC_old_allocator;
1590 if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
1591 GC_push_old_obj, 0)
1592 != PCR_ERes_okay) {
1593 ABORT("Old object enumeration failed");
1596 /* Traverse all thread stacks. */
1597 if (PCR_ERes_IsErr(
1598 PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
1599 || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
1600 ABORT("Thread stack marking failed\n");
1604 # endif /* PCR */
1606 # ifdef SRC_M3
1608 # ifdef ALL_INTERIOR_POINTERS
1609 --> misconfigured
1610 # endif
1612 void GC_push_thread_structures GC_PROTO((void))
1614 /* Not our responsibibility. */
1617 extern void ThreadF__ProcessStacks();
1619 void GC_push_thread_stack(start, stop)
1620 word start, stop;
1622 GC_push_all_stack((ptr_t)start, (ptr_t)stop + sizeof(word));
1625 /* Push routine with M3 specific calling convention. */
1626 GC_m3_push_root(dummy1, p, dummy2, dummy3)
1627 word *p;
1628 ptr_t dummy1, dummy2;
1629 int dummy3;
1631 word q = *p;
1633 GC_PUSH_ONE_STACK(q, p);
1636 /* M3 set equivalent to RTHeap.TracedRefTypes */
1637 typedef struct { int elts[1]; } RefTypeSet;
1638 RefTypeSet GC_TracedRefTypes = {{0x1}};
1640 void GC_default_push_other_roots GC_PROTO((void))
1642 /* Use the M3 provided routine for finding static roots. */
1643 /* This is a bit dubious, since it presumes no C roots. */
1644 /* We handle the collector roots explicitly in GC_push_roots */
1645 RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
1646 if (GC_words_allocd > 0) {
1647 ThreadF__ProcessStacks(GC_push_thread_stack);
1649 /* Otherwise this isn't absolutely necessary, and we have */
1650 /* startup ordering problems. */
1653 # endif /* SRC_M3 */
1655 # if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
1656 defined(GC_WIN32_THREADS)
1658 extern void GC_push_all_stacks();
1660 void GC_default_push_other_roots GC_PROTO((void))
1662 GC_push_all_stacks();
1665 # endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
1667 void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
1669 #endif /* THREADS */
1672 * Routines for accessing dirty bits on virtual pages.
1673 * We plan to eventually implement four strategies for doing so:
1674 * DEFAULT_VDB: A simple dummy implementation that treats every page
1675 * as possibly dirty. This makes incremental collection
1676 * useless, but the implementation is still correct.
1677 * PCR_VDB: Use PPCRs virtual dirty bit facility.
1678 * PROC_VDB: Use the /proc facility for reading dirty bits. Only
1679 * works under some SVR4 variants. Even then, it may be
1680 * too slow to be entirely satisfactory. Requires reading
1681 * dirty bits for entire address space. Implementations tend
1682 * to assume that the client is a (slow) debugger.
1683 * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
1684 * dirtied pages. The implementation (and implementability)
1685 * is highly system dependent. This usually fails when system
1686 * calls write to a protected page. We prevent the read system
1687 * call from doing so. It is the clients responsibility to
1688 * make sure that other system calls are similarly protected
1689 * or write only to the stack.
1692 GC_bool GC_dirty_maintained = FALSE;
1694 # ifdef DEFAULT_VDB
1696 /* All of the following assume the allocation lock is held, and */
1697 /* signals are disabled. */
1699 /* The client asserts that unallocated pages in the heap are never */
1700 /* written. */
1702 /* Initialize virtual dirty bit implementation. */
1703 void GC_dirty_init()
1705 GC_dirty_maintained = TRUE;
1708 /* Retrieve system dirty bits for heap to a local buffer. */
1709 /* Restore the systems notion of which pages are dirty. */
1710 void GC_read_dirty()
1713 /* Is the HBLKSIZE sized page at h marked dirty in the local buffer? */
1714 /* If the actual page size is different, this returns TRUE if any */
1715 /* of the pages overlapping h are dirty. This routine may err on the */
1716 /* side of labelling pages as dirty (and this implementation does). */
1717 /*ARGSUSED*/
1718 GC_bool GC_page_was_dirty(h)
1719 struct hblk *h;
1721 return(TRUE);
1725 * The following two routines are typically less crucial. They matter
1726 * most with large dynamic libraries, or if we can't accurately identify
1727 * stacks, e.g. under Solaris 2.X. Otherwise the following default
1728 * versions are adequate.
1731 /* Could any valid GC heap pointer ever have been written to this page? */
1732 /*ARGSUSED*/
1733 GC_bool GC_page_was_ever_dirty(h)
1734 struct hblk *h;
1736 return(TRUE);
1739 /* Reset the n pages starting at h to "was never dirty" status. */
1740 void GC_is_fresh(h, n)
1741 struct hblk *h;
1742 word n;
1746 /* A call hints that h is about to be written. */
1747 /* May speed up some dirty bit implementations. */
1748 /*ARGSUSED*/
1749 void GC_write_hint(h)
1750 struct hblk *h;
1754 # endif /* DEFAULT_VDB */
1757 # ifdef MPROTECT_VDB
1760 * See DEFAULT_VDB for interface descriptions.
1764 * This implementation maintains dirty bits itself by catching write
1765 * faults and keeping track of them. We assume nobody else catches
1766 * SIGBUS or SIGSEGV. We assume no write faults occur in system calls
1767 * except as a result of a read system call. This means clients must
1768 * either ensure that system calls do not touch the heap, or must
1769 * provide their own wrappers analogous to the one for read.
1770 * We assume the page size is a multiple of HBLKSIZE.
1771 * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we
1772 * tried to use portable code where easily possible. It is known
1773 * not to work under a number of other systems.
1776 # if !defined(MSWIN32) && !defined(MSWINCE)
1778 # include <sys/mman.h>
1779 # include <signal.h>
1780 # include <sys/syscall.h>
1782 # define PROTECT(addr, len) \
1783 if (mprotect((caddr_t)(addr), (size_t)(len), \
1784 PROT_READ | OPT_PROT_EXEC) < 0) { \
1785 ABORT("mprotect failed"); \
1787 # define UNPROTECT(addr, len) \
1788 if (mprotect((caddr_t)(addr), (size_t)(len), \
1789 PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
1790 ABORT("un-mprotect failed"); \
1793 # else
1795 # ifndef MSWINCE
1796 # include <signal.h>
1797 # endif
1799 static DWORD protect_junk;
1800 # define PROTECT(addr, len) \
1801 if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
1802 &protect_junk)) { \
1803 DWORD last_error = GetLastError(); \
1804 GC_printf1("Last error code: %lx\n", last_error); \
1805 ABORT("VirtualProtect failed"); \
1807 # define UNPROTECT(addr, len) \
1808 if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READWRITE, \
1809 &protect_junk)) { \
1810 ABORT("un-VirtualProtect failed"); \
1813 # endif
1815 #if defined(SUNOS4) || defined(FREEBSD)
1816 typedef void (* SIG_PF)();
1817 #endif
1818 #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
1819 || defined(MACOSX) || defined(HURD)
1820 # ifdef __STDC__
1821 typedef void (* SIG_PF)(int);
1822 # else
1823 typedef void (* SIG_PF)();
1824 # endif
1825 #endif
1826 #if defined(MSWIN32)
1827 typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
1828 # undef SIG_DFL
1829 # define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
1830 #endif
1831 #if defined(MSWINCE)
1832 typedef LONG (WINAPI *SIG_PF)(struct _EXCEPTION_POINTERS *);
1833 # undef SIG_DFL
1834 # define SIG_DFL (SIG_PF) (-1)
1835 #endif
1837 #if defined(IRIX5) || defined(OSF1) || defined(HURD)
1838 typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
1839 #endif
1840 #if defined(SUNOS5SIGS)
1841 # ifdef HPUX
1842 # define SIGINFO __siginfo
1843 # else
1844 # define SIGINFO siginfo
1845 # endif
1846 # ifdef __STDC__
1847 typedef void (* REAL_SIG_PF)(int, struct SIGINFO *, void *);
1848 # else
1849 typedef void (* REAL_SIG_PF)();
1850 # endif
1851 #endif
1852 #if defined(LINUX)
1853 # include <linux/version.h>
1854 # if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(IA64)
1855 typedef struct sigcontext s_c;
1856 # else
1857 typedef struct sigcontext_struct s_c;
1858 # endif
1859 # if defined(ALPHA) || defined(M68K)
1860 typedef void (* REAL_SIG_PF)(int, int, s_c *);
1861 # else
1862 # if defined(IA64) || defined(HP_PA)
1863 typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
1864 # else
1865 typedef void (* REAL_SIG_PF)(int, s_c);
1866 # endif
1867 # endif
1868 # ifdef ALPHA
1869 /* Retrieve fault address from sigcontext structure by decoding */
1870 /* instruction. */
1871 char * get_fault_addr(s_c *sc) {
1872 unsigned instr;
1873 word faultaddr;
1875 instr = *((unsigned *)(sc->sc_pc));
1876 faultaddr = sc->sc_regs[(instr >> 16) & 0x1f];
1877 faultaddr += (word) (((int)instr << 16) >> 16);
1878 return (char *)faultaddr;
1880 # endif /* !ALPHA */
1881 # endif
1883 # if defined(MACOSX) /* Should also test for PowerPC? */
1884 typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
1886 /* Decodes the machine instruction which was responsible for the sending of the
1887 SIGBUS signal. Sadly this is the only way to find the faulting address because
1888 the signal handler doesn't get it directly from the kernel (although it is
1889 available on the Mach level, but droppped by the BSD personality before it
1890 calls our signal handler...)
1891 This code should be able to deal correctly with all PPCs starting from the
1892 601 up to and including the G4s (including Velocity Engine). */
1893 #define EXTRACT_OP1(iw) (((iw) & 0xFC000000) >> 26)
1894 #define EXTRACT_OP2(iw) (((iw) & 0x000007FE) >> 1)
1895 #define EXTRACT_REGA(iw) (((iw) & 0x001F0000) >> 16)
1896 #define EXTRACT_REGB(iw) (((iw) & 0x03E00000) >> 21)
1897 #define EXTRACT_REGC(iw) (((iw) & 0x0000F800) >> 11)
1898 #define EXTRACT_DISP(iw) ((short *) &(iw))[1]
1900 static char *get_fault_addr(struct sigcontext *scp)
1902 unsigned int instr = *((unsigned int *) scp->sc_ir);
1903 unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
1904 int disp = 0, tmp;
1905 unsigned int baseA = 0, baseB = 0;
1906 unsigned int addr, alignmask = 0xFFFFFFFF;
1908 #ifdef GC_DEBUG_DECODER
1909 GC_err_printf1("Instruction: 0x%lx\n", instr);
1910 GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
1911 #endif
1912 switch(EXTRACT_OP1(instr)) {
1913 case 38: /* stb */
1914 case 39: /* stbu */
1915 case 54: /* stfd */
1916 case 55: /* stfdu */
1917 case 52: /* stfs */
1918 case 53: /* stfsu */
1919 case 44: /* sth */
1920 case 45: /* sthu */
1921 case 47: /* stmw */
1922 case 36: /* stw */
1923 case 37: /* stwu */
1924 tmp = EXTRACT_REGA(instr);
1925 if(tmp > 0)
1926 baseA = regs[tmp];
1927 disp = EXTRACT_DISP(instr);
1928 break;
1929 case 31:
1930 #ifdef GC_DEBUG_DECODER
1931 GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
1932 #endif
1933 switch(EXTRACT_OP2(instr)) {
1934 case 86: /* dcbf */
1935 case 54: /* dcbst */
1936 case 1014: /* dcbz */
1937 case 247: /* stbux */
1938 case 215: /* stbx */
1939 case 759: /* stfdux */
1940 case 727: /* stfdx */
1941 case 983: /* stfiwx */
1942 case 695: /* stfsux */
1943 case 663: /* stfsx */
1944 case 918: /* sthbrx */
1945 case 439: /* sthux */
1946 case 407: /* sthx */
1947 case 661: /* stswx */
1948 case 662: /* stwbrx */
1949 case 150: /* stwcx. */
1950 case 183: /* stwux */
1951 case 151: /* stwx */
1952 case 135: /* stvebx */
1953 case 167: /* stvehx */
1954 case 199: /* stvewx */
1955 case 231: /* stvx */
1956 case 487: /* stvxl */
1957 tmp = EXTRACT_REGA(instr);
1958 if(tmp > 0)
1959 baseA = regs[tmp];
1960 baseB = regs[EXTRACT_REGC(instr)];
1961 /* determine Altivec alignment mask */
1962 switch(EXTRACT_OP2(instr)) {
1963 case 167: /* stvehx */
1964 alignmask = 0xFFFFFFFE;
1965 break;
1966 case 199: /* stvewx */
1967 alignmask = 0xFFFFFFFC;
1968 break;
1969 case 231: /* stvx */
1970 alignmask = 0xFFFFFFF0;
1971 break;
1972 case 487: /* stvxl */
1973 alignmask = 0xFFFFFFF0;
1974 break;
1976 break;
1977 case 725: /* stswi */
1978 tmp = EXTRACT_REGA(instr);
1979 if(tmp > 0)
1980 baseA = regs[tmp];
1981 break;
1982 default: /* ignore instruction */
1983 #ifdef GC_DEBUG_DECODER
1984 GC_err_printf("Ignored by inner handler\n");
1985 #endif
1986 return NULL;
1987 break;
1989 break;
1990 default: /* ignore instruction */
1991 #ifdef GC_DEBUG_DECODER
1992 GC_err_printf("Ignored by main handler\n");
1993 #endif
1994 return NULL;
1995 break;
1998 addr = (baseA + baseB) + disp;
1999 addr &= alignmask;
2000 #ifdef GC_DEBUG_DECODER
2001 GC_err_printf1("BaseA: %d\n", baseA);
2002 GC_err_printf1("BaseB: %d\n", baseB);
2003 GC_err_printf1("Disp: %d\n", disp);
2004 GC_err_printf1("Address: %d\n", addr);
2005 #endif
2006 return (char *)addr;
2008 #endif /* MACOSX */
2010 SIG_PF GC_old_bus_handler;
2011 SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS_VIOLATION filter */
2013 #ifdef THREADS
2014 /* We need to lock around the bitmap update in the write fault handler */
2015 /* in order to avoid the risk of losing a bit. We do this with a */
2016 /* test-and-set spin lock if we know how to do that. Otherwise we */
2017 /* check whether we are already in the handler and use the dumb but */
2018 /* safe fallback algorithm of setting all bits in the word. */
2019 /* Contention should be very rare, so we do the minimum to handle it */
2020 /* correctly. */
2021 #ifdef GC_TEST_AND_SET_DEFINED
2022 static VOLATILE unsigned int fault_handler_lock = 0;
2023 void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
2024 while (GC_test_and_set(&fault_handler_lock)) {}
2025 /* Could also revert to set_pht_entry_from_index_safe if initial */
2026 /* GC_test_and_set fails. */
2027 set_pht_entry_from_index(db, index);
2028 GC_clear(&fault_handler_lock);
2030 #else /* !GC_TEST_AND_SET_DEFINED */
2031 /* THIS IS INCORRECT! The dirty bit vector may be temporarily wrong, */
2032 /* just before we notice the conflict and correct it. We may end up */
2033 /* looking at it while it's wrong. But this requires contention */
2034 /* exactly when a GC is triggered, which seems far less likely to */
2035 /* fail than the old code, which had no reported failures. Thus we */
2036 /* leave it this way while we think of something better, or support */
2037 /* GC_test_and_set on the remaining platforms. */
2038 static VOLATILE word currently_updating = 0;
2039 void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
2040 unsigned int update_dummy;
2041 currently_updating = (word)(&update_dummy);
2042 set_pht_entry_from_index(db, index);
2043 /* If we get contention in the 10 or so instruction window here, */
2044 /* and we get stopped by a GC between the two updates, we lose! */
2045 if (currently_updating != (word)(&update_dummy)) {
2046 set_pht_entry_from_index_safe(db, index);
2047 /* We claim that if two threads concurrently try to update the */
2048 /* dirty bit vector, the first one to execute UPDATE_START */
2049 /* will see it changed when UPDATE_END is executed. (Note that */
2050 /* &update_dummy must differ in two distinct threads.) It */
2051 /* will then execute set_pht_entry_from_index_safe, thus */
2052 /* returning us to a safe state, though not soon enough. */
2055 #endif /* !GC_TEST_AND_SET_DEFINED */
2056 #else /* !THREADS */
2057 # define async_set_pht_entry_from_index(db, index) \
2058 set_pht_entry_from_index(db, index)
2059 #endif /* !THREADS */
2061 /*ARGSUSED*/
2062 # if defined (SUNOS4) || defined(FREEBSD)
2063 void GC_write_fault_handler(sig, code, scp, addr)
2064 int sig, code;
2065 struct sigcontext *scp;
2066 char * addr;
2067 # ifdef SUNOS4
2068 # define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
2069 # define CODE_OK (FC_CODE(code) == FC_PROT \
2070 || (FC_CODE(code) == FC_OBJERR \
2071 && FC_ERRNO(code) == FC_PROT))
2072 # endif
2073 # ifdef FREEBSD
2074 # define SIG_OK (sig == SIGBUS)
2075 # define CODE_OK (code == BUS_PAGE_FAULT)
2076 # endif
2077 # endif
2078 # if defined(IRIX5) || defined(OSF1) || defined(HURD)
2079 # include <errno.h>
2080 void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
2081 # ifdef OSF1
2082 # define SIG_OK (sig == SIGSEGV)
2083 # define CODE_OK (code == 2 /* experimentally determined */)
2084 # endif
2085 # ifdef IRIX5
2086 # define SIG_OK (sig == SIGSEGV)
2087 # define CODE_OK (code == EACCES)
2088 # endif
2089 # ifdef HURD
2090 # define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
2091 # define CODE_OK TRUE
2092 # endif
2093 # endif
2094 # if defined(LINUX)
2095 # if defined(ALPHA) || defined(M68K)
2096 void GC_write_fault_handler(int sig, int code, s_c * sc)
2097 # else
2098 # if defined(IA64) || defined(HP_PA)
2099 void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
2100 # else
2101 void GC_write_fault_handler(int sig, s_c sc)
2102 # endif
2103 # endif
2104 # define SIG_OK (sig == SIGSEGV)
2105 # define CODE_OK TRUE
2106 /* Empirically c.trapno == 14, on IA32, but is that useful? */
2107 /* Should probably consider alignment issues on other */
2108 /* architectures. */
2109 # endif
2110 # if defined(SUNOS5SIGS)
2111 # ifdef __STDC__
2112 void GC_write_fault_handler(int sig, struct SIGINFO *scp, void * context)
2113 # else
2114 void GC_write_fault_handler(sig, scp, context)
2115 int sig;
2116 struct SIGINFO *scp;
2117 void * context;
2118 # endif
2119 # ifdef HPUX
2120 # define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
2121 # define CODE_OK (scp -> si_code == SEGV_ACCERR) \
2122 || (scp -> si_code == BUS_ADRERR) \
2123 || (scp -> si_code == BUS_UNKNOWN) \
2124 || (scp -> si_code == SEGV_UNKNOWN) \
2125 || (scp -> si_code == BUS_OBJERR)
2126 # else
2127 # define SIG_OK (sig == SIGSEGV)
2128 # define CODE_OK (scp -> si_code == SEGV_ACCERR)
2129 # endif
2130 # endif
2132 # if defined(MACOSX)
2133 void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
2134 # define SIG_OK (sig == SIGBUS)
2135 # define CODE_OK (code == 0 /* experimentally determined */)
2136 # endif
2138 # if defined(MSWIN32) || defined(MSWINCE)
2139 LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
2140 # define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
2141 STATUS_ACCESS_VIOLATION)
2142 # define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
2143 /* Write fault */
2144 # endif
2146 register unsigned i;
2147 # if defined(HURD)
2148 char *addr = (char *) code;
2149 # endif
2150 # ifdef IRIX5
2151 char * addr = (char *) (size_t) (scp -> sc_badvaddr);
2152 # endif
2153 # if defined(OSF1) && defined(ALPHA)
2154 char * addr = (char *) (scp -> sc_traparg_a0);
2155 # endif
2156 # ifdef SUNOS5SIGS
2157 char * addr = (char *) (scp -> si_addr);
2158 # endif
2159 # ifdef LINUX
2160 # ifdef I386
2161 char * addr = (char *) (sc.cr2);
2162 # else
2163 # if defined(M68K)
2164 char * addr = NULL;
2166 struct sigcontext *scp = (struct sigcontext *)(sc);
2168 int format = (scp->sc_formatvec >> 12) & 0xf;
2169 unsigned long *framedata = (unsigned long *)(scp + 1);
2170 unsigned long ea;
2172 if (format == 0xa || format == 0xb) {
2173 /* 68020/030 */
2174 ea = framedata[2];
2175 } else if (format == 7) {
2176 /* 68040 */
2177 ea = framedata[3];
2178 if (framedata[1] & 0x08000000) {
2179 /* correct addr on misaligned access */
2180 ea = (ea+4095)&(~4095);
2182 } else if (format == 4) {
2183 /* 68060 */
2184 ea = framedata[0];
2185 if (framedata[1] & 0x08000000) {
2186 /* correct addr on misaligned access */
2187 ea = (ea+4095)&(~4095);
2190 addr = (char *)ea;
2191 # else
2192 # ifdef ALPHA
2193 char * addr = get_fault_addr(sc);
2194 # else
2195 # if defined(IA64) || defined(HP_PA)
2196 char * addr = si -> si_addr;
2197 /* I believe this is claimed to work on all platforms for */
2198 /* Linux 2.3.47 and later. Hopefully we don't have to */
2199 /* worry about earlier kernels on IA64. */
2200 # else
2201 # if defined(POWERPC)
2202 char * addr = (char *) (sc.regs->dar);
2203 # else
2204 --> architecture not supported
2205 # endif
2206 # endif
2207 # endif
2208 # endif
2209 # endif
2210 # endif
2211 # if defined(MACOSX)
2212 char * addr = get_fault_addr(scp);
2213 # endif
2214 # if defined(MSWIN32) || defined(MSWINCE)
2215 char * addr = (char *) (exc_info -> ExceptionRecord
2216 -> ExceptionInformation[1]);
2217 # define sig SIGSEGV
2218 # endif
2220 if (SIG_OK && CODE_OK) {
2221 register struct hblk * h =
2222 (struct hblk *)((word)addr & ~(GC_page_size-1));
2223 GC_bool in_allocd_block;
2225 # ifdef SUNOS5SIGS
2226 /* Address is only within the correct physical page. */
2227 in_allocd_block = FALSE;
2228 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
2229 if (HDR(h+i) != 0) {
2230 in_allocd_block = TRUE;
2233 # else
2234 in_allocd_block = (HDR(addr) != 0);
2235 # endif
2236 if (!in_allocd_block) {
2237 /* Heap blocks now begin and end on page boundaries */
2238 SIG_PF old_handler;
2240 if (sig == SIGSEGV) {
2241 old_handler = GC_old_segv_handler;
2242 } else {
2243 old_handler = GC_old_bus_handler;
2245 if (old_handler == SIG_DFL) {
2246 # if !defined(MSWIN32) && !defined(MSWINCE)
2247 GC_err_printf1("Segfault at 0x%lx\n", addr);
2248 ABORT("Unexpected bus error or segmentation fault");
2249 # else
2250 return(EXCEPTION_CONTINUE_SEARCH);
2251 # endif
2252 } else {
2253 # if defined (SUNOS4) || defined(FREEBSD)
2254 (*old_handler) (sig, code, scp, addr);
2255 return;
2256 # endif
2257 # if defined (SUNOS5SIGS)
2258 (*(REAL_SIG_PF)old_handler) (sig, scp, context);
2259 return;
2260 # endif
2261 # if defined (LINUX)
2262 # if defined(ALPHA) || defined(M68K)
2263 (*(REAL_SIG_PF)old_handler) (sig, code, sc);
2264 # else
2265 # if defined(IA64) || defined(HP_PA)
2266 (*(REAL_SIG_PF)old_handler) (sig, si, scp);
2267 # else
2268 (*(REAL_SIG_PF)old_handler) (sig, sc);
2269 # endif
2270 # endif
2271 return;
2272 # endif
2273 # if defined (IRIX5) || defined(OSF1) || defined(HURD)
2274 (*(REAL_SIG_PF)old_handler) (sig, code, scp);
2275 return;
2276 # endif
2277 # ifdef MACOSX
2278 (*(REAL_SIG_PF)old_handler) (sig, code, scp);
2279 # endif
2280 # ifdef MSWIN32
2281 return((*old_handler)(exc_info));
2282 # endif
2285 UNPROTECT(h, GC_page_size);
2286 /* We need to make sure that no collection occurs between */
2287 /* the UNPROTECT and the setting of the dirty bit. Otherwise */
2288 /* a write by a third thread might go unnoticed. Reversing */
2289 /* the order is just as bad, since we would end up unprotecting */
2290 /* a page in a GC cycle during which it's not marked. */
2291 /* Currently we do this by disabling the thread stopping */
2292 /* signals while this handler is running. An alternative might */
2293 /* be to record the fact that we're about to unprotect, or */
2294 /* have just unprotected a page in the GC's thread structure, */
2295 /* and then to have the thread stopping code set the dirty */
2296 /* flag, if necessary. */
2297 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
2298 register int index = PHT_HASH(h+i);
2300 async_set_pht_entry_from_index(GC_dirty_pages, index);
2302 # if defined(OSF1)
2303 /* These reset the signal handler each time by default. */
2304 signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
2305 # endif
2306 /* The write may not take place before dirty bits are read. */
2307 /* But then we'll fault again ... */
2308 # if defined(MSWIN32) || defined(MSWINCE)
2309 return(EXCEPTION_CONTINUE_EXECUTION);
2310 # else
2311 return;
2312 # endif
2314 #if defined(MSWIN32) || defined(MSWINCE)
2315 return EXCEPTION_CONTINUE_SEARCH;
2316 #else
2317 GC_err_printf1("Segfault at 0x%lx\n", addr);
2318 ABORT("Unexpected bus error or segmentation fault");
2319 #endif
2323 * We hold the allocation lock. We expect block h to be written
2324 * shortly.
2326 void GC_write_hint(h)
2327 struct hblk *h;
2329 register struct hblk * h_trunc;
2330 register unsigned i;
2331 register GC_bool found_clean;
2333 if (!GC_dirty_maintained) return;
2334 h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
2335 found_clean = FALSE;
2336 for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
2337 register int index = PHT_HASH(h_trunc+i);
2339 if (!get_pht_entry_from_index(GC_dirty_pages, index)) {
2340 found_clean = TRUE;
2341 async_set_pht_entry_from_index(GC_dirty_pages, index);
2344 if (found_clean) {
2345 UNPROTECT(h_trunc, GC_page_size);
2349 void GC_dirty_init()
2351 # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
2352 defined(OSF1) || defined(HURD)
2353 struct sigaction act, oldact;
2354 /* We should probably specify SA_SIGINFO for Linux, and handle */
2355 /* the different architectures more uniformly. */
2356 # if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD)
2357 act.sa_flags = SA_RESTART;
2358 act.sa_handler = (SIG_PF)GC_write_fault_handler;
2359 # else
2360 act.sa_flags = SA_RESTART | SA_SIGINFO;
2361 act.sa_sigaction = GC_write_fault_handler;
2362 # endif
2363 (void)sigemptyset(&act.sa_mask);
2364 # ifdef SIG_SUSPEND
2365 /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
2366 /* handler. This effectively makes the handler atomic w.r.t. */
2367 /* stopping the world for GC. */
2368 (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
2369 # endif /* SIG_SUSPEND */
2370 # endif
2371 # if defined(MACOSX)
2372 struct sigaction act, oldact;
2374 act.sa_flags = SA_RESTART;
2375 act.sa_handler = GC_write_fault_handler;
2376 sigemptyset(&act.sa_mask);
2377 # endif
2378 # ifdef PRINTSTATS
2379 GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
2380 # endif
2381 GC_dirty_maintained = TRUE;
2382 if (GC_page_size % HBLKSIZE != 0) {
2383 GC_err_printf0("Page size not multiple of HBLKSIZE\n");
2384 ABORT("Page size not multiple of HBLKSIZE");
2386 # if defined(SUNOS4) || defined(FREEBSD)
2387 GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
2388 if (GC_old_bus_handler == SIG_IGN) {
2389 GC_err_printf0("Previously ignored bus error!?");
2390 GC_old_bus_handler = SIG_DFL;
2392 if (GC_old_bus_handler != SIG_DFL) {
2393 # ifdef PRINTSTATS
2394 GC_err_printf0("Replaced other SIGBUS handler\n");
2395 # endif
2397 # endif
2398 # if defined(SUNOS4)
2399 GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
2400 if (GC_old_segv_handler == SIG_IGN) {
2401 GC_err_printf0("Previously ignored segmentation violation!?");
2402 GC_old_segv_handler = SIG_DFL;
2404 if (GC_old_segv_handler != SIG_DFL) {
2405 # ifdef PRINTSTATS
2406 GC_err_printf0("Replaced other SIGSEGV handler\n");
2407 # endif
2409 # endif
2410 # if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \
2411 || defined(OSF1) || defined(HURD)
2412 /* SUNOS5SIGS includes HPUX */
2413 # if defined(GC_IRIX_THREADS)
2414 sigaction(SIGSEGV, 0, &oldact);
2415 sigaction(SIGSEGV, &act, 0);
2416 # else
2417 sigaction(SIGSEGV, &act, &oldact);
2418 # endif
2419 # if defined(_sigargs) || defined(HURD)
2420 /* This is Irix 5.x, not 6.x. Irix 5.x does not have */
2421 /* sa_sigaction. */
2422 GC_old_segv_handler = oldact.sa_handler;
2423 # else /* Irix 6.x or SUNOS5SIGS or LINUX */
2424 if (oldact.sa_flags & SA_SIGINFO) {
2425 GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
2426 } else {
2427 GC_old_segv_handler = oldact.sa_handler;
2429 # endif
2430 if (GC_old_segv_handler == SIG_IGN) {
2431 GC_err_printf0("Previously ignored segmentation violation!?");
2432 GC_old_segv_handler = SIG_DFL;
2434 if (GC_old_segv_handler != SIG_DFL) {
2435 # ifdef PRINTSTATS
2436 GC_err_printf0("Replaced other SIGSEGV handler\n");
2437 # endif
2439 # endif
2440 # if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
2441 sigaction(SIGBUS, &act, &oldact);
2442 GC_old_bus_handler = oldact.sa_handler;
2443 if (GC_old_bus_handler == SIG_IGN) {
2444 GC_err_printf0("Previously ignored bus error!?");
2445 GC_old_bus_handler = SIG_DFL;
2447 if (GC_old_bus_handler != SIG_DFL) {
2448 # ifdef PRINTSTATS
2449 GC_err_printf0("Replaced other SIGBUS handler\n");
2450 # endif
2452 # endif /* MACOS || HPUX || LINUX */
2453 # if defined(MSWIN32)
2454 GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
2455 if (GC_old_segv_handler != NULL) {
2456 # ifdef PRINTSTATS
2457 GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
2458 # endif
2459 } else {
2460 GC_old_segv_handler = SIG_DFL;
2462 # endif
2467 void GC_protect_heap()
2469 ptr_t start;
2470 word len;
2471 unsigned i;
2473 for (i = 0; i < GC_n_heap_sects; i++) {
2474 start = GC_heap_sects[i].hs_start;
2475 len = GC_heap_sects[i].hs_bytes;
2476 PROTECT(start, len);
2480 /* We assume that either the world is stopped or its OK to lose dirty */
2481 /* bits while this is happenning (as in GC_enable_incremental). */
2482 void GC_read_dirty()
2484 BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
2485 (sizeof GC_dirty_pages));
2486 BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
2487 GC_protect_heap();
2490 GC_bool GC_page_was_dirty(h)
2491 struct hblk * h;
2493 register word index = PHT_HASH(h);
2495 return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
2499 * Acquiring the allocation lock here is dangerous, since this
2500 * can be called from within GC_call_with_alloc_lock, and the cord
2501 * package does so. On systems that allow nested lock acquisition, this
2502 * happens to work.
2503 * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
2506 static GC_bool syscall_acquired_lock = FALSE; /* Protected by GC lock. */
2508 void GC_begin_syscall()
2510 if (!I_HOLD_LOCK()) {
2511 LOCK();
2512 syscall_acquired_lock = TRUE;
2516 void GC_end_syscall()
2518 if (syscall_acquired_lock) {
2519 syscall_acquired_lock = FALSE;
2520 UNLOCK();
2524 void GC_unprotect_range(addr, len)
2525 ptr_t addr;
2526 word len;
2528 struct hblk * start_block;
2529 struct hblk * end_block;
2530 register struct hblk *h;
2531 ptr_t obj_start;
2533 if (!GC_incremental) return;
2534 obj_start = GC_base(addr);
2535 if (obj_start == 0) return;
2536 if (GC_base(addr + len - 1) != obj_start) {
2537 ABORT("GC_unprotect_range(range bigger than object)");
2539 start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
2540 end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
2541 end_block += GC_page_size/HBLKSIZE - 1;
2542 for (h = start_block; h <= end_block; h++) {
2543 register word index = PHT_HASH(h);
2545 async_set_pht_entry_from_index(GC_dirty_pages, index);
2547 UNPROTECT(start_block,
2548 ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
2551 #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_LINUX_THREADS) \
2552 && !defined(GC_USE_LD_WRAP)
2553 /* Replacement for UNIX system call. */
2554 /* Other calls that write to the heap */
2555 /* should be handled similarly. */
2556 # if defined(__STDC__) && !defined(SUNOS4)
2557 # include <unistd.h>
2558 # include <sys/uio.h>
2559 ssize_t read(int fd, void *buf, size_t nbyte)
2560 # else
2561 # ifndef LINT
2562 int read(fd, buf, nbyte)
2563 # else
2564 int GC_read(fd, buf, nbyte)
2565 # endif
2566 int fd;
2567 char *buf;
2568 int nbyte;
2569 # endif
2571 int result;
2573 GC_begin_syscall();
2574 GC_unprotect_range(buf, (word)nbyte);
2575 # if defined(IRIX5) || defined(GC_LINUX_THREADS)
2576 /* Indirect system call may not always be easily available. */
2577 /* We could call _read, but that would interfere with the */
2578 /* libpthread interception of read. */
2579 /* On Linux, we have to be careful with the linuxthreads */
2580 /* read interception. */
2582 struct iovec iov;
2584 iov.iov_base = buf;
2585 iov.iov_len = nbyte;
2586 result = readv(fd, &iov, 1);
2588 # else
2589 # if defined(HURD)
2590 result = __read(fd, buf, nbyte);
2591 # else
2592 /* The two zero args at the end of this list are because one
2593 IA-64 syscall() implementation actually requires six args
2594 to be passed, even though they aren't always used. */
2595 result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
2596 # endif /* !HURD */
2597 # endif
2598 GC_end_syscall();
2599 return(result);
2601 #endif /* !MSWIN32 && !MSWINCE && !GC_LINUX_THREADS */
2603 #ifdef GC_USE_LD_WRAP
2604 /* We use the GNU ld call wrapping facility. */
2605 /* This requires that the linker be invoked with "--wrap read". */
2606 /* This can be done by passing -Wl,"--wrap read" to gcc. */
2607 /* I'm not sure that this actually wraps whatever version of read */
2608 /* is called by stdio. That code also mentions __read. */
2609 # include <unistd.h>
2610 ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
2612 int result;
2614 GC_begin_syscall();
2615 GC_unprotect_range(buf, (word)nbyte);
2616 result = __real_read(fd, buf, nbyte);
2617 GC_end_syscall();
2618 return(result);
2621 /* We should probably also do this for __read, or whatever stdio */
2622 /* actually calls. */
2623 #endif
2625 /*ARGSUSED*/
2626 GC_bool GC_page_was_ever_dirty(h)
2627 struct hblk *h;
2629 return(TRUE);
2632 /* Reset the n pages starting at h to "was never dirty" status. */
2633 /*ARGSUSED*/
2634 void GC_is_fresh(h, n)
2635 struct hblk *h;
2636 word n;
2640 # else /* !MPROTECT_VDB */
2642 # ifdef GC_USE_LD_WRAP
2643 ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
2644 { return __real_read(fd, buf, nbyte); }
2645 # endif
2647 # endif /* MPROTECT_VDB */
2649 # ifdef PROC_VDB
2652 * See DEFAULT_VDB for interface descriptions.
2656 * This implementaion assumes a Solaris 2.X like /proc pseudo-file-system
2657 * from which we can read page modified bits. This facility is far from
2658 * optimal (e.g. we would like to get the info for only some of the
2659 * address space), but it avoids intercepting system calls.
2662 #include <errno.h>
2663 #include <sys/types.h>
2664 #include <sys/signal.h>
2665 #include <sys/fault.h>
2666 #include <sys/syscall.h>
2667 #include <sys/procfs.h>
2668 #include <sys/stat.h>
2670 #define INITIAL_BUF_SZ 4096
2671 word GC_proc_buf_size = INITIAL_BUF_SZ;
2672 char *GC_proc_buf;
2674 #ifdef GC_SOLARIS_THREADS
2675 /* We don't have exact sp values for threads. So we count on */
2676 /* occasionally declaring stack pages to be fresh. Thus we */
2677 /* need a real implementation of GC_is_fresh. We can't clear */
2678 /* entries in GC_written_pages, since that would declare all */
2679 /* pages with the given hash address to be fresh. */
2680 # define MAX_FRESH_PAGES 8*1024 /* Must be power of 2 */
2681 struct hblk ** GC_fresh_pages; /* A direct mapped cache. */
2682 /* Collisions are dropped. */
2684 # define FRESH_PAGE_SLOT(h) (divHBLKSZ((word)(h)) & (MAX_FRESH_PAGES-1))
2685 # define ADD_FRESH_PAGE(h) \
2686 GC_fresh_pages[FRESH_PAGE_SLOT(h)] = (h)
2687 # define PAGE_IS_FRESH(h) \
2688 (GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
2689 #endif
2691 /* Add all pages in pht2 to pht1 */
2692 void GC_or_pages(pht1, pht2)
2693 page_hash_table pht1, pht2;
2695 register int i;
2697 for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
2700 int GC_proc_fd;
2702 void GC_dirty_init()
2704 int fd;
2705 char buf[30];
2707 GC_dirty_maintained = TRUE;
2708 if (GC_words_allocd != 0 || GC_words_allocd_before_gc != 0) {
2709 register int i;
2711 for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
2712 # ifdef PRINTSTATS
2713 GC_printf1("Allocated words:%lu:all pages may have been written\n",
2714 (unsigned long)
2715 (GC_words_allocd + GC_words_allocd_before_gc));
2716 # endif
2718 sprintf(buf, "/proc/%d", getpid());
2719 fd = open(buf, O_RDONLY);
2720 if (fd < 0) {
2721 ABORT("/proc open failed");
2723 GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
2724 close(fd);
2725 if (GC_proc_fd < 0) {
2726 ABORT("/proc ioctl failed");
2728 GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
2729 # ifdef GC_SOLARIS_THREADS
2730 GC_fresh_pages = (struct hblk **)
2731 GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
2732 if (GC_fresh_pages == 0) {
2733 GC_err_printf0("No space for fresh pages\n");
2734 EXIT();
2736 BZERO(GC_fresh_pages, MAX_FRESH_PAGES * sizeof (struct hblk *));
2737 # endif
2740 /* Ignore write hints. They don't help us here. */
2741 /*ARGSUSED*/
2742 void GC_write_hint(h)
2743 struct hblk *h;
2747 #ifdef GC_SOLARIS_THREADS
2748 # define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
2749 #else
2750 # define READ(fd,buf,nbytes) read(fd, buf, nbytes)
2751 #endif
2753 void GC_read_dirty()
2755 unsigned long ps, np;
2756 int nmaps;
2757 ptr_t vaddr;
2758 struct prasmap * map;
2759 char * bufp;
2760 ptr_t current_addr, limit;
2761 int i;
2762 int dummy;
2764 BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
2766 bufp = GC_proc_buf;
2767 if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
2768 # ifdef PRINTSTATS
2769 GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
2770 GC_proc_buf_size);
2771 # endif
2773 /* Retry with larger buffer. */
2774 word new_size = 2 * GC_proc_buf_size;
2775 char * new_buf = GC_scratch_alloc(new_size);
2777 if (new_buf != 0) {
2778 GC_proc_buf = bufp = new_buf;
2779 GC_proc_buf_size = new_size;
2781 if (syscall(SYS_read, GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
2782 WARN("Insufficient space for /proc read\n", 0);
2783 /* Punt: */
2784 memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
2785 memset(GC_written_pages, 0xff, sizeof(page_hash_table));
2786 # ifdef GC_SOLARIS_THREADS
2787 BZERO(GC_fresh_pages,
2788 MAX_FRESH_PAGES * sizeof (struct hblk *));
2789 # endif
2790 return;
2794 /* Copy dirty bits into GC_grungy_pages */
2795 nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
2796 /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
2797 nmaps, PG_REFERENCED, PG_MODIFIED); */
2798 bufp = bufp + sizeof(struct prpageheader);
2799 for (i = 0; i < nmaps; i++) {
2800 map = (struct prasmap *)bufp;
2801 vaddr = (ptr_t)(map -> pr_vaddr);
2802 ps = map -> pr_pagesize;
2803 np = map -> pr_npage;
2804 /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
2805 limit = vaddr + ps * np;
2806 bufp += sizeof (struct prasmap);
2807 for (current_addr = vaddr;
2808 current_addr < limit; current_addr += ps){
2809 if ((*bufp++) & PG_MODIFIED) {
2810 register struct hblk * h = (struct hblk *) current_addr;
2812 while ((ptr_t)h < current_addr + ps) {
2813 register word index = PHT_HASH(h);
2815 set_pht_entry_from_index(GC_grungy_pages, index);
2816 # ifdef GC_SOLARIS_THREADS
2818 register int slot = FRESH_PAGE_SLOT(h);
2820 if (GC_fresh_pages[slot] == h) {
2821 GC_fresh_pages[slot] = 0;
2824 # endif
2825 h++;
2829 bufp += sizeof(long) - 1;
2830 bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
2832 /* Update GC_written_pages. */
2833 GC_or_pages(GC_written_pages, GC_grungy_pages);
2834 # ifdef GC_SOLARIS_THREADS
2835 /* Make sure that old stacks are considered completely clean */
2836 /* unless written again. */
2837 GC_old_stacks_are_fresh();
2838 # endif
2841 #undef READ
2843 GC_bool GC_page_was_dirty(h)
2844 struct hblk *h;
2846 register word index = PHT_HASH(h);
2847 register GC_bool result;
2849 result = get_pht_entry_from_index(GC_grungy_pages, index);
2850 # ifdef GC_SOLARIS_THREADS
2851 if (result && PAGE_IS_FRESH(h)) result = FALSE;
2852 /* This happens only if page was declared fresh since */
2853 /* the read_dirty call, e.g. because it's in an unused */
2854 /* thread stack. It's OK to treat it as clean, in */
2855 /* that case. And it's consistent with */
2856 /* GC_page_was_ever_dirty. */
2857 # endif
2858 return(result);
2861 GC_bool GC_page_was_ever_dirty(h)
2862 struct hblk *h;
2864 register word index = PHT_HASH(h);
2865 register GC_bool result;
2867 result = get_pht_entry_from_index(GC_written_pages, index);
2868 # ifdef GC_SOLARIS_THREADS
2869 if (result && PAGE_IS_FRESH(h)) result = FALSE;
2870 # endif
2871 return(result);
2874 /* Caller holds allocation lock. */
2875 void GC_is_fresh(h, n)
2876 struct hblk *h;
2877 word n;
2880 register word index;
2882 # ifdef GC_SOLARIS_THREADS
2883 register word i;
2885 if (GC_fresh_pages != 0) {
2886 for (i = 0; i < n; i++) {
2887 ADD_FRESH_PAGE(h + i);
2890 # endif
2893 # endif /* PROC_VDB */
2896 # ifdef PCR_VDB
2898 # include "vd/PCR_VD.h"
2900 # define NPAGES (32*1024) /* 128 MB */
2902 PCR_VD_DB GC_grungy_bits[NPAGES];
2904 ptr_t GC_vd_base; /* Address corresponding to GC_grungy_bits[0] */
2905 /* HBLKSIZE aligned. */
2907 void GC_dirty_init()
2909 GC_dirty_maintained = TRUE;
2910 /* For the time being, we assume the heap generally grows up */
2911 GC_vd_base = GC_heap_sects[0].hs_start;
2912 if (GC_vd_base == 0) {
2913 ABORT("Bad initial heap segment");
2915 if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
2916 != PCR_ERes_okay) {
2917 ABORT("dirty bit initialization failed");
2921 void GC_read_dirty()
2923 /* lazily enable dirty bits on newly added heap sects */
2925 static int onhs = 0;
2926 int nhs = GC_n_heap_sects;
2927 for( ; onhs < nhs; onhs++ ) {
2928 PCR_VD_WriteProtectEnable(
2929 GC_heap_sects[onhs].hs_start,
2930 GC_heap_sects[onhs].hs_bytes );
2935 if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
2936 != PCR_ERes_okay) {
2937 ABORT("dirty bit read failed");
2941 GC_bool GC_page_was_dirty(h)
2942 struct hblk *h;
2944 if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
2945 return(TRUE);
2947 return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
2950 /*ARGSUSED*/
2951 void GC_write_hint(h)
2952 struct hblk *h;
2954 PCR_VD_WriteProtectDisable(h, HBLKSIZE);
2955 PCR_VD_WriteProtectEnable(h, HBLKSIZE);
2958 # endif /* PCR_VDB */
2961 * Call stack save code for debugging.
2962 * Should probably be in mach_dep.c, but that requires reorganization.
2965 /* I suspect the following works for most X86 *nix variants, so */
2966 /* long as the frame pointer is explicitly stored. In the case of gcc, */
2967 /* compiler flags (e.g. -fomit-frame-pointer) determine whether it is. */
2968 #if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
2969 struct frame {
2970 struct frame *fr_savfp;
2971 long fr_savpc;
2972 long fr_arg[NARGS]; /* All the arguments go here. */
2974 #endif
2976 #if defined(SPARC)
2977 # if defined(LINUX)
2978 struct frame {
2979 long fr_local[8];
2980 long fr_arg[6];
2981 struct frame *fr_savfp;
2982 long fr_savpc;
2983 # ifndef __arch64__
2984 char *fr_stret;
2985 # endif
2986 long fr_argd[6];
2987 long fr_argx[0];
2989 # else
2990 # if defined(SUNOS4)
2991 # include <machine/frame.h>
2992 # else
2993 # if defined (DRSNX)
2994 # include <sys/sparc/frame.h>
2995 # else
2996 # if defined(OPENBSD) || defined(NETBSD)
2997 # include <frame.h>
2998 # else
2999 # include <sys/frame.h>
3000 # endif
3001 # endif
3002 # endif
3003 # endif
3004 # if NARGS > 6
3005 --> We only know how to to get the first 6 arguments
3006 # endif
3007 #endif /* SPARC */
3009 #ifdef SAVE_CALL_CHAIN
3010 /* Fill in the pc and argument information for up to NFRAMES of my */
3011 /* callers. Ignore my frame and my callers frame. */
3013 #if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
3014 # define FR_SAVFP fr_fp
3015 # define FR_SAVPC fr_pc
3016 #else
3017 # define FR_SAVFP fr_savfp
3018 # define FR_SAVPC fr_savpc
3019 #endif
3021 #if defined(SPARC) && (defined(__arch64__) || defined(__sparcv9))
3022 # define BIAS 2047
3023 #else
3024 # define BIAS 0
3025 #endif
3027 void GC_save_callers (info)
3028 struct callinfo info[NFRAMES];
3030 struct frame *frame;
3031 struct frame *fp;
3032 int nframes = 0;
3033 # ifdef I386
3034 /* We assume this is turned on only with gcc as the compiler. */
3035 asm("movl %%ebp,%0" : "=r"(frame));
3036 fp = frame;
3037 # else
3038 word GC_save_regs_in_stack();
3040 frame = (struct frame *) GC_save_regs_in_stack ();
3041 fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
3042 #endif
3044 for (; (!(fp HOTTER_THAN frame) && !(GC_stackbottom HOTTER_THAN (ptr_t)fp)
3045 && (nframes < NFRAMES));
3046 fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
3047 register int i;
3049 info[nframes].ci_pc = fp->FR_SAVPC;
3050 # if NARGS > 0
3051 for (i = 0; i < NARGS; i++) {
3052 info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
3054 # endif /* NARGS > 0 */
3056 if (nframes < NFRAMES) info[nframes].ci_pc = 0;
3059 #endif /* SAVE_CALL_CHAIN */
3061 #if defined(LINUX) && defined(__ELF__) && \
3062 (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
3063 #ifdef GC_USE_LD_WRAP
3064 # define READ __real_read
3065 #else
3066 # define READ read
3067 #endif
3070 /* Repeatedly perform a read call until the buffer is filled or */
3071 /* we encounter EOF. */
3072 ssize_t GC_repeat_read(int fd, char *buf, size_t count)
3074 ssize_t num_read = 0;
3075 ssize_t result;
3077 while (num_read < count) {
3078 result = READ(fd, buf + num_read, count - num_read);
3079 if (result < 0) return result;
3080 if (result == 0) break;
3081 num_read += result;
3083 return num_read;
3085 #endif /* LINUX && ... */
3088 #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
3090 /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
3091 addresses in FIND_LEAK output. */
3093 void GC_print_address_map()
3095 int f;
3096 int result;
3097 char maps_temp[32768];
3098 GC_err_printf0("---------- Begin address map ----------\n");
3099 f = open("/proc/self/maps", O_RDONLY);
3100 if (-1 == f) ABORT("Couldn't open /proc/self/maps");
3101 do {
3102 result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
3103 if (result <= 0) ABORT("Couldn't read /proc/self/maps");
3104 GC_err_write(maps_temp, result);
3105 } while (result == sizeof(maps_temp));
3107 GC_err_printf0("---------- End address map ----------\n");
3110 #endif