[BACK]Return to os_dep.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Diff for /OpenXM_contrib2/asir2000/gc/os_dep.c between version 1.3 and 1.6

version 1.3, 2000/12/01 09:26:12 version 1.6, 2002/07/24 08:00:11
Line 1 
Line 1 
 int ox_usr1_sent, ox_int_received, critical_when_signal;  
 static int inside_critical_section;  
   
 /*  /*
  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers   * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.   * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
Line 17  static int inside_critical_section;
Line 14  static int inside_critical_section;
  * modified is included with the above copyright notice.   * modified is included with the above copyright notice.
  */   */
   
 # include "gc_priv.h"  # include "private/gc_priv.h"
   
 # if defined(LINUX) && !defined(POWERPC)  # if defined(LINUX) && !defined(POWERPC)
 #   include <linux/version.h>  #   include <linux/version.h>
Line 48  static int inside_critical_section;
Line 45  static int inside_critical_section;
 #     endif /* 2 <= __GLIBC__ */  #     endif /* 2 <= __GLIBC__ */
 #   endif  #   endif
 # endif  # endif
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)  # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS) \
       && !defined(MSWINCE)
 #   include <sys/types.h>  #   include <sys/types.h>
 #   if !defined(MSWIN32) && !defined(SUNOS4)  #   if !defined(MSWIN32) && !defined(SUNOS4)
 #       include <unistd.h>  #       include <unistd.h>
Line 56  static int inside_critical_section;
Line 54  static int inside_critical_section;
 # endif  # endif
   
 # include <stdio.h>  # include <stdio.h>
 # include <signal.h>  # if defined(MSWINCE)
   #   define SIGSEGV 0 /* value is irrelevant */
   # else
   #   include <signal.h>
   # endif
   
 /* Blatantly OS dependent routines, except for those that are related   */  /* Blatantly OS dependent routines, except for those that are related   */
 /* to dynamic loading.                                                  */  /* to dynamic loading.                                                  */
   
 # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)  # if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if defined(IRIX_THREADS) || defined(HPUX_THREADS)  # if !defined(STACKBOTTOM) && defined(HEURISTIC2)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
Line 73  static int inside_critical_section;
Line 75  static int inside_critical_section;
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)  # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
         || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if defined(LINUX) && \  
      (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64) \  
       || defined(MIPS))  
 #   define NEED_FIND_LIMIT  
 # endif  
   
 #ifdef NEED_FIND_LIMIT  #ifdef NEED_FIND_LIMIT
 #   include <setjmp.h>  #   include <setjmp.h>
 #endif  #endif
   
 #ifdef FREEBSD  #if defined(FREEBSD) && defined(I386)
 #  include <machine/trap.h>  #  include <machine/trap.h>
 #endif  #endif
   
 #ifdef AMIGA  #ifdef AMIGA
 # include <proto/exec.h>  # define GC_AMIGA_DEF
 # include <proto/dos.h>  # include "AmigaOS.c"
 # include <dos/dosextens.h>  # undef GC_AMIGA_DEF
 # include <workbench/startup.h>  
 #endif  #endif
   
 #ifdef MSWIN32  #if defined(MSWIN32) || defined(MSWINCE)
 # define WIN32_LEAN_AND_MEAN  # define WIN32_LEAN_AND_MEAN
 # define NOSERVICE  # define NOSERVICE
 # include <windows.h>  # include <windows.h>
Line 116  static int inside_critical_section;
Line 112  static int inside_critical_section;
 # include <sys/types.h>  # include <sys/types.h>
 # include <sys/mman.h>  # include <sys/mman.h>
 # include <sys/stat.h>  # include <sys/stat.h>
   #endif
   
   #ifdef UNIX_LIKE
 # include <fcntl.h>  # include <fcntl.h>
 #endif  #endif
   
 #ifdef SUNOS5SIGS  #if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX)
 # include <sys/siginfo.h>  # ifdef SUNOS5SIGS
   #  include <sys/siginfo.h>
   # endif
 # undef setjmp  # undef setjmp
 # undef longjmp  # undef longjmp
 # define setjmp(env) sigsetjmp(env, 1)  # define setjmp(env) sigsetjmp(env, 1)
Line 129  static int inside_critical_section;
Line 130  static int inside_critical_section;
 #endif  #endif
   
 #ifdef DJGPP  #ifdef DJGPP
   /* Apparently necessary for djgpp 2.01.  May casuse problems with     */    /* Apparently necessary for djgpp 2.01.  May cause problems with      */
   /* other versions.                                                    */    /* other versions.                                                    */
   typedef long unsigned int caddr_t;    typedef long unsigned int caddr_t;
 #endif  #endif
Line 147  static int inside_critical_section;
Line 148  static int inside_critical_section;
 #endif  #endif
   
 #if defined(SEARCH_FOR_DATA_START)  #if defined(SEARCH_FOR_DATA_START)
   /* The following doesn't work if the GC is in a dynamic library.      */  
   /* The I386 case can be handled without a search.  The Alpha case     */    /* The I386 case can be handled without a search.  The Alpha case     */
   /* used to be handled differently as well, but the rules changed      */    /* used to be handled differently as well, but the rules changed      */
   /* for recent Linux versions.  This seems to be the easiest way to    */    /* for recent Linux versions.  This seems to be the easiest way to    */
   /* cover all versions.                                                */    /* cover all versions.                                                */
   ptr_t GC_data_start;  
   
   extern char * GC_copyright[];  /* Any data symbol would do. */  # ifdef LINUX
   #   pragma weak __data_start
       extern int __data_start[];
   #   pragma weak data_start
       extern int data_start[];
   # endif /* LINUX */
     extern int _end[];
   
     ptr_t GC_data_start;
   
   void GC_init_linux_data_start()    void GC_init_linux_data_start()
   {    {
     extern ptr_t GC_find_limit();      extern ptr_t GC_find_limit();
   
     GC_data_start = GC_find_limit((ptr_t)GC_copyright, FALSE);  #   ifdef LINUX
         /* Try the easy approaches first: */
         if ((ptr_t)__data_start != 0) {
             GC_data_start = (ptr_t)(__data_start);
             return;
         }
         if ((ptr_t)data_start != 0) {
             GC_data_start = (ptr_t)(data_start);
             return;
         }
   #   endif /* LINUX */
       GC_data_start = GC_find_limit((ptr_t)(_end), FALSE);
   }    }
 #endif  #endif
   
   # ifdef ECOS
   
   # ifndef ECOS_GC_MEMORY_SIZE
   # define ECOS_GC_MEMORY_SIZE (448 * 1024)
   # endif /* ECOS_GC_MEMORY_SIZE */
   
   // setjmp() function, as described in ANSI para 7.6.1.1
   #define setjmp( __env__ )  hal_setjmp( __env__ )
   
   // FIXME: This is a simple way of allocating memory which is
   // compatible with ECOS early releases.  Later releases use a more
   // sophisticated means of allocating memory than this simple static
   // allocator, but this method is at least bound to work.
   static char memory[ECOS_GC_MEMORY_SIZE];
   static char *brk = memory;
   
   static void *tiny_sbrk(ptrdiff_t increment)
   {
     void *p = brk;
   
     brk += increment;
   
     if (brk >  memory + sizeof memory)
       {
         brk -= increment;
         return NULL;
       }
   
     return p;
   }
   #define sbrk tiny_sbrk
   # endif /* ECOS */
   
   #if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
     ptr_t GC_data_start;
   
     void GC_init_netbsd_elf()
     {
       extern ptr_t GC_find_limit();
       extern char **environ;
           /* This may need to be environ, without the underscore, for     */
           /* some versions.                                               */
       GC_data_start = GC_find_limit((ptr_t)&environ, FALSE);
     }
   #endif
   
 # ifdef OS2  # ifdef OS2
   
 # include <stddef.h>  # include <stddef.h>
Line 268  void GC_enable_signals(void)
Line 332  void GC_enable_signals(void)
 # else  # else
   
 #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \  #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
       && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)        && !defined(MSWINCE) \
         && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW) \
         && !defined(NOSYS) && !defined(ECOS)
   
 #   if defined(sigmask) && !defined(UTS4)  #   if defined(sigmask) && !defined(UTS4) && !defined(HURD)
         /* Use the traditional BSD interface */          /* Use the traditional BSD interface */
 #       define SIGSET_T int  #       define SIGSET_T int
 #       define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))  #       define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
Line 327  void GC_disable_signals()
Line 393  void GC_disable_signals()
         GC_sig_disabled++;          GC_sig_disabled++;
 #   endif  #   endif
     SIGSETMASK(old_mask,new_mask);      SIGSETMASK(old_mask,new_mask);
         if ( critical_when_signal )  
                 inside_critical_section = 1;  
         else {  
                 inside_critical_section = 0;  
                 critical_when_signal = 1;  
         }  
 }  }
   
 void GC_enable_signals()  void GC_enable_signals()
Line 342  void GC_enable_signals()
Line 402  void GC_enable_signals()
         GC_sig_disabled--;          GC_sig_disabled--;
 #   endif  #   endif
     SIGSETMASK(dummy,old_mask);      SIGSETMASK(dummy,old_mask);
         if ( !inside_critical_section ) {  
                 critical_when_signal = 0;  
                 if ( ox_usr1_sent ) {  
                         ox_usr1_sent = 0; ox_usr1_handler();  
                 }  
                 if ( ox_int_received ) {  
                         ox_int_received = 0; int_handler();  
                 }  
         } else  
                 inside_critical_section = 0;  
 }  }
   
 #  endif  /* !PCR */  #  endif  /* !PCR */
Line 359  void GC_enable_signals()
Line 409  void GC_enable_signals()
 # endif /*!OS/2 */  # endif /*!OS/2 */
   
 /* Ivan Demakov: simplest way (to me) */  /* Ivan Demakov: simplest way (to me) */
 #ifdef DOS4GW  #if defined (DOS4GW)
   void GC_disable_signals() { }    void GC_disable_signals() { }
   void GC_enable_signals() { }    void GC_enable_signals() { }
 #endif  #endif
Line 367  void GC_enable_signals()
Line 417  void GC_enable_signals()
 /* Find the page size */  /* Find the page size */
 word GC_page_size;  word GC_page_size;
   
 # ifdef MSWIN32  # if defined(MSWIN32) || defined(MSWINCE)
   void GC_setpagesize()    void GC_setpagesize()
   {    {
     SYSTEM_INFO sysinfo;      GetSystemInfo(&GC_sysinfo);
       GC_page_size = GC_sysinfo.dwPageSize;
     GetSystemInfo(&sysinfo);  
     GC_page_size = sysinfo.dwPageSize;  
   }    }
   
 # else  # else
Line 398  word GC_page_size;
Line 446  word GC_page_size;
  * With threads, GC_mark_roots needs to know how to do this.   * With threads, GC_mark_roots needs to know how to do this.
  * Called with allocator lock held.   * Called with allocator lock held.
  */   */
 # ifdef MSWIN32  # if defined(MSWIN32) || defined(MSWINCE)
 # define is_writable(prot) ((prot) == PAGE_READWRITE \  # define is_writable(prot) ((prot) == PAGE_READWRITE \
                             || (prot) == PAGE_WRITECOPY \                              || (prot) == PAGE_WRITECOPY \
                             || (prot) == PAGE_EXECUTE_READWRITE \                              || (prot) == PAGE_EXECUTE_READWRITE \
Line 435  ptr_t GC_get_stack_base()
Line 483  ptr_t GC_get_stack_base()
 }  }
   
   
 # else  # endif /* MS Windows */
   
   # ifdef BEOS
   # include <kernel/OS.h>
   ptr_t GC_get_stack_base(){
           thread_info th;
           get_thread_info(find_thread(NULL),&th);
           return th.stack_end;
   }
   # endif /* BEOS */
   
   
 # ifdef OS2  # ifdef OS2
   
 ptr_t GC_get_stack_base()  ptr_t GC_get_stack_base()
Line 451  ptr_t GC_get_stack_base()
Line 509  ptr_t GC_get_stack_base()
     return((ptr_t)(ptib -> tib_pstacklimit));      return((ptr_t)(ptib -> tib_pstacklimit));
 }  }
   
 # else  # endif /* OS2 */
   
 # ifdef AMIGA  # ifdef AMIGA
   #   define GC_AMIGA_SB
   #   include "AmigaOS.c"
   #   undef GC_AMIGA_SB
   # endif /* AMIGA */
   
 ptr_t GC_get_stack_base()  # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
 {  
     struct Process *proc = (struct Process*)SysBase->ThisTask;  
   
     /* Reference: Amiga Guru Book Pages: 42,567,574 */  
     if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS  
         && proc->pr_CLI != NULL) {  
         /* first ULONG is StackSize */  
         /*longPtr = proc->pr_ReturnAddr;  
         size = longPtr[0];*/  
   
         return (char *)proc->pr_ReturnAddr + sizeof(ULONG);  
     } else {  
         return (char *)proc->pr_Task.tc_SPUpper;  
     }  
 }  
   
 #if 0 /* old version */  
 ptr_t GC_get_stack_base()  
 {  
     extern struct WBStartup *_WBenchMsg;  
     extern long __base;  
     extern long __stack;  
     struct Task *task;  
     struct Process *proc;  
     struct CommandLineInterface *cli;  
     long size;  
   
     if ((task = FindTask(0)) == 0) {  
         GC_err_puts("Cannot find own task structure\n");  
         ABORT("task missing");  
     }  
     proc = (struct Process *)task;  
     cli = BADDR(proc->pr_CLI);  
   
     if (_WBenchMsg != 0 || cli == 0) {  
         size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;  
     } else {  
         size = cli->cli_DefaultStack * 4;  
     }  
     return (ptr_t)(__base + GC_max(size, __stack));  
 }  
 #endif /* 0 */  
   
 # else /* !AMIGA, !OS2, ... */  
   
 # ifdef NEED_FIND_LIMIT  
   /* Some tools to implement HEURISTIC2 */  
 #   define MIN_PAGE_SIZE 256    /* Smallest conceivable page size, bytes */  
     /* static */ jmp_buf GC_jmp_buf;  
   
     /*ARGSUSED*/  
     void GC_fault_handler(sig)  
     int sig;  
     {  
         longjmp(GC_jmp_buf, 1);  
     }  
   
 #   ifdef __STDC__  #   ifdef __STDC__
         typedef void (*handler)(int);          typedef void (*handler)(int);
 #   else  #   else
         typedef void (*handler)();          typedef void (*handler)();
 #   endif  #   endif
   
 #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) || defined(HURD)
         static struct sigaction old_segv_act;          static struct sigaction old_segv_act;
 #       if defined(_sigargs) || defined(HPUX) /* !Irix6.x */  #       if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) || defined(HURD)
             static struct sigaction old_bus_act;              static struct sigaction old_bus_act;
 #       endif  #       endif
 #   else  #   else
         static handler old_segv_handler, old_bus_handler;          static handler old_segv_handler, old_bus_handler;
 #   endif  #   endif
   
     void GC_setup_temporary_fault_handler()  #   ifdef __STDC__
         void GC_set_and_save_fault_handler(handler h)
   #   else
         void GC_set_and_save_fault_handler(h)
         handler h;
   #   endif
     {      {
 #       if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)  #       if defined(SUNOS5SIGS) || defined(IRIX5)  \
           || defined(OSF1) || defined(HURD)
           struct sigaction      act;            struct sigaction      act;
   
           act.sa_handler        = GC_fault_handler;            act.sa_handler        = h;
           act.sa_flags          = SA_RESTART | SA_NODEFER;  #         ifdef SUNOS5SIGS
               act.sa_flags          = SA_RESTART | SA_NODEFER;
   #         else
               act.sa_flags          = SA_RESTART;
   #         endif
           /* The presence of SA_NODEFER represents yet another gross    */            /* The presence of SA_NODEFER represents yet another gross    */
           /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */            /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */
           /* interact correctly with -lthread.  We hide the confusion   */            /* interact correctly with -lthread.  We hide the confusion   */
Line 542  ptr_t GC_get_stack_base()
Line 558  ptr_t GC_get_stack_base()
           /* signal mask.                                               */            /* signal mask.                                               */
   
           (void) sigemptyset(&act.sa_mask);            (void) sigemptyset(&act.sa_mask);
 #         ifdef IRIX_THREADS  #         ifdef GC_IRIX_THREADS
                 /* Older versions have a bug related to retrieving and  */                  /* Older versions have a bug related to retrieving and  */
                 /* and setting a handler at the same time.              */                  /* and setting a handler at the same time.              */
                 (void) sigaction(SIGSEGV, 0, &old_segv_act);                  (void) sigaction(SIGSEGV, 0, &old_segv_act);
Line 550  ptr_t GC_get_stack_base()
Line 566  ptr_t GC_get_stack_base()
 #         else  #         else
                 (void) sigaction(SIGSEGV, &act, &old_segv_act);                  (void) sigaction(SIGSEGV, &act, &old_segv_act);
 #               if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \  #               if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
                    || defined(HPUX)                     || defined(HPUX) || defined(HURD)
                     /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */                      /* Under Irix 5.x or HP/UX, we may get SIGBUS.      */
                     /* Pthreads doesn't exist under Irix 5.x, so we     */                      /* Pthreads doesn't exist under Irix 5.x, so we     */
                     /* don't have to worry in the threads case.         */                      /* don't have to worry in the threads case.         */
                     (void) sigaction(SIGBUS, &act, &old_bus_act);                      (void) sigaction(SIGBUS, &act, &old_bus_act);
 #               endif  #               endif
 #         endif /* IRIX_THREADS */  #         endif /* GC_IRIX_THREADS */
 #       else  #       else
           old_segv_handler = signal(SIGSEGV, GC_fault_handler);            old_segv_handler = signal(SIGSEGV, h);
 #         ifdef SIGBUS  #         ifdef SIGBUS
             old_bus_handler = signal(SIGBUS, GC_fault_handler);              old_bus_handler = signal(SIGBUS, h);
 #         endif  #         endif
 #       endif  #       endif
     }      }
   # endif /* NEED_FIND_LIMIT || UNIX_LIKE */
   
   # ifdef NEED_FIND_LIMIT
     /* Some tools to implement HEURISTIC2 */
   #   define MIN_PAGE_SIZE 256    /* Smallest conceivable page size, bytes */
       /* static */ jmp_buf GC_jmp_buf;
   
       /*ARGSUSED*/
       void GC_fault_handler(sig)
       int sig;
       {
           longjmp(GC_jmp_buf, 1);
       }
   
       void GC_setup_temporary_fault_handler()
       {
           GC_set_and_save_fault_handler(GC_fault_handler);
       }
   
     void GC_reset_fault_handler()      void GC_reset_fault_handler()
     {      {
 #       if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)  #       if defined(SUNOS5SIGS) || defined(IRIX5) \
              || defined(OSF1) || defined(HURD)
           (void) sigaction(SIGSEGV, &old_segv_act, 0);            (void) sigaction(SIGSEGV, &old_segv_act, 0);
 #         if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \  #         if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
              || defined(HPUX)               || defined(HPUX) || defined(HURD)
               (void) sigaction(SIGBUS, &old_bus_act, 0);                (void) sigaction(SIGBUS, &old_bus_act, 0);
 #         endif  #         endif
 #       else  #       else
Line 615  ptr_t GC_get_stack_base()
Line 650  ptr_t GC_get_stack_base()
     }      }
 # endif  # endif
   
   #if defined(ECOS) || defined(NOSYS)
     ptr_t GC_get_stack_base()
     {
       return STACKBOTTOM;
     }
   #endif
   
 #ifdef LINUX_STACKBOTTOM  #ifdef LINUX_STACKBOTTOM
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <fcntl.h>  
   
 # define STAT_SKIP 27   /* Number of fields preceding startstack        */  # define STAT_SKIP 27   /* Number of fields preceding startstack        */
                         /* field in /proc/self/stat                     */                          /* field in /proc/self/stat                     */
   
   # pragma weak __libc_stack_end
     extern ptr_t __libc_stack_end;
   
   # ifdef IA64
   #   pragma weak __libc_ia64_register_backing_store_base
       extern ptr_t __libc_ia64_register_backing_store_base;
   
       ptr_t GC_get_register_stack_base(void)
       {
         if (0 != &__libc_ia64_register_backing_store_base
             && 0 != __libc_ia64_register_backing_store_base) {
           /* Glibc 2.2.4 has a bug such that for dynamically linked       */
           /* executables __libc_ia64_register_backing_store_base is       */
           /* defined but ininitialized during constructor calls.          */
           /* Hence we check for both nonzero address and value.           */
           return __libc_ia64_register_backing_store_base;
         } else {
           word result = (word)GC_stackbottom - BACKING_STORE_DISPLACEMENT;
           result += BACKING_STORE_ALIGNMENT - 1;
           result &= ~(BACKING_STORE_ALIGNMENT - 1);
           return (ptr_t)result;
         }
       }
   # endif
   
   ptr_t GC_linux_stack_base(void)    ptr_t GC_linux_stack_base(void)
   {    {
     /* We read the stack base value from /proc/self/stat.  We do this   */      /* We read the stack base value from /proc/self/stat.  We do this   */
     /* using direct I/O system calls in order to avoid calling malloc   */      /* using direct I/O system calls in order to avoid calling malloc   */
     /* in case REDIRECT_MALLOC is defined.                              */      /* in case REDIRECT_MALLOC is defined.                              */
 #   define STAT_BUF_SIZE 4096  #   define STAT_BUF_SIZE 4096
 #   ifdef USE_LD_WRAP  #   if defined(GC_USE_LD_WRAP)
 #       define STAT_READ __real_read  #       define STAT_READ __real_read
 #   else  #   else
 #       define STAT_READ read  #       define STAT_READ read
Line 641  ptr_t GC_get_stack_base()
Line 707  ptr_t GC_get_stack_base()
     word result = 0;      word result = 0;
     size_t i, buf_offset = 0;      size_t i, buf_offset = 0;
   
       /* First try the easy way.  This should work for glibc 2.2  */
         if (0 != &__libc_stack_end) {
   #       ifdef IA64
             /* Some versions of glibc set the address 16 bytes too        */
             /* low while the initialization code is running.              */
             if (((word)__libc_stack_end & 0xfff) + 0x10 < 0x1000) {
               return __libc_stack_end + 0x10;
             } /* Otherwise it's not safe to add 16 bytes and we fall      */
               /* back to using /proc.                                     */
   #       else
             return __libc_stack_end;
   #       endif
         }
     f = open("/proc/self/stat", O_RDONLY);      f = open("/proc/self/stat", O_RDONLY);
     if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {      if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
         ABORT("Couldn't read /proc/self/stat");          ABORT("Couldn't read /proc/self/stat");
Line 665  ptr_t GC_get_stack_base()
Line 744  ptr_t GC_get_stack_base()
   
 #endif /* LINUX_STACKBOTTOM */  #endif /* LINUX_STACKBOTTOM */
   
   #ifdef FREEBSD_STACKBOTTOM
   
   /* This uses an undocumented sysctl call, but at least one expert       */
   /* believes it will stay.                                               */
   
   #include <unistd.h>
   #include <sys/types.h>
   #include <sys/sysctl.h>
   
     ptr_t GC_freebsd_stack_base(void)
     {
       int nm[2] = {CTL_KERN, KERN_USRSTACK};
       ptr_t base;
       size_t len = sizeof(ptr_t);
       int r = sysctl(nm, 2, &base, &len, NULL, 0);
   
       if (r) ABORT("Error getting stack base");
   
       return base;
     }
   
   #endif /* FREEBSD_STACKBOTTOM */
   
   #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
       && !defined(MSWINCE) && !defined(OS2)
   
 ptr_t GC_get_stack_base()  ptr_t GC_get_stack_base()
 {  {
     word dummy;      word dummy;
Line 688  ptr_t GC_get_stack_base()
Line 793  ptr_t GC_get_stack_base()
 #       ifdef LINUX_STACKBOTTOM  #       ifdef LINUX_STACKBOTTOM
            result = GC_linux_stack_base();             result = GC_linux_stack_base();
 #       endif  #       endif
   #       ifdef FREEBSD_STACKBOTTOM
              result = GC_freebsd_stack_base();
   #       endif
 #       ifdef HEURISTIC2  #       ifdef HEURISTIC2
 #           ifdef STACK_GROWS_DOWN  #           ifdef STACK_GROWS_DOWN
                 result = GC_find_limit((ptr_t)(&dummy), TRUE);                  result = GC_find_limit((ptr_t)(&dummy), TRUE);
Line 715  ptr_t GC_get_stack_base()
Line 823  ptr_t GC_get_stack_base()
 #   endif /* STACKBOTTOM */  #   endif /* STACKBOTTOM */
 }  }
   
 # endif /* ! AMIGA */  # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS */
 # endif /* ! OS2 */  
 # endif /* ! MSWIN32 */  
   
 /*  /*
  * Register static data segment(s) as roots.   * Register static data segment(s) as roots.
Line 817  void GC_register_data_segments()
Line 923  void GC_register_data_segments()
     }      }
 }  }
   
 # else  # else /* !OS2 */
   
   # if defined(MSWIN32) || defined(MSWINCE)
   
 # ifdef MSWIN32  # ifdef MSWIN32
   /* Unfortunately, we have to handle win32s very differently from NT,  */    /* Unfortunately, we have to handle win32s very differently from NT,  */
   /* Since VirtualQuery has very different semantics.  In particular,   */    /* Since VirtualQuery has very different semantics.  In particular,   */
   /* under win32s a VirtualQuery call on an unmapped page returns an    */    /* under win32s a VirtualQuery call on an unmapped page returns an    */
   /* invalid result.  Under GC_register_data_segments is a noop and     */    /* invalid result.  Under NT, GC_register_data_segments is a noop and */
   /* all real work is done by GC_register_dynamic_libraries.  Under     */    /* all real work is done by GC_register_dynamic_libraries.  Under     */
   /* win32s, we cannot find the data segments associated with dll's.    */    /* win32s, we cannot find the data segments associated with dll's.    */
   /* We rgister the main data segment here.                             */    /* We rgister the main data segment here.                             */
   GC_bool GC_win32s = FALSE;    /* We're running under win32s.  */  #  ifdef __GCC__
     GC_bool GC_no_win32_dlls = TRUE;       /* GCC can't do SEH, so we can't use VirtualQuery */
   #  else
     GC_bool GC_no_win32_dlls = FALSE;
   #  endif
   
   GC_bool GC_is_win32s()  
   {  
       DWORD v = GetVersion();  
   
       /* Check that this is not NT, and Windows major version <= 3      */  
       return ((v & 0x80000000) && (v & 0xff) <= 3);  
   }  
   
   void GC_init_win32()    void GC_init_win32()
   {    {
       GC_win32s = GC_is_win32s();      /* if we're running under win32s, assume that no DLLs will be loaded */
       DWORD v = GetVersion();
       GC_no_win32_dlls |= ((v & 0x80000000) && (v & 0xff) <= 3);
   }    }
   
   /* Return the smallest address a such that VirtualQuery               */    /* Return the smallest address a such that VirtualQuery               */
   /* returns correct results for all addresses between a and start.     */    /* returns correct results for all addresses between a and start.     */
   /* Assumes VirtualQuery returns correct information for start.        */    /* Assumes VirtualQuery returns correct information for start.        */
   ptr_t GC_least_described_address(ptr_t start)    ptr_t GC_least_described_address(ptr_t start)
   {    {
     MEMORY_BASIC_INFORMATION buf;      MEMORY_BASIC_INFORMATION buf;
     SYSTEM_INFO sysinfo;  
     DWORD result;      DWORD result;
     LPVOID limit;      LPVOID limit;
     ptr_t p;      ptr_t p;
     LPVOID q;      LPVOID q;
   
     GetSystemInfo(&sysinfo);      limit = GC_sysinfo.lpMinimumApplicationAddress;
     limit = sysinfo.lpMinimumApplicationAddress;  
     p = (ptr_t)((word)start & ~(GC_page_size - 1));      p = (ptr_t)((word)start & ~(GC_page_size - 1));
     for (;;) {      for (;;) {
         q = (LPVOID)(p - GC_page_size);          q = (LPVOID)(p - GC_page_size);
Line 866  void GC_register_data_segments()
Line 970  void GC_register_data_segments()
     }      }
     return(p);      return(p);
   }    }
   # endif
   
   /* Is p the start of either the malloc heap, or of one of our */    /* Is p the start of either the malloc heap, or of one of our */
   /* heap sections?                                             */    /* heap sections?                                             */
Line 879  void GC_register_data_segments()
Line 984  void GC_register_data_segments()
   
        if (0 == malloc_heap_pointer) {         if (0 == malloc_heap_pointer) {
          MEMORY_BASIC_INFORMATION buf;           MEMORY_BASIC_INFORMATION buf;
          register DWORD result = VirtualQuery(malloc(1), &buf, sizeof(buf));           void *pTemp = malloc( 1 );
            register DWORD result = VirtualQuery(pTemp, &buf, sizeof(buf));
   
            free( pTemp );
   
   
          if (result != sizeof(buf)) {           if (result != sizeof(buf)) {
              ABORT("Weird VirtualQuery result");               ABORT("Weird VirtualQuery result");
Line 893  void GC_register_data_segments()
Line 1002  void GC_register_data_segments()
      }       }
      return(FALSE);       return(FALSE);
   }    }
   
   # ifdef MSWIN32
   void GC_register_root_section(ptr_t static_root)    void GC_register_root_section(ptr_t static_root)
   {    {
       MEMORY_BASIC_INFORMATION buf;        MEMORY_BASIC_INFORMATION buf;
       SYSTEM_INFO sysinfo;  
       DWORD result;        DWORD result;
       DWORD protect;        DWORD protect;
       LPVOID p;        LPVOID p;
       char * base;        char * base;
       char * limit, * new_limit;        char * limit, * new_limit;
   
       if (!GC_win32s) return;        if (!GC_no_win32_dlls) return;
       p = base = limit = GC_least_described_address(static_root);        p = base = limit = GC_least_described_address(static_root);
       GetSystemInfo(&sysinfo);        while (p < GC_sysinfo.lpMaximumApplicationAddress) {
       while (p < sysinfo.lpMaximumApplicationAddress) {  
         result = VirtualQuery(p, &buf, sizeof(buf));          result = VirtualQuery(p, &buf, sizeof(buf));
         if (result != sizeof(buf) || buf.AllocationBase == 0          if (result != sizeof(buf) || buf.AllocationBase == 0
             || GC_is_heap_base(buf.AllocationBase)) break;              || GC_is_heap_base(buf.AllocationBase)) break;
Line 928  void GC_register_data_segments()
Line 1036  void GC_register_data_segments()
       }        }
       if (base != limit) GC_add_roots_inner(base, limit, FALSE);        if (base != limit) GC_add_roots_inner(base, limit, FALSE);
   }    }
   #endif
   
   void GC_register_data_segments()    void GC_register_data_segments()
   {    {
   #     ifdef MSWIN32
       static char dummy;        static char dummy;
   
       GC_register_root_section((ptr_t)(&dummy));        GC_register_root_section((ptr_t)(&dummy));
   }  
 # else  
 # ifdef AMIGA  
   
    void GC_register_data_segments()  
    {  
      struct Process     *proc;  
      struct CommandLineInterface *cli;  
      BPTR myseglist;  
      ULONG *data;  
   
      int        num;  
   
   
 #    ifdef __GNUC__  
         ULONG dataSegSize;  
         GC_bool found_segment = FALSE;  
         extern char __data_size[];  
   
         dataSegSize=__data_size+8;  
         /* Can`t find the Location of __data_size, because  
            it`s possible that is it, inside the segment. */  
   
 #     endif  #     endif
   
         proc= (struct Process*)SysBase->ThisTask;  
   
         /* Reference: Amiga Guru Book Pages: 538ff,565,573  
                      and XOper.asm */  
         if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {  
           if (proc->pr_CLI == NULL) {  
             myseglist = proc->pr_SegList;  
           } else {  
             /* ProcLoaded       'Loaded as a command: '*/  
             cli = BADDR(proc->pr_CLI);  
             myseglist = cli->cli_Module;  
           }  
         } else {  
           ABORT("Not a Process.");  
         }  
   
         if (myseglist == NULL) {  
             ABORT("Arrrgh.. can't find segments, aborting");  
         }  
   
         /* xoper hunks Shell Process */  
   
         num=0;  
         for (data = (ULONG *)BADDR(myseglist); data != NULL;  
              data = (ULONG *)BADDR(data[0])) {  
           if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||  
               ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {  
 #             ifdef __GNUC__  
                 if (dataSegSize == data[-1]) {  
                   found_segment = TRUE;  
                 }  
 #             endif  
               GC_add_roots_inner((char *)&data[1],  
                                  ((char *)&data[1]) + data[-1], FALSE);  
           }  
           ++num;  
         } /* for */  
 #       ifdef __GNUC__  
            if (!found_segment) {  
              ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");  
            }  
 #       endif  
   }    }
   
 #if 0 /* old version */  # else /* !OS2 && !Windows */
   void GC_register_data_segments()  
   {  
     extern struct WBStartup *_WBenchMsg;  
     struct Process      *proc;  
     struct CommandLineInterface *cli;  
     BPTR myseglist;  
     ULONG *data;  
   
     if ( _WBenchMsg != 0 ) {  # if (defined(SVR4) || defined(AUX) || defined(DGUX) \
         if ((myseglist = _WBenchMsg->sm_Segment) == 0) {        || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
             GC_err_puts("No seglist from workbench\n");  
             return;  
         }  
     } else {  
         if ((proc = (struct Process *)FindTask(0)) == 0) {  
             GC_err_puts("Cannot find process structure\n");  
             return;  
         }  
         if ((cli = BADDR(proc->pr_CLI)) == 0) {  
             GC_err_puts("No CLI\n");  
             return;  
         }  
         if ((myseglist = cli->cli_Module) == 0) {  
             GC_err_puts("No seglist from CLI\n");  
             return;  
         }  
     }  
   
     for (data = (ULONG *)BADDR(myseglist); data != 0;  
          data = (ULONG *)BADDR(data[0])) {  
 #        ifdef AMIGA_SKIP_SEG  
            if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||  
            ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {  
 #        else  
            {  
 #        endif /* AMIGA_SKIP_SEG */  
           GC_add_roots_inner((char *)&data[1],  
                              ((char *)&data[1]) + data[-1], FALSE);  
          }  
     }  
   }  
 #endif /* old version */  
   
   
 # else  
   
 # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)  
 char * GC_SysVGetDataStart(max_page_size, etext_addr)  char * GC_SysVGetDataStart(max_page_size, etext_addr)
 int max_page_size;  int max_page_size;
 int * etext_addr;  int * etext_addr;
Line 1084  int * etext_addr;
Line 1083  int * etext_addr;
 # endif  # endif
   
   
   #ifdef AMIGA
   
   #  define GC_AMIGA_DS
   #  include "AmigaOS.c"
   #  undef GC_AMIGA_DS
   
   #else /* !OS2 && !Windows && !AMIGA */
   
 void GC_register_data_segments()  void GC_register_data_segments()
 {  {
 #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \  #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS) \
        && !defined(MACOSX)         && !defined(MACOSX)
 #     if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS)  #     if defined(REDIRECT_MALLOC) && defined(GC_SOLARIS_THREADS)
         /* As of Solaris 2.3, the Solaris threads implementation        */          /* As of Solaris 2.3, the Solaris threads implementation        */
         /* allocates the data structure for the initial thread with     */          /* allocates the data structure for the initial thread with     */
         /* sbrk at process startup.  It needs to be scanned, so that    */          /* sbrk at process startup.  It needs to be scanned, so that    */
Line 1099  void GC_register_data_segments()
Line 1106  void GC_register_data_segments()
         GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);          GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
 #     else  #     else
         GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);          GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
   #       if defined(DATASTART2)
            GC_add_roots_inner(DATASTART2, (char *)(DATAEND2), FALSE);
   #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   if !defined(PCR) && (defined(NEXT) || defined(MACOSX))  #   if !defined(PCR) && (defined(NEXT) || defined(MACOSX))
Line 1143  void GC_register_data_segments()
Line 1153  void GC_register_data_segments()
 }  }
   
 # endif  /* ! AMIGA */  # endif  /* ! AMIGA */
 # endif  /* ! MSWIN32 */  # endif  /* ! MSWIN32 && ! MSWINCE*/
 # endif  /* ! OS2 */  # endif  /* ! OS2 */
   
 /*  /*
  * Auxiliary routines for obtaining memory from OS.   * Auxiliary routines for obtaining memory from OS.
  */   */
   
 # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \  # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
         && !defined(MSWIN32) && !defined(MACOS) && !defined(DOS4GW)          && !defined(MSWIN32) && !defined(MSWINCE) \
           && !defined(MACOS) && !defined(DOS4GW)
   
 # ifdef SUNOS4  # ifdef SUNOS4
     extern caddr_t sbrk();      extern caddr_t sbrk();
Line 1162  void GC_register_data_segments()
Line 1173  void GC_register_data_segments()
 #   define SBRK_ARG_T int  #   define SBRK_ARG_T int
 # endif  # endif
   
   
 # ifdef RS6000  # ifdef RS6000
 /* The compiler seems to generate speculative reads one past the end of */  /* The compiler seems to generate speculative reads one past the end of */
 /* an allocated object.  Hence we need to make sure that the page       */  /* an allocated object.  Hence we need to make sure that the page       */
Line 1194  word bytes;
Line 1206  word bytes;
 #else  /* Not RS6000 */  #else  /* Not RS6000 */
   
 #if defined(USE_MMAP)  #if defined(USE_MMAP)
 /* Tested only under IRIX5 and Solaris 2 */  /* Tested only under Linux, IRIX5 and Solaris 2 */
   
 #ifdef USE_MMAP_FIXED  #ifdef USE_MMAP_FIXED
 #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE  #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
Line 1204  word bytes;
Line 1216  word bytes;
 #   define GC_MMAP_FLAGS MAP_PRIVATE  #   define GC_MMAP_FLAGS MAP_PRIVATE
 #endif  #endif
   
   #ifndef HEAP_START
   #   define HEAP_START 0
   #endif
   
 ptr_t GC_unix_get_mem(bytes)  ptr_t GC_unix_get_mem(bytes)
 word bytes;  word bytes;
 {  {
Line 1222  word bytes;
Line 1238  word bytes;
     if (result == MAP_FAILED) return(0);      if (result == MAP_FAILED) return(0);
     last_addr = (ptr_t)result + bytes + GC_page_size - 1;      last_addr = (ptr_t)result + bytes + GC_page_size - 1;
     last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));      last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
   #   if !defined(LINUX)
         if (last_addr == 0) {
           /* Oops.  We got the end of the address space.  This isn't      */
           /* usable by arbitrary C code, since one-past-end pointers      */
           /* don't work, so we discard it and try again.                  */
           munmap(result, (size_t)(-GC_page_size) - (size_t)result);
                           /* Leave last page mapped, so we can't repeat. */
           return GC_unix_get_mem(bytes);
         }
   #   else
         GC_ASSERT(last_addr != 0);
   #   endif
     return((ptr_t)result);      return((ptr_t)result);
 }  }
   
Line 1275  void * os2_alloc(size_t bytes)
Line 1303  void * os2_alloc(size_t bytes)
 # endif /* OS2 */  # endif /* OS2 */
   
   
   # if defined(MSWIN32) || defined(MSWINCE)
   SYSTEM_INFO GC_sysinfo;
   # endif
   
 # ifdef MSWIN32  # ifdef MSWIN32
   
   # ifdef USE_GLOBAL_ALLOC
   #   define GLOBAL_ALLOC_TEST 1
   # else
   #   define GLOBAL_ALLOC_TEST GC_no_win32_dlls
   # endif
   
 word GC_n_heap_bases = 0;  word GC_n_heap_bases = 0;
   
 ptr_t GC_win32_get_mem(bytes)  ptr_t GC_win32_get_mem(bytes)
 word bytes;  word bytes;
 {  {
     ptr_t result;      ptr_t result;
   
     if (GC_win32s) {      if (GLOBAL_ALLOC_TEST) {
         /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */          /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */
         /* There are also unconfirmed rumors of other           */          /* There are also unconfirmed rumors of other           */
         /* problems, so we dodge the issue.                     */          /* problems, so we dodge the issue.                     */
         result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);          result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
         result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));          result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
     } else {      } else {
         result = (ptr_t) VirtualAlloc(NULL, bytes,          /* VirtualProtect only works on regions returned by a   */
           /* single VirtualAlloc call.  Thus we allocate one      */
           /* extra page, which will prevent merging of blocks     */
           /* in separate regions, and eliminate any temptation    */
           /* to call VirtualProtect on a range spanning regions.  */
           /* This wastes a small amount of memory, and risks      */
           /* increased fragmentation.  But better alternatives    */
           /* would require effort.                                */
           result = (ptr_t) VirtualAlloc(NULL, bytes + 1,
                                       MEM_COMMIT | MEM_RESERVE,                                        MEM_COMMIT | MEM_RESERVE,
                                       PAGE_EXECUTE_READWRITE);                                        PAGE_EXECUTE_READWRITE);
     }      }
Line 1304  word bytes;
Line 1351  word bytes;
   
 void GC_win32_free_heap ()  void GC_win32_free_heap ()
 {  {
     if (GC_win32s) {      if (GC_no_win32_dlls) {
         while (GC_n_heap_bases > 0) {          while (GC_n_heap_bases > 0) {
             GlobalFree (GC_heap_bases[--GC_n_heap_bases]);              GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
             GC_heap_bases[GC_n_heap_bases] = 0;              GC_heap_bases[GC_n_heap_bases] = 0;
         }          }
     }      }
 }  }
   # endif
   
   #ifdef AMIGA
   # define GC_AMIGA_AM
   # include "AmigaOS.c"
   # undef GC_AMIGA_AM
   #endif
   
   
   # ifdef MSWINCE
   word GC_n_heap_bases = 0;
   
   ptr_t GC_wince_get_mem(bytes)
   word bytes;
   {
       ptr_t result;
       word i;
   
       /* Round up allocation size to multiple of page size */
       bytes = (bytes + GC_page_size-1) & ~(GC_page_size-1);
   
       /* Try to find reserved, uncommitted pages */
       for (i = 0; i < GC_n_heap_bases; i++) {
           if (((word)(-(signed_word)GC_heap_lengths[i])
                & (GC_sysinfo.dwAllocationGranularity-1))
               >= bytes) {
               result = GC_heap_bases[i] + GC_heap_lengths[i];
               break;
           }
       }
   
       if (i == GC_n_heap_bases) {
           /* Reserve more pages */
           word res_bytes = (bytes + GC_sysinfo.dwAllocationGranularity-1)
                            & ~(GC_sysinfo.dwAllocationGranularity-1);
           /* If we ever support MPROTECT_VDB here, we will probably need to       */
           /* ensure that res_bytes is strictly > bytes, so that VirtualProtect    */
           /* never spans regions.  It seems to be OK for a VirtualFree argument   */
           /* to span regions, so we should be OK for now.                         */
           result = (ptr_t) VirtualAlloc(NULL, res_bytes,
                                         MEM_RESERVE | MEM_TOP_DOWN,
                                         PAGE_EXECUTE_READWRITE);
           if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
               /* If I read the documentation correctly, this can  */
               /* only happen if HBLKSIZE > 64k or not a power of 2.       */
           if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
           GC_heap_bases[GC_n_heap_bases] = result;
           GC_heap_lengths[GC_n_heap_bases] = 0;
           GC_n_heap_bases++;
       }
   
       /* Commit pages */
       result = (ptr_t) VirtualAlloc(result, bytes,
                                     MEM_COMMIT,
                                     PAGE_EXECUTE_READWRITE);
       if (result != NULL) {
           if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
           GC_heap_lengths[i] += bytes;
       }
   
       return(result);
   }
 # endif  # endif
   
 #ifdef USE_MUNMAP  #ifdef USE_MUNMAP
   
 /* For now, this only works on some Unix-like systems.  If you  */  /* For now, this only works on Win32/WinCE and some Unix-like   */
 /* have something else, don't define USE_MUNMAP.                */  /* systems.  If you have something else, don't define           */
   /* USE_MUNMAP.                                                  */
 /* We assume ANSI C to support this feature.                    */  /* We assume ANSI C to support this feature.                    */
   
   #if !defined(MSWIN32) && !defined(MSWINCE)
   
 #include <unistd.h>  #include <unistd.h>
 #include <sys/mman.h>  #include <sys/mman.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/types.h>  #include <sys/types.h>
 #include <fcntl.h>  
   
   #endif
   
 /* Compute a page aligned starting address for the unmap        */  /* Compute a page aligned starting address for the unmap        */
 /* operation on a block of size bytes starting at start.        */  /* operation on a block of size bytes starting at start.        */
 /* Return 0 if the block is too small to make this feasible.    */  /* Return 0 if the block is too small to make this feasible.    */
Line 1348  ptr_t GC_unmap_end(ptr_t start, word bytes)
Line 1460  ptr_t GC_unmap_end(ptr_t start, word bytes)
     return end_addr;      return end_addr;
 }  }
   
   /* Under Win32/WinCE we commit (map) and decommit (unmap)       */
   /* memory using VirtualAlloc and VirtualFree.  These functions  */
   /* work on individual allocations of virtual memory, made       */
   /* previously using VirtualAlloc with the MEM_RESERVE flag.     */
   /* The ranges we need to (de)commit may span several of these   */
   /* allocations; therefore we use VirtualQuery to check          */
   /* allocation lengths, and split up the range as necessary.     */
   
 /* We assume that GC_remap is called on exactly the same range  */  /* We assume that GC_remap is called on exactly the same range  */
 /* as a previous call to GC_unmap.  It is safe to consistently  */  /* as a previous call to GC_unmap.  It is safe to consistently  */
 /* round the endpoints in both places.                          */  /* round the endpoints in both places.                          */
Line 1357  void GC_unmap(ptr_t start, word bytes)
Line 1477  void GC_unmap(ptr_t start, word bytes)
     ptr_t end_addr = GC_unmap_end(start, bytes);      ptr_t end_addr = GC_unmap_end(start, bytes);
     word len = end_addr - start_addr;      word len = end_addr - start_addr;
     if (0 == start_addr) return;      if (0 == start_addr) return;
     if (munmap(start_addr, len) != 0) ABORT("munmap failed");  #   if defined(MSWIN32) || defined(MSWINCE)
     GC_unmapped_bytes += len;        while (len != 0) {
             MEMORY_BASIC_INFORMATION mem_info;
             GC_word free_len;
             if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
                 != sizeof(mem_info))
                 ABORT("Weird VirtualQuery result");
             free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
             if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
                 ABORT("VirtualFree failed");
             GC_unmapped_bytes += free_len;
             start_addr += free_len;
             len -= free_len;
         }
   #   else
         if (munmap(start_addr, len) != 0) ABORT("munmap failed");
         GC_unmapped_bytes += len;
   #   endif
 }  }
   
   
Line 1370  void GC_remap(ptr_t start, word bytes)
Line 1506  void GC_remap(ptr_t start, word bytes)
     word len = end_addr - start_addr;      word len = end_addr - start_addr;
     ptr_t result;      ptr_t result;
   
     if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);  #   if defined(MSWIN32) || defined(MSWINCE)
     if (0 == start_addr) return;        if (0 == start_addr) return;
     result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,        while (len != 0) {
                   MAP_FIXED | MAP_PRIVATE, zero_descr, 0);            MEMORY_BASIC_INFORMATION mem_info;
     if (result != start_addr) {            GC_word alloc_len;
         ABORT("mmap remapping failed");            if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
     }                != sizeof(mem_info))
     GC_unmapped_bytes -= len;                ABORT("Weird VirtualQuery result");
             alloc_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
             result = VirtualAlloc(start_addr, alloc_len,
                                   MEM_COMMIT,
                                   PAGE_EXECUTE_READWRITE);
             if (result != start_addr) {
                 ABORT("VirtualAlloc remapping failed");
             }
             GC_unmapped_bytes -= alloc_len;
             start_addr += alloc_len;
             len -= alloc_len;
         }
   #   else
         if (-1 == zero_descr) zero_descr = open("/dev/zero", O_RDWR);
         if (0 == start_addr) return;
         result = mmap(start_addr, len, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
                       MAP_FIXED | MAP_PRIVATE, zero_descr, 0);
         if (result != start_addr) {
             ABORT("mmap remapping failed");
         }
         GC_unmapped_bytes -= len;
   #   endif
 }  }
   
 /* Two adjacent blocks have already been unmapped and are about to      */  /* Two adjacent blocks have already been unmapped and are about to      */
Line 1398  void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t sta
Line 1555  void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t sta
     if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);      if (0 == start2_addr) end_addr = GC_unmap_end(start1, bytes1 + bytes2);
     if (0 == start_addr) return;      if (0 == start_addr) return;
     len = end_addr - start_addr;      len = end_addr - start_addr;
     if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed");  #   if defined(MSWIN32) || defined(MSWINCE)
     GC_unmapped_bytes += len;        while (len != 0) {
             MEMORY_BASIC_INFORMATION mem_info;
             GC_word free_len;
             if (VirtualQuery(start_addr, &mem_info, sizeof(mem_info))
                 != sizeof(mem_info))
                 ABORT("Weird VirtualQuery result");
             free_len = (len < mem_info.RegionSize) ? len : mem_info.RegionSize;
             if (!VirtualFree(start_addr, free_len, MEM_DECOMMIT))
                 ABORT("VirtualFree failed");
             GC_unmapped_bytes += free_len;
             start_addr += free_len;
             len -= free_len;
         }
   #   else
         if (len != 0 && munmap(start_addr, len) != 0) ABORT("munmap failed");
         GC_unmapped_bytes += len;
   #   endif
 }  }
   
 #endif /* USE_MUNMAP */  #endif /* USE_MUNMAP */
   
 /* Routine for pushing any additional roots.  In THREADS        */  /* Routine for pushing any additional roots.  In THREADS        */
 /* environment, this is also responsible for marking from       */  /* environment, this is also responsible for marking from       */
 /* thread stacks.  In the SRC_M3 case, it also handles          */  /* thread stacks.                                               */
 /* global variables.                                            */  
 #ifndef THREADS  #ifndef THREADS
 void (*GC_push_other_roots)() = 0;  void (*GC_push_other_roots)() = 0;
 #else /* THREADS */  #else /* THREADS */
Line 1434  PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any
Line 1606  PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any
 }  }
   
   
 void GC_default_push_other_roots()  void GC_default_push_other_roots GC_PROTO((void))
 {  {
     /* Traverse data allocated by previous memory managers.             */      /* Traverse data allocated by previous memory managers.             */
         {          {
Line 1462  void GC_default_push_other_roots()
Line 1634  void GC_default_push_other_roots()
     --> misconfigured      --> misconfigured
 # endif  # endif
   
   void GC_push_thread_structures GC_PROTO((void))
   {
       /* Not our responsibibility. */
   }
   
 extern void ThreadF__ProcessStacks();  extern void ThreadF__ProcessStacks();
   
Line 1479  int dummy3;
Line 1655  int dummy3;
 {  {
     word q = *p;      word q = *p;
   
     if ((ptr_t)(q) >= GC_least_plausible_heap_addr      GC_PUSH_ONE_STACK(q, p);
          && (ptr_t)(q) < GC_greatest_plausible_heap_addr) {  
          GC_push_one_checked(q,FALSE);  
     }  
 }  }
   
 /* M3 set equivalent to RTHeap.TracedRefTypes */  /* M3 set equivalent to RTHeap.TracedRefTypes */
 typedef struct { int elts[1]; }  RefTypeSet;  typedef struct { int elts[1]; }  RefTypeSet;
 RefTypeSet GC_TracedRefTypes = {{0x1}};  RefTypeSet GC_TracedRefTypes = {{0x1}};
   
 /* From finalize.c */  void GC_default_push_other_roots GC_PROTO((void))
 extern void GC_push_finalizer_structures();  
   
 /* From stubborn.c: */  
 # ifdef STUBBORN_ALLOC  
     extern GC_PTR * GC_changing_list_start;  
 # endif  
   
   
 void GC_default_push_other_roots()  
 {  {
     /* Use the M3 provided routine for finding static roots.    */      /* Use the M3 provided routine for finding static roots.     */
     /* This is a bit dubious, since it presumes no C roots.     */      /* This is a bit dubious, since it presumes no C roots.      */
     /* We handle the collector roots explicitly.                */      /* We handle the collector roots explicitly in GC_push_roots */
        {          RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
 #        ifdef STUBBORN_ALLOC  
            GC_push_one(GC_changing_list_start);  
 #        endif  
          GC_push_finalizer_structures();  
          RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);  
        }  
         if (GC_words_allocd > 0) {          if (GC_words_allocd > 0) {
             ThreadF__ProcessStacks(GC_push_thread_stack);              ThreadF__ProcessStacks(GC_push_thread_stack);
         }          }
Line 1519  void GC_default_push_other_roots()
Line 1677  void GC_default_push_other_roots()
   
 # endif /* SRC_M3 */  # endif /* SRC_M3 */
   
 # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \  # if defined(GC_SOLARIS_THREADS) || defined(GC_PTHREADS) || \
      || defined(IRIX_THREADS) || defined(LINUX_THREADS) \       defined(GC_WIN32_THREADS)
      || defined(IRIX_JDK_THREADS) || defined(HPUX_THREADS)  
   
 extern void GC_push_all_stacks();  extern void GC_push_all_stacks();
   
 void GC_default_push_other_roots()  void GC_default_push_other_roots GC_PROTO((void))
 {  {
     GC_push_all_stacks();      GC_push_all_stacks();
 }  }
   
 # endif /* SOLARIS_THREADS || ... */  # endif /* GC_SOLARIS_THREADS || GC_PTHREADS */
   
 void (*GC_push_other_roots)() = GC_default_push_other_roots;  void (*GC_push_other_roots) GC_PROTO((void)) = GC_default_push_other_roots;
   
 #endif  #endif /* THREADS */
   
 /*  /*
  * Routines for accessing dirty  bits on virtual pages.   * Routines for accessing dirty  bits on virtual pages.
  * We plan to eventaually implement four strategies for doing so:   * We plan to eventually implement four strategies for doing so:
  * DEFAULT_VDB: A simple dummy implementation that treats every page   * DEFAULT_VDB: A simple dummy implementation that treats every page
  *              as possibly dirty.  This makes incremental collection   *              as possibly dirty.  This makes incremental collection
  *              useless, but the implementation is still correct.   *              useless, but the implementation is still correct.
Line 1611  word n;
Line 1768  word n;
 {  {
 }  }
   
 /* A call hints that h is about to be written.  */  /* A call that:                                         */
 /* May speed up some dirty bit implementations. */  /* I) hints that [h, h+nblocks) is about to be written. */
   /* II) guarantees that protection is removed.           */
   /* (I) may speed up some dirty bit implementations.     */
   /* (II) may be essential if we need to ensure that      */
   /* pointer-free system call buffers in the heap are     */
   /* not protected.                                       */
 /*ARGSUSED*/  /*ARGSUSED*/
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
 }  }
   
Line 1631  struct hblk *h;
Line 1795  struct hblk *h;
 /*  /*
  * This implementation maintains dirty bits itself by catching write   * This implementation maintains dirty bits itself by catching write
  * faults and keeping track of them.  We assume nobody else catches   * faults and keeping track of them.  We assume nobody else catches
  * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls   * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls.
  * except as a result of a read system call.  This means clients must   * This means that clients must ensure that system calls don't write
  * either ensure that system calls do not touch the heap, or must   * to the write-protected heap.  Probably the best way to do this is to
  * provide their own wrappers analogous to the one for read.   * ensure that system calls write at most to POINTERFREE objects in the
    * heap, and do even that only if we are on a platform on which those
    * are not protected.  Another alternative is to wrap system calls
    * (see example for read below), but the current implementation holds
    * a lock across blocking calls, making it problematic for multithreaded
    * applications.
  * We assume the page size is a multiple of HBLKSIZE.   * We assume the page size is a multiple of HBLKSIZE.
  * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we   * We prefer them to be the same.  We avoid protecting POINTERFREE
  * tried to use portable code where easily possible.  It is known   * objects only if they are the same.
  * not to work under a number of other systems.  
  */   */
   
 # ifndef MSWIN32  # if !defined(MSWIN32) && !defined(MSWINCE)
   
 #   include <sys/mman.h>  #   include <sys/mman.h>
 #   include <signal.h>  #   include <signal.h>
Line 1660  struct hblk *h;
Line 1828  struct hblk *h;
   
 # else  # else
   
 #   include <signal.h>  #   ifndef MSWINCE
   #     include <signal.h>
   #   endif
   
     static DWORD protect_junk;      static DWORD protect_junk;
 #   define PROTECT(addr, len) \  #   define PROTECT(addr, len) \
Line 1681  struct hblk *h;
Line 1851  struct hblk *h;
 #if defined(SUNOS4) || defined(FREEBSD)  #if defined(SUNOS4) || defined(FREEBSD)
     typedef void (* SIG_PF)();      typedef void (* SIG_PF)();
 #endif  #endif
 #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX)  #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
       || defined(MACOSX) || defined(HURD)
 # ifdef __STDC__  # ifdef __STDC__
     typedef void (* SIG_PF)(int);      typedef void (* SIG_PF)(int);
 # else  # else
Line 1693  struct hblk *h;
Line 1864  struct hblk *h;
 #   undef SIG_DFL  #   undef SIG_DFL
 #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)  #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
 #endif  #endif
   #if defined(MSWINCE)
       typedef LONG (WINAPI *SIG_PF)(struct _EXCEPTION_POINTERS *);
   #   undef SIG_DFL
   #   define SIG_DFL (SIG_PF) (-1)
   #endif
   
 #if defined(IRIX5) || defined(OSF1)  #if defined(IRIX5) || defined(OSF1) || defined(HURD)
     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
 #endif  #endif
 #if defined(SUNOS5SIGS)  #if defined(SUNOS5SIGS)
Line 1710  struct hblk *h;
Line 1886  struct hblk *h;
 # endif  # endif
 #endif  #endif
 #if defined(LINUX)  #if defined(LINUX)
 #   include <linux/version.h>  #   if __GLIBC__ > 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ >= 2
 #   if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(IA64)  
       typedef struct sigcontext s_c;        typedef struct sigcontext s_c;
 #   else  #   else  /* glibc < 2.2 */
       typedef struct sigcontext_struct s_c;  #     include <linux/version.h>
 #   endif  #     if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA) || defined(ARM32)
           typedef struct sigcontext s_c;
   #     else
           typedef struct sigcontext_struct s_c;
   #     endif
   #   endif  /* glibc < 2.2 */
 #   if defined(ALPHA) || defined(M68K)  #   if defined(ALPHA) || defined(M68K)
       typedef void (* REAL_SIG_PF)(int, int, s_c *);        typedef void (* REAL_SIG_PF)(int, int, s_c *);
 #   else  #   else
 #     if defined(IA64)  #     if defined(IA64) || defined(HP_PA)
         typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);          typedef void (* REAL_SIG_PF)(int, siginfo_t *, s_c *);
 #     else  #     else
         typedef void (* REAL_SIG_PF)(int, s_c);          typedef void (* REAL_SIG_PF)(int, s_c);
Line 1740  struct hblk *h;
Line 1920  struct hblk *h;
 #   endif /* !ALPHA */  #   endif /* !ALPHA */
 # endif  # endif
   
   # if defined(MACOSX) /* Should also test for PowerPC? */
       typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
   
   /* Decodes the machine instruction which was responsible for the sending of the
      SIGBUS signal. Sadly this is the only way to find the faulting address because
      the signal handler doesn't get it directly from the kernel (although it is
      available on the Mach level, but droppped by the BSD personality before it
      calls our signal handler...)
      This code should be able to deal correctly with all PPCs starting from the
      601 up to and including the G4s (including Velocity Engine). */
   #define EXTRACT_OP1(iw)     (((iw) & 0xFC000000) >> 26)
   #define EXTRACT_OP2(iw)     (((iw) & 0x000007FE) >> 1)
   #define EXTRACT_REGA(iw)    (((iw) & 0x001F0000) >> 16)
   #define EXTRACT_REGB(iw)    (((iw) & 0x03E00000) >> 21)
   #define EXTRACT_REGC(iw)    (((iw) & 0x0000F800) >> 11)
   #define EXTRACT_DISP(iw)    ((short *) &(iw))[1]
   
   static char *get_fault_addr(struct sigcontext *scp)
   {
      unsigned int   instr = *((unsigned int *) scp->sc_ir);
      unsigned int * regs = &((unsigned int *) scp->sc_regs)[2];
      int            disp = 0, tmp;
      unsigned int   baseA = 0, baseB = 0;
      unsigned int   addr, alignmask = 0xFFFFFFFF;
   
   #ifdef GC_DEBUG_DECODER
      GC_err_printf1("Instruction: 0x%lx\n", instr);
      GC_err_printf1("Opcode 1: d\n", (int)EXTRACT_OP1(instr));
   #endif
      switch(EXTRACT_OP1(instr)) {
         case 38:   /* stb */
         case 39:   /* stbu */
         case 54:   /* stfd */
         case 55:   /* stfdu */
         case 52:   /* stfs */
         case 53:   /* stfsu */
         case 44:   /* sth */
         case 45:   /* sthu */
         case 47:   /* stmw */
         case 36:   /* stw */
         case 37:   /* stwu */
               tmp = EXTRACT_REGA(instr);
               if(tmp > 0)
                  baseA = regs[tmp];
               disp = EXTRACT_DISP(instr);
               break;
         case 31:
   #ifdef GC_DEBUG_DECODER
               GC_err_printf1("Opcode 2: %d\n", (int)EXTRACT_OP2(instr));
   #endif
               switch(EXTRACT_OP2(instr)) {
                  case 86:    /* dcbf */
                  case 54:    /* dcbst */
                  case 1014:  /* dcbz */
                  case 247:   /* stbux */
                  case 215:   /* stbx */
                  case 759:   /* stfdux */
                  case 727:   /* stfdx */
                  case 983:   /* stfiwx */
                  case 695:   /* stfsux */
                  case 663:   /* stfsx */
                  case 918:   /* sthbrx */
                  case 439:   /* sthux */
                  case 407:   /* sthx */
                  case 661:   /* stswx */
                  case 662:   /* stwbrx */
                  case 150:   /* stwcx. */
                  case 183:   /* stwux */
                  case 151:   /* stwx */
                  case 135:   /* stvebx */
                  case 167:   /* stvehx */
                  case 199:   /* stvewx */
                  case 231:   /* stvx */
                  case 487:   /* stvxl */
                        tmp = EXTRACT_REGA(instr);
                        if(tmp > 0)
                           baseA = regs[tmp];
                           baseB = regs[EXTRACT_REGC(instr)];
                           /* determine Altivec alignment mask */
                           switch(EXTRACT_OP2(instr)) {
                              case 167:   /* stvehx */
                                    alignmask = 0xFFFFFFFE;
                                    break;
                              case 199:   /* stvewx */
                                    alignmask = 0xFFFFFFFC;
                                    break;
                              case 231:   /* stvx */
                                    alignmask = 0xFFFFFFF0;
                                    break;
                              case 487:  /* stvxl */
                                    alignmask = 0xFFFFFFF0;
                                    break;
                           }
                           break;
                  case 725:   /* stswi */
                        tmp = EXTRACT_REGA(instr);
                        if(tmp > 0)
                           baseA = regs[tmp];
                           break;
                  default:   /* ignore instruction */
   #ifdef GC_DEBUG_DECODER
                        GC_err_printf("Ignored by inner handler\n");
   #endif
                        return NULL;
                       break;
               }
               break;
         default:   /* ignore instruction */
   #ifdef GC_DEBUG_DECODER
               GC_err_printf("Ignored by main handler\n");
   #endif
               return NULL;
               break;
      }
   
      addr = (baseA + baseB) + disp;
     addr &= alignmask;
   #ifdef GC_DEBUG_DECODER
      GC_err_printf1("BaseA: %d\n", baseA);
      GC_err_printf1("BaseB: %d\n", baseB);
      GC_err_printf1("Disp:  %d\n", disp);
      GC_err_printf1("Address: %d\n", addr);
   #endif
      return (char *)addr;
   }
   #endif /* MACOSX */
   
 SIG_PF GC_old_bus_handler;  SIG_PF GC_old_bus_handler;
 SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */  SIG_PF GC_old_segv_handler;     /* Also old MSWIN32 ACCESS_VIOLATION filter */
   
   #ifdef THREADS
   /* We need to lock around the bitmap update in the write fault handler  */
   /* in order to avoid the risk of losing a bit.  We do this with a       */
   /* test-and-set spin lock if we know how to do that.  Otherwise we      */
   /* check whether we are already in the handler and use the dumb but     */
   /* safe fallback algorithm of setting all bits in the word.             */
   /* Contention should be very rare, so we do the minimum to handle it    */
   /* correctly.                                                           */
   #ifdef GC_TEST_AND_SET_DEFINED
     static VOLATILE unsigned int fault_handler_lock = 0;
     void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
       while (GC_test_and_set(&fault_handler_lock)) {}
       /* Could also revert to set_pht_entry_from_index_safe if initial    */
       /* GC_test_and_set fails.                                           */
       set_pht_entry_from_index(db, index);
       GC_clear(&fault_handler_lock);
     }
   #else /* !GC_TEST_AND_SET_DEFINED */
     /* THIS IS INCORRECT! The dirty bit vector may be temporarily wrong,  */
     /* just before we notice the conflict and correct it. We may end up   */
     /* looking at it while it's wrong.  But this requires contention      */
     /* exactly when a GC is triggered, which seems far less likely to     */
     /* fail than the old code, which had no reported failures.  Thus we   */
     /* leave it this way while we think of something better, or support   */
     /* GC_test_and_set on the remaining platforms.                        */
     static VOLATILE word currently_updating = 0;
     void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
       unsigned int update_dummy;
       currently_updating = (word)(&update_dummy);
       set_pht_entry_from_index(db, index);
       /* If we get contention in the 10 or so instruction window here,    */
       /* and we get stopped by a GC between the two updates, we lose!     */
       if (currently_updating != (word)(&update_dummy)) {
           set_pht_entry_from_index_safe(db, index);
           /* We claim that if two threads concurrently try to update the  */
           /* dirty bit vector, the first one to execute UPDATE_START      */
           /* will see it changed when UPDATE_END is executed.  (Note that */
           /* &update_dummy must differ in two distinct threads.)  It      */
           /* will then execute set_pht_entry_from_index_safe, thus        */
           /* returning us to a safe state, though not soon enough.        */
       }
     }
   #endif /* !GC_TEST_AND_SET_DEFINED */
   #else /* !THREADS */
   # define async_set_pht_entry_from_index(db, index) \
           set_pht_entry_from_index(db, index)
   #endif /* !THREADS */
   
 /*ARGSUSED*/  /*ARGSUSED*/
 # if defined (SUNOS4) || defined(FREEBSD)  # if defined (SUNOS4) || defined(FREEBSD)
     void GC_write_fault_handler(sig, code, scp, addr)      void GC_write_fault_handler(sig, code, scp, addr)
Line 1760  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2115  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #     define CODE_OK (code == BUS_PAGE_FAULT)  #     define CODE_OK (code == BUS_PAGE_FAULT)
 #   endif  #   endif
 # endif  # endif
 # if defined(IRIX5) || defined(OSF1)  # if defined(IRIX5) || defined(OSF1) || defined(HURD)
 #   include <errno.h>  #   include <errno.h>
     void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)      void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
 #   define SIG_OK (sig == SIGSEGV)  
 #   ifdef OSF1  #   ifdef OSF1
   #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (code == 2 /* experimentally determined */)  #     define CODE_OK (code == 2 /* experimentally determined */)
 #   endif  #   endif
 #   ifdef IRIX5  #   ifdef IRIX5
   #     define SIG_OK (sig == SIGSEGV)
 #     define CODE_OK (code == EACCES)  #     define CODE_OK (code == EACCES)
 #   endif  #   endif
   #   ifdef HURD
   #     define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
   #     define CODE_OK  TRUE
   #   endif
 # endif  # endif
 # if defined(LINUX)  # if defined(LINUX)
 #   if defined(ALPHA) || defined(M68K)  #   if defined(ALPHA) || defined(M68K)
       void GC_write_fault_handler(int sig, int code, s_c * sc)        void GC_write_fault_handler(int sig, int code, s_c * sc)
 #   else  #   else
 #     if defined(IA64)  #     if defined(IA64) || defined(HP_PA)
         void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)          void GC_write_fault_handler(int sig, siginfo_t * si, s_c * scp)
 #     else  #     else
         void GC_write_fault_handler(int sig, s_c sc)  #       if defined(ARM32)
             void GC_write_fault_handler(int sig, int a2, int a3, int a4, s_c sc)
   #       else
             void GC_write_fault_handler(int sig, s_c sc)
   #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   define SIG_OK (sig == SIGSEGV)  #   define SIG_OK (sig == SIGSEGV)
Line 1808  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2172  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #     define CODE_OK (scp -> si_code == SEGV_ACCERR)  #     define CODE_OK (scp -> si_code == SEGV_ACCERR)
 #   endif  #   endif
 # endif  # endif
 # if defined(MSWIN32)  
   # if defined(MACOSX)
       void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
   #   define SIG_OK (sig == SIGBUS)
   #   define CODE_OK (code == 0 /* experimentally determined */)
   # endif
   
   # if defined(MSWIN32) || defined(MSWINCE)
     LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)      LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
 #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \  #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
                         EXCEPTION_ACCESS_VIOLATION)                          STATUS_ACCESS_VIOLATION)
 #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)  #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
                         /* Write fault */                          /* Write fault */
 # endif  # endif
 {  {
     register unsigned i;      register unsigned i;
   #   if defined(HURD)
           char *addr = (char *) code;
   #   endif
 #   ifdef IRIX5  #   ifdef IRIX5
         char * addr = (char *) (size_t) (scp -> sc_badvaddr);          char * addr = (char *) (size_t) (scp -> sc_badvaddr);
 #   endif  #   endif
Line 1833  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2207  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #       if defined(M68K)  #       if defined(M68K)
           char * addr = NULL;            char * addr = NULL;
   
           struct sigcontext *scp = (struct sigcontext *)(&sc);            struct sigcontext *scp = (struct sigcontext *)(sc);
   
           int format = (scp->sc_formatvec >> 12) & 0xf;            int format = (scp->sc_formatvec >> 12) & 0xf;
           unsigned long *framedata = (unsigned long *)(scp + 1);            unsigned long *framedata = (unsigned long *)(scp + 1);
Line 1845  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2219  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
           } else if (format == 7) {            } else if (format == 7) {
                 /* 68040 */                  /* 68040 */
                 ea = framedata[3];                  ea = framedata[3];
                   if (framedata[1] & 0x08000000) {
                           /* correct addr on misaligned access */
                           ea = (ea+4095)&(~4095);
                   }
           } else if (format == 4) {            } else if (format == 4) {
                 /* 68060 */                  /* 68060 */
                 ea = framedata[0];                  ea = framedata[0];
Line 1858  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2236  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #         ifdef ALPHA  #         ifdef ALPHA
             char * addr = get_fault_addr(sc);              char * addr = get_fault_addr(sc);
 #         else  #         else
 #           ifdef IA64  #           if defined(IA64) || defined(HP_PA)
               char * addr = si -> si_addr;                char * addr = si -> si_addr;
               /* I believe this is claimed to work on all platforms for */                /* I believe this is claimed to work on all platforms for */
               /* Linux 2.3.47 and later.  Hopefully we don't have to    */                /* Linux 2.3.47 and later.  Hopefully we don't have to    */
Line 1867  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2245  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #             if defined(POWERPC)  #             if defined(POWERPC)
                 char * addr = (char *) (sc.regs->dar);                  char * addr = (char *) (sc.regs->dar);
 #             else  #             else
                 --> architecture not supported  #               if defined(ARM32)
                     char * addr = (char *)sc.fault_address;
   #               else
                     --> architecture not supported
   #               endif
 #             endif  #             endif
 #           endif  #           endif
 #         endif  #         endif
 #       endif  #       endif
 #     endif  #     endif
 #   endif  #   endif
 #   if defined(MSWIN32)  #   if defined(MACOSX)
           char * addr = get_fault_addr(scp);
   #   endif
   #   if defined(MSWIN32) || defined(MSWINCE)
         char * addr = (char *) (exc_info -> ExceptionRecord          char * addr = (char *) (exc_info -> ExceptionRecord
                                 -> ExceptionInformation[1]);                                  -> ExceptionInformation[1]);
 #       define sig SIGSEGV  #       define sig SIGSEGV
Line 1906  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2291  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
                 old_handler = GC_old_bus_handler;                  old_handler = GC_old_bus_handler;
             }              }
             if (old_handler == SIG_DFL) {              if (old_handler == SIG_DFL) {
 #               ifndef MSWIN32  #               if !defined(MSWIN32) && !defined(MSWINCE)
                     GC_err_printf1("Segfault at 0x%lx\n", addr);                      GC_err_printf1("Segfault at 0x%lx\n", addr);
                     ABORT("Unexpected bus error or segmentation fault");                      ABORT("Unexpected bus error or segmentation fault");
 #               else  #               else
Line 1925  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2310  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #                   if defined(ALPHA) || defined(M68K)  #                   if defined(ALPHA) || defined(M68K)
                         (*(REAL_SIG_PF)old_handler) (sig, code, sc);                          (*(REAL_SIG_PF)old_handler) (sig, code, sc);
 #                   else  #                   else
 #                     if defined(IA64)  #                     if defined(IA64) || defined(HP_PA)
                         (*(REAL_SIG_PF)old_handler) (sig, si, scp);                          (*(REAL_SIG_PF)old_handler) (sig, si, scp);
 #                     else  #                     else
                         (*(REAL_SIG_PF)old_handler) (sig, sc);                          (*(REAL_SIG_PF)old_handler) (sig, sc);
Line 1933  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2318  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #                   endif  #                   endif
                     return;                      return;
 #               endif  #               endif
 #               if defined (IRIX5) || defined(OSF1)  #               if defined (IRIX5) || defined(OSF1) || defined(HURD)
                     (*(REAL_SIG_PF)old_handler) (sig, code, scp);                      (*(REAL_SIG_PF)old_handler) (sig, code, scp);
                     return;                      return;
 #               endif  #               endif
   #               ifdef MACOSX
                       (*(REAL_SIG_PF)old_handler) (sig, code, scp);
   #               endif
 #               ifdef MSWIN32  #               ifdef MSWIN32
                     return((*old_handler)(exc_info));                      return((*old_handler)(exc_info));
 #               endif  #               endif
             }              }
         }          }
           UNPROTECT(h, GC_page_size);
           /* We need to make sure that no collection occurs between       */
           /* the UNPROTECT and the setting of the dirty bit.  Otherwise   */
           /* a write by a third thread might go unnoticed.  Reversing     */
           /* the order is just as bad, since we would end up unprotecting */
           /* a page in a GC cycle during which it's not marked.           */
           /* Currently we do this by disabling the thread stopping        */
           /* signals while this handler is running.  An alternative might */
           /* be to record the fact that we're about to unprotect, or      */
           /* have just unprotected a page in the GC's thread structure,   */
           /* and then to have the thread stopping code set the dirty      */
           /* flag, if necessary.                                          */
         for (i = 0; i < divHBLKSZ(GC_page_size); i++) {          for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
             register int index = PHT_HASH(h+i);              register int index = PHT_HASH(h+i);
   
             set_pht_entry_from_index(GC_dirty_pages, index);              async_set_pht_entry_from_index(GC_dirty_pages, index);
         }          }
         UNPROTECT(h, GC_page_size);  #       if defined(OSF1)
 #       if defined(OSF1) || defined(LINUX)  
             /* These reset the signal handler each time by default. */              /* These reset the signal handler each time by default. */
             signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);              signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
 #       endif  #       endif
         /* The write may not take place before dirty bits are read.     */          /* The write may not take place before dirty bits are read.     */
         /* But then we'll fault again ...                               */          /* But then we'll fault again ...                               */
 #       ifdef MSWIN32  #       if defined(MSWIN32) || defined(MSWINCE)
             return(EXCEPTION_CONTINUE_EXECUTION);              return(EXCEPTION_CONTINUE_EXECUTION);
 #       else  #       else
             return;              return;
 #       endif  #       endif
     }      }
 #ifdef MSWIN32  #if defined(MSWIN32) || defined(MSWINCE)
     return EXCEPTION_CONTINUE_SEARCH;      return EXCEPTION_CONTINUE_SEARCH;
 #else  #else
     GC_err_printf1("Segfault at 0x%lx\n", addr);      GC_err_printf1("Segfault at 0x%lx\n", addr);
Line 1970  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2369  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
   
 /*  /*
  * We hold the allocation lock.  We expect block h to be written   * We hold the allocation lock.  We expect block h to be written
  * shortly.   * shortly.  Ensure that all pages containing any part of the n hblks
    * starting at h are no longer protected.  If is_ptrfree is false,
    * also ensure that they will subsequently appear to be dirty.
  */   */
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
     register struct hblk * h_trunc;      struct hblk * h_trunc;  /* Truncated to page boundary */
     register unsigned i;      struct hblk * h_end;    /* Page boundary following block end */
     register GC_bool found_clean;      struct hblk * current;
       GC_bool found_clean;
   
     if (!GC_dirty_maintained) return;      if (!GC_dirty_maintained) return;
     h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));      h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
       h_end = (struct hblk *)(((word)(h + nblocks) + GC_page_size-1)
                               & ~(GC_page_size-1));
     found_clean = FALSE;      found_clean = FALSE;
     for (i = 0; i < divHBLKSZ(GC_page_size); i++) {      for (current = h_trunc; current < h_end; ++current) {
         register int index = PHT_HASH(h_trunc+i);          int index = PHT_HASH(current);
   
         if (!get_pht_entry_from_index(GC_dirty_pages, index)) {          if (!is_ptrfree || current < h || current >= h + nblocks) {
             found_clean = TRUE;              async_set_pht_entry_from_index(GC_dirty_pages, index);
             set_pht_entry_from_index(GC_dirty_pages, index);  
         }          }
     }      }
     if (found_clean) {      UNPROTECT(h_trunc, (ptr_t)h_end - (ptr_t)h_trunc);
         UNPROTECT(h_trunc, GC_page_size);  
     }  
 }  }
   
 void GC_dirty_init()  void GC_dirty_init()
 {  {
 #if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
     struct sigaction    act, oldact;         defined(OSF1) || defined(HURD)
 #   ifdef IRIX5        struct sigaction  act, oldact;
         /* We should probably specify SA_SIGINFO for Linux, and handle    */
         /* the different architectures more uniformly.                    */
   #     if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD)
         act.sa_flags    = SA_RESTART;          act.sa_flags    = SA_RESTART;
         act.sa_handler  = GC_write_fault_handler;          act.sa_handler  = (SIG_PF)GC_write_fault_handler;
 #   else  #     else
         act.sa_flags    = SA_RESTART | SA_SIGINFO;          act.sa_flags    = SA_RESTART | SA_SIGINFO;
         act.sa_sigaction = GC_write_fault_handler;          act.sa_sigaction = GC_write_fault_handler;
   #     endif
         (void)sigemptyset(&act.sa_mask);
   #     ifdef SIG_SUSPEND
           /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
           /* handler.  This effectively makes the handler atomic w.r.t.   */
           /* stopping the world for GC.                                   */
           (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
   #     endif /* SIG_SUSPEND */
   #    endif
   #   if defined(MACOSX)
         struct sigaction act, oldact;
   
         act.sa_flags = SA_RESTART;
         act.sa_handler = GC_write_fault_handler;
         sigemptyset(&act.sa_mask);
 #   endif  #   endif
     (void)sigemptyset(&act.sa_mask);  
 #endif  
 #   ifdef PRINTSTATS  #   ifdef PRINTSTATS
         GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");          GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
 #   endif  #   endif
Line 2028  void GC_dirty_init()
Line 2447  void GC_dirty_init()
 #       endif  #       endif
       }        }
 #   endif  #   endif
 #   if defined(OSF1) || defined(SUNOS4) || defined(LINUX)  #   if defined(SUNOS4)
       GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);        GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
       if (GC_old_segv_handler == SIG_IGN) {        if (GC_old_segv_handler == SIG_IGN) {
         GC_err_printf0("Previously ignored segmentation violation!?");          GC_err_printf0("Previously ignored segmentation violation!?");
Line 2040  void GC_dirty_init()
Line 2459  void GC_dirty_init()
 #       endif  #       endif
       }        }
 #   endif  #   endif
 #   if defined(SUNOS5SIGS) || defined(IRIX5)  #   if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \
 #     if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS)         || defined(OSF1) || defined(HURD)
         /* SUNOS5SIGS includes HPUX */
   #     if defined(GC_IRIX_THREADS)
         sigaction(SIGSEGV, 0, &oldact);          sigaction(SIGSEGV, 0, &oldact);
         sigaction(SIGSEGV, &act, 0);          sigaction(SIGSEGV, &act, 0);
 #     else  #     else
         sigaction(SIGSEGV, &act, &oldact);          sigaction(SIGSEGV, &act, &oldact);
 #     endif  #     endif
 #     if defined(_sigargs)  #     if defined(_sigargs) || defined(HURD) || !defined(SA_SIGINFO)
         /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */          /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
         /* sa_sigaction.                                        */          /* sa_sigaction.                                        */
         GC_old_segv_handler = oldact.sa_handler;          GC_old_segv_handler = oldact.sa_handler;
 #     else /* Irix 6.x or SUNOS5SIGS */  #     else /* Irix 6.x or SUNOS5SIGS or LINUX */
         if (oldact.sa_flags & SA_SIGINFO) {          if (oldact.sa_flags & SA_SIGINFO) {
           GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);            GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
         } else {          } else {
Line 2067  void GC_dirty_init()
Line 2488  void GC_dirty_init()
           GC_err_printf0("Replaced other SIGSEGV handler\n");            GC_err_printf0("Replaced other SIGSEGV handler\n");
 #       endif  #       endif
       }        }
 #     ifdef HPUX  #   endif
           sigaction(SIGBUS, &act, &oldact);  #   if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
           GC_old_bus_handler = oldact.sa_handler;        sigaction(SIGBUS, &act, &oldact);
           if (GC_old_segv_handler != SIG_DFL) {        GC_old_bus_handler = oldact.sa_handler;
 #           ifdef PRINTSTATS        if (GC_old_bus_handler == SIG_IGN) {
               GC_err_printf0("Replaced other SIGBUS handler\n");               GC_err_printf0("Previously ignored bus error!?");
 #           endif               GC_old_bus_handler = SIG_DFL;
           }        }
 #     endif        if (GC_old_bus_handler != SIG_DFL) {
 #    endif  #       ifdef PRINTSTATS
             GC_err_printf0("Replaced other SIGBUS handler\n");
   #       endif
         }
   #   endif /* MACOS || HPUX || LINUX */
 #   if defined(MSWIN32)  #   if defined(MSWIN32)
       GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);        GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
       if (GC_old_segv_handler != NULL) {        if (GC_old_segv_handler != NULL) {
Line 2089  void GC_dirty_init()
Line 2514  void GC_dirty_init()
 #   endif  #   endif
 }  }
   
   int GC_incremental_protection_needs()
   {
       if (GC_page_size == HBLKSIZE) {
           return GC_PROTECTS_POINTER_HEAP;
       } else {
           return GC_PROTECTS_POINTER_HEAP | GC_PROTECTS_PTRFREE_HEAP;
       }
   }
   
   #define HAVE_INCREMENTAL_PROTECTION_NEEDS
   
   #define IS_PTRFREE(hhdr) ((hhdr)->hb_descr == 0)
   
   #define PAGE_ALIGNED(x) !((word)(x) & (GC_page_size - 1))
 void GC_protect_heap()  void GC_protect_heap()
 {  {
     ptr_t start;      ptr_t start;
     word len;      word len;
       struct hblk * current;
       struct hblk * current_start;  /* Start of block to be protected. */
       struct hblk * limit;
     unsigned i;      unsigned i;
       GC_bool protect_all =
             (0 != (GC_incremental_protection_needs() & GC_PROTECTS_PTRFREE_HEAP));
     for (i = 0; i < GC_n_heap_sects; i++) {      for (i = 0; i < GC_n_heap_sects; i++) {
         start = GC_heap_sects[i].hs_start;          start = GC_heap_sects[i].hs_start;
         len = GC_heap_sects[i].hs_bytes;          len = GC_heap_sects[i].hs_bytes;
         PROTECT(start, len);          if (protect_all) {
             PROTECT(start, len);
           } else {
             GC_ASSERT(PAGE_ALIGNED(len))
             GC_ASSERT(PAGE_ALIGNED(start))
             current_start = current = (struct hblk *)start;
             limit = (struct hblk *)(start + len);
             while (current < limit) {
               hdr * hhdr;
               word nhblks;
               GC_bool is_ptrfree;
   
               GC_ASSERT(PAGE_ALIGNED(current));
               GET_HDR(current, hhdr);
               if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
                 /* This can happen only if we're at the beginning of a    */
                 /* heap segment, and a block spans heap segments.         */
                 /* We will handle that block as part of the preceding     */
                 /* segment.                                               */
                 GC_ASSERT(current_start == current);
                 current_start = ++current;
                 continue;
               }
               if (HBLK_IS_FREE(hhdr)) {
                 GC_ASSERT(PAGE_ALIGNED(hhdr -> hb_sz));
                 nhblks = divHBLKSZ(hhdr -> hb_sz);
                 is_ptrfree = TRUE;        /* dirty on alloc */
               } else {
                 nhblks = OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
                 is_ptrfree = IS_PTRFREE(hhdr);
               }
               if (is_ptrfree) {
                 if (current_start < current) {
                   PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
                 }
                 current_start = (current += nhblks);
               } else {
                 current += nhblks;
               }
             }
             if (current_start < current) {
               PROTECT(current_start, (ptr_t)current - (ptr_t)current_start);
             }
           }
     }      }
 }  }
   
Line 2129  struct hblk * h;
Line 2613  struct hblk * h;
  * happens to work.   * happens to work.
  * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.   * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
  */   */
   
   static GC_bool syscall_acquired_lock = FALSE;   /* Protected by GC lock. */
   
 void GC_begin_syscall()  void GC_begin_syscall()
 {  {
     if (!I_HOLD_LOCK()) LOCK();      if (!I_HOLD_LOCK()) {
           LOCK();
           syscall_acquired_lock = TRUE;
       }
 }  }
   
 void GC_end_syscall()  void GC_end_syscall()
 {  {
     if (!I_HOLD_LOCK()) UNLOCK();      if (syscall_acquired_lock) {
           syscall_acquired_lock = FALSE;
           UNLOCK();
       }
 }  }
   
 void GC_unprotect_range(addr, len)  void GC_unprotect_range(addr, len)
Line 2149  word len;
Line 2641  word len;
     register struct hblk *h;      register struct hblk *h;
     ptr_t obj_start;      ptr_t obj_start;
   
     if (!GC_incremental) return;      if (!GC_dirty_maintained) return;
     obj_start = GC_base(addr);      obj_start = GC_base(addr);
     if (obj_start == 0) return;      if (obj_start == 0) return;
     if (GC_base(addr + len - 1) != obj_start) {      if (GC_base(addr + len - 1) != obj_start) {
Line 2161  word len;
Line 2653  word len;
     for (h = start_block; h <= end_block; h++) {      for (h = start_block; h <= end_block; h++) {
         register word index = PHT_HASH(h);          register word index = PHT_HASH(h);
   
         set_pht_entry_from_index(GC_dirty_pages, index);          async_set_pht_entry_from_index(GC_dirty_pages, index);
     }      }
     UNPROTECT(start_block,      UNPROTECT(start_block,
               ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);                ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
 }  }
   
 #if !defined(MSWIN32) && !defined(LINUX_THREADS)  #if 0
 /* Replacement for UNIX system call.     */  
 /* Other calls that write to the heap    */  /* We no longer wrap read by default, since that was causing too many   */
 /* should be handled similarly.          */  /* problems.  It is preferred that the client instead avoids writing    */
   /* to the write-protected heap with a system call.                      */
   /* This still serves as sample code if you do want to wrap system calls.*/
   
   #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(GC_USE_LD_WRAP)
   /* Replacement for UNIX system call.                                      */
   /* Other calls that write to the heap should be handled similarly.        */
   /* Note that this doesn't work well for blocking reads:  It will hold     */
   /* the allocation lock for the entire duration of the call. Multithreaded */
   /* clients should really ensure that it won't block, either by setting    */
   /* the descriptor nonblocking, or by calling select or poll first, to     */
   /* make sure that input is available.                                     */
   /* Another, preferred alternative is to ensure that system calls never    */
   /* write to the protected heap (see above).                               */
 # if defined(__STDC__) && !defined(SUNOS4)  # if defined(__STDC__) && !defined(SUNOS4)
 #   include <unistd.h>  #   include <unistd.h>
 #   include <sys/uio.h>  #   include <sys/uio.h>
Line 2190  word len;
Line 2695  word len;
   
     GC_begin_syscall();      GC_begin_syscall();
     GC_unprotect_range(buf, (word)nbyte);      GC_unprotect_range(buf, (word)nbyte);
 #   if defined(IRIX5) || defined(LINUX_THREADS)  #   if defined(IRIX5) || defined(GC_LINUX_THREADS)
         /* Indirect system call may not always be easily available.     */          /* Indirect system call may not always be easily available.     */
         /* We could call _read, but that would interfere with the       */          /* We could call _read, but that would interfere with the       */
         /* libpthread interception of read.                             */          /* libpthread interception of read.                             */
Line 2204  word len;
Line 2709  word len;
             result = readv(fd, &iov, 1);              result = readv(fd, &iov, 1);
         }          }
 #   else  #   else
         result = syscall(SYS_read, fd, buf, nbyte);  #     if defined(HURD)
           result = __read(fd, buf, nbyte);
   #     else
           /* The two zero args at the end of this list are because one
              IA-64 syscall() implementation actually requires six args
              to be passed, even though they aren't always used. */
           result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
   #     endif /* !HURD */
 #   endif  #   endif
     GC_end_syscall();      GC_end_syscall();
     return(result);      return(result);
 }  }
 #endif /* !MSWIN32 && !LINUX */  #endif /* !MSWIN32 && !MSWINCE && !GC_LINUX_THREADS */
   
 #ifdef USE_LD_WRAP  #if defined(GC_USE_LD_WRAP) && !defined(THREADS)
     /* We use the GNU ld call wrapping facility.                        */      /* We use the GNU ld call wrapping facility.                        */
     /* This requires that the linker be invoked with "--wrap read".     */      /* This requires that the linker be invoked with "--wrap read".     */
     /* This can be done by passing -Wl,"--wrap read" to gcc.            */      /* This can be done by passing -Wl,"--wrap read" to gcc.            */
Line 2233  word len;
Line 2745  word len;
     /* actually calls.                                                  */      /* actually calls.                                                  */
 #endif  #endif
   
   #endif /* 0 */
   
 /*ARGSUSED*/  /*ARGSUSED*/
 GC_bool GC_page_was_ever_dirty(h)  GC_bool GC_page_was_ever_dirty(h)
 struct hblk *h;  struct hblk *h;
Line 2248  word n;
Line 2762  word n;
 {  {
 }  }
   
   # else /* !MPROTECT_VDB */
   
   #   ifdef GC_USE_LD_WRAP
         ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
         { return __real_read(fd, buf, nbyte); }
   #   endif
   
 # endif /* MPROTECT_VDB */  # endif /* MPROTECT_VDB */
   
 # ifdef PROC_VDB  # ifdef PROC_VDB
Line 2270  word n;
Line 2791  word n;
 #include <sys/syscall.h>  #include <sys/syscall.h>
 #include <sys/procfs.h>  #include <sys/procfs.h>
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <fcntl.h>  
   
 #define INITIAL_BUF_SZ 4096  #define INITIAL_BUF_SZ 4096
 word GC_proc_buf_size = INITIAL_BUF_SZ;  word GC_proc_buf_size = INITIAL_BUF_SZ;
 char *GC_proc_buf;  char *GC_proc_buf;
   
 #ifdef SOLARIS_THREADS  #ifdef GC_SOLARIS_THREADS
 /* We don't have exact sp values for threads.  So we count on   */  /* We don't have exact sp values for threads.  So we count on   */
 /* occasionally declaring stack pages to be fresh.  Thus we     */  /* occasionally declaring stack pages to be fresh.  Thus we     */
 /* need a real implementation of GC_is_fresh.  We can't clear   */  /* need a real implementation of GC_is_fresh.  We can't clear   */
Line 2331  void GC_dirty_init()
Line 2851  void GC_dirty_init()
         ABORT("/proc ioctl failed");          ABORT("/proc ioctl failed");
     }      }
     GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);      GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
         GC_fresh_pages = (struct hblk **)          GC_fresh_pages = (struct hblk **)
           GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));            GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
         if (GC_fresh_pages == 0) {          if (GC_fresh_pages == 0) {
Line 2344  void GC_dirty_init()
Line 2864  void GC_dirty_init()
   
 /* Ignore write hints. They don't help us here. */  /* Ignore write hints. They don't help us here. */
 /*ARGSUSED*/  /*ARGSUSED*/
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
 }  }
   
 #ifdef SOLARIS_THREADS  #ifdef GC_SOLARIS_THREADS
 #   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)  #   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
 #else  #else
 #   define READ(fd,buf,nbytes) read(fd, buf, nbytes)  #   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
Line 2388  int dummy;
Line 2910  int dummy;
                 /* Punt:        */                  /* Punt:        */
                 memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));                  memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
                 memset(GC_written_pages, 0xff, sizeof(page_hash_table));                  memset(GC_written_pages, 0xff, sizeof(page_hash_table));
 #               ifdef SOLARIS_THREADS  #               ifdef GC_SOLARIS_THREADS
                     BZERO(GC_fresh_pages,                      BZERO(GC_fresh_pages,
                           MAX_FRESH_PAGES * sizeof (struct hblk *));                            MAX_FRESH_PAGES * sizeof (struct hblk *));
 #               endif  #               endif
Line 2418  int dummy;
Line 2940  int dummy;
                         register word index = PHT_HASH(h);                          register word index = PHT_HASH(h);
   
                         set_pht_entry_from_index(GC_grungy_pages, index);                          set_pht_entry_from_index(GC_grungy_pages, index);
 #                       ifdef SOLARIS_THREADS  #                       ifdef GC_SOLARIS_THREADS
                           {                            {
                             register int slot = FRESH_PAGE_SLOT(h);                              register int slot = FRESH_PAGE_SLOT(h);
   
Line 2436  int dummy;
Line 2958  int dummy;
         }          }
     /* Update GC_written_pages. */      /* Update GC_written_pages. */
         GC_or_pages(GC_written_pages, GC_grungy_pages);          GC_or_pages(GC_written_pages, GC_grungy_pages);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
       /* Make sure that old stacks are considered completely clean      */        /* Make sure that old stacks are considered completely clean      */
       /* unless written again.                                          */        /* unless written again.                                          */
         GC_old_stacks_are_fresh();          GC_old_stacks_are_fresh();
Line 2452  struct hblk *h;
Line 2974  struct hblk *h;
     register GC_bool result;      register GC_bool result;
   
     result = get_pht_entry_from_index(GC_grungy_pages, index);      result = get_pht_entry_from_index(GC_grungy_pages, index);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
         if (result && PAGE_IS_FRESH(h)) result = FALSE;          if (result && PAGE_IS_FRESH(h)) result = FALSE;
         /* This happens only if page was declared fresh since   */          /* This happens only if page was declared fresh since   */
         /* the read_dirty call, e.g. because it's in an unused  */          /* the read_dirty call, e.g. because it's in an unused  */
Line 2470  struct hblk *h;
Line 2992  struct hblk *h;
     register GC_bool result;      register GC_bool result;
   
     result = get_pht_entry_from_index(GC_written_pages, index);      result = get_pht_entry_from_index(GC_written_pages, index);
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
         if (result && PAGE_IS_FRESH(h)) result = FALSE;          if (result && PAGE_IS_FRESH(h)) result = FALSE;
 #   endif  #   endif
     return(result);      return(result);
Line 2484  word n;
Line 3006  word n;
   
     register word index;      register word index;
   
 #   ifdef SOLARIS_THREADS  #   ifdef GC_SOLARIS_THREADS
       register word i;        register word i;
   
       if (GC_fresh_pages != 0) {        if (GC_fresh_pages != 0) {
Line 2553  struct hblk *h;
Line 3075  struct hblk *h;
 }  }
   
 /*ARGSUSED*/  /*ARGSUSED*/
 void GC_write_hint(h)  void GC_remove_protection(h, nblocks, is_ptrfree)
 struct hblk *h;  struct hblk *h;
   word nblocks;
   GC_bool is_ptrfree;
 {  {
     PCR_VD_WriteProtectDisable(h, HBLKSIZE);      PCR_VD_WriteProtectDisable(h, nblocks*HBLKSIZE);
     PCR_VD_WriteProtectEnable(h, HBLKSIZE);      PCR_VD_WriteProtectEnable(h, nblocks*HBLKSIZE);
 }  }
   
 # endif /* PCR_VDB */  # endif /* PCR_VDB */
   
   # ifndef HAVE_INCREMENTAL_PROTECTION_NEEDS
     int GC_incremental_protection_needs()
     {
       return GC_PROTECTS_NONE;
     }
   # endif /* !HAVE_INCREMENTAL_PROTECTION_NEEDS */
   
 /*  /*
  * Call stack save code for debugging.   * Call stack save code for debugging.
  * Should probably be in mach_dep.c, but that requires reorganization.   * Should probably be in mach_dep.c, but that requires reorganization.
  */   */
 #if defined(SPARC) && !defined(LINUX)  
 #   if defined(SUNOS4)  /* I suspect the following works for most X86 *nix variants, so         */
 #     include <machine/frame.h>  /* long as the frame pointer is explicitly stored.  In the case of gcc, */
 #   else  /* compiler flags (e.g. -fomit-frame-pointer) determine whether it is.  */
 #     if defined (DRSNX)  #if defined(I386) && defined(LINUX) && defined(SAVE_CALL_CHAIN)
 #       include <sys/sparc/frame.h>  #   include <features.h>
 #     else  
 #        if defined(OPENBSD)      struct frame {
 #          include <frame.h>          struct frame *fr_savfp;
 #        else          long    fr_savpc;
 #          include <sys/frame.h>          long    fr_arg[NARGS];  /* All the arguments go here.   */
 #        endif      };
 #     endif  #endif
 #   endif  
 #   if NARGS > 6  #if defined(SPARC)
   #  if defined(LINUX)
   #    include <features.h>
   
        struct frame {
           long    fr_local[8];
           long    fr_arg[6];
           struct frame *fr_savfp;
           long    fr_savpc;
   #       ifndef __arch64__
             char  *fr_stret;
   #       endif
           long    fr_argd[6];
           long    fr_argx[0];
        };
   #  else
   #    if defined(SUNOS4)
   #      include <machine/frame.h>
   #    else
   #      if defined (DRSNX)
   #        include <sys/sparc/frame.h>
   #      else
   #        if defined(OPENBSD) || defined(NETBSD)
   #          include <frame.h>
   #        else
   #          include <sys/frame.h>
   #        endif
   #      endif
   #    endif
   #  endif
   #  if NARGS > 6
         --> We only know how to to get the first 6 arguments          --> We only know how to to get the first 6 arguments
 #   endif  #  endif
   #endif /* SPARC */
   
 #ifdef SAVE_CALL_CHAIN  #ifdef  NEED_CALLINFO
 /* Fill in the pc and argument information for up to NFRAMES of my      */  /* Fill in the pc and argument information for up to NFRAMES of my      */
 /* callers.  Ignore my frame and my callers frame.                      */  /* callers.  Ignore my frame and my callers frame.                      */
   
 #ifdef OPENBSD  #ifdef LINUX
   # include <features.h>
   # if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1 || __GLIBC__ > 2
   #   define HAVE_BUILTIN_BACKTRACE
   #   ifdef IA64
   #     define BUILTIN_BACKTRACE_BROKEN
   #   endif
   # endif
   #endif
   
   #include <execinfo.h>
   #ifdef LINUX
   #   include <unistd.h>
   #endif
   
   #endif /* NEED_CALLINFO */
   
   #ifdef SAVE_CALL_CHAIN
   
   #if NARGS == 0 && NFRAMES % 2 == 0 /* No padding */ \
       && defined(HAVE_BUILTIN_BACKTRACE)
   
   void GC_save_callers (info)
   struct callinfo info[NFRAMES];
   {
     void * tmp_info[NFRAMES + 1];
     int npcs, i;
   # define IGNORE_FRAMES 1
   
     /* We retrieve NFRAMES+1 pc values, but discard the first, since it   */
     /* points to our own frame.                                           */
     GC_ASSERT(sizeof(struct callinfo) == sizeof(void *));
     npcs = backtrace((void **)tmp_info, NFRAMES + IGNORE_FRAMES);
     BCOPY(tmp_info+IGNORE_FRAMES, info, (npcs - IGNORE_FRAMES) * sizeof(void *));
     for (i = npcs - IGNORE_FRAMES; i < NFRAMES; ++i) info[i].ci_pc = 0;
   }
   
   #else /* No builtin backtrace; do it ourselves */
   
   #if (defined(OPENBSD) || defined(NETBSD)) && defined(SPARC)
 #  define FR_SAVFP fr_fp  #  define FR_SAVFP fr_fp
 #  define FR_SAVPC fr_pc  #  define FR_SAVPC fr_pc
 #else  #else
Line 2596  struct hblk *h;
Line 3197  struct hblk *h;
 #  define FR_SAVPC fr_savpc  #  define FR_SAVPC fr_savpc
 #endif  #endif
   
   #if defined(SPARC) && (defined(__arch64__) || defined(__sparcv9))
   #   define BIAS 2047
   #else
   #   define BIAS 0
   #endif
   
 void GC_save_callers (info)  void GC_save_callers (info)
 struct callinfo info[NFRAMES];  struct callinfo info[NFRAMES];
 {  {
   struct frame *frame;    struct frame *frame;
   struct frame *fp;    struct frame *fp;
   int nframes = 0;    int nframes = 0;
   word GC_save_regs_in_stack();  # ifdef I386
       /* We assume this is turned on only with gcc as the compiler. */
       asm("movl %%ebp,%0" : "=r"(frame));
       fp = frame;
   # else
       word GC_save_regs_in_stack();
   
   frame = (struct frame *) GC_save_regs_in_stack ();      frame = (struct frame *) GC_save_regs_in_stack ();
       fp = (struct frame *)((long) frame -> FR_SAVFP + BIAS);
   #endif
   
   for (fp = frame -> FR_SAVFP; fp != 0 && nframes < NFRAMES;     for (; (!(fp HOTTER_THAN frame) && !(GC_stackbottom HOTTER_THAN (ptr_t)fp)
        fp = fp -> FR_SAVFP, nframes++) {             && (nframes < NFRAMES));
          fp = (struct frame *)((long) fp -> FR_SAVFP + BIAS), nframes++) {
       register int i;        register int i;
   
       info[nframes].ci_pc = fp->FR_SAVPC;        info[nframes].ci_pc = fp->FR_SAVPC;
       for (i = 0; i < NARGS; i++) {  #     if NARGS > 0
         info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);          for (i = 0; i < NARGS; i++) {
       }            info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
           }
   #     endif /* NARGS > 0 */
   }    }
   if (nframes < NFRAMES) info[nframes].ci_pc = 0;    if (nframes < NFRAMES) info[nframes].ci_pc = 0;
 }  }
   
   #endif /* No builtin backtrace */
   
 #endif /* SAVE_CALL_CHAIN */  #endif /* SAVE_CALL_CHAIN */
 #endif /* SPARC */  
   
   #ifdef NEED_CALLINFO
   
   /* Print info to stderr.  We do NOT hold the allocation lock */
   void GC_print_callers (info)
   struct callinfo info[NFRAMES];
   {
       register int i;
       static int reentry_count = 0;
   
       LOCK();
         ++reentry_count;
       UNLOCK();
   
   #   if NFRAMES == 1
         GC_err_printf0("\tCaller at allocation:\n");
   #   else
         GC_err_printf0("\tCall chain at allocation:\n");
   #   endif
       for (i = 0; i < NFRAMES; i++) {
           if (info[i].ci_pc == 0) break;
   #       if NARGS > 0
           {
             int j;
   
             GC_err_printf0("\t\targs: ");
             for (j = 0; j < NARGS; j++) {
               if (j != 0) GC_err_printf0(", ");
               GC_err_printf2("%d (0x%X)", ~(info[i].ci_arg[j]),
                                           ~(info[i].ci_arg[j]));
             }
             GC_err_printf0("\n");
           }
   #       endif
           if (reentry_count > 1) {
               /* We were called during an allocation during       */
               /* a previous GC_print_callers call; punt.          */
               GC_err_printf1("\t\t##PC##= 0x%lx\n", info[i].ci_pc);
               continue;
           }
           {
   #         ifdef LINUX
               FILE *pipe;
   #         endif
   #         if defined(HAVE_BUILTIN_BACKTRACE) && \
                !defined(BUILTIN_BACKTRACE_BROKEN)
               char **sym_name =
                 backtrace_symbols((void **)(&(info[i].ci_pc)), 1);
               char *name = sym_name[0];
               GC_bool found_it = (strchr(name, '(') != 0);
   #         else
               char buf[40];
               char *name = buf;
               GC_bool fount_it = FALSE:
               sprintf(buf, "##PC##= 0x%lx", info[i].ci_pc);
   #         endif
   #         ifdef LINUX
               if (!found_it) {
   #               define EXE_SZ 100
                   static char exe_name[EXE_SZ];
   #               define CMD_SZ 200
                   char cmd_buf[CMD_SZ];
   #               define RESULT_SZ 200
                   static char result_buf[RESULT_SZ];
                   size_t result_len;
                   static GC_bool found_exe_name = FALSE;
                   static GC_bool will_fail = FALSE;
                   int ret_code;
                   /* Unfortunately, this is the common case for the       */
                   /* main executable.                                     */
                   /* Try to get it via a hairy and expensive scheme.      */
                   /* First we get the name of the executable:             */
                   if (will_fail) goto out;
                   if (!found_exe_name) {
                     ret_code = readlink("/proc/self/exe", exe_name, EXE_SZ);
                     if (ret_code < 0 || ret_code >= EXE_SZ
                         || exe_name[0] != '/') {
                       will_fail = TRUE;   /* Dont try again. */
                       goto out;
                     }
                     exe_name[ret_code] = '\0';
                     found_exe_name = TRUE;
                   }
                   /* Then we use popen to start addr2line -e <exe> <addr> */
                   /* There are faster ways to do this, but hopefully this */
                   /* isn't time critical.                                 */
                   sprintf(cmd_buf, "/usr/bin/addr2line -e %s 0x%lx", exe_name,
                                    (unsigned long)info[i].ci_pc);
                   pipe = popen(cmd_buf, "r");
                   if (pipe < 0 || fgets(result_buf, RESULT_SZ, pipe) == 0) {
                     will_fail = TRUE;
                     goto out;
                   }
                   result_len = strlen(result_buf);
                   if (result_buf[result_len - 1] == '\n') --result_len;
                   if (result_buf[0] == '?'
                       || result_buf[result_len-2] == ':'
                          && result_buf[result_len-1] == '0')
                       goto out;
                   if (result_len < RESULT_SZ - 25) {
                     /* Add in hex address */
                       sprintf(result_buf + result_len, " [0x%lx]",
                             (unsigned long)info[i].ci_pc);
                   }
                   name = result_buf;
                   pclose(pipe);
                   out:
               }
   #         endif /* LINUX */
             GC_err_printf1("\t\t%s\n", name);
             free(sym_name);  /* May call GC_free; that's OK */
           }
       }
       LOCK();
         --reentry_count;
       UNLOCK();
   }
   
   #endif /* NEED_CALLINFO */
   
   #if defined(LINUX) && defined(__ELF__) && \
       (!defined(SMALL_CONFIG) || defined(USE_PROC_FOR_LIBRARIES))
   #ifdef GC_USE_LD_WRAP
   #   define READ __real_read
   #else
   #   define READ read
   #endif
   
   
   /* Repeatedly perform a read call until the buffer is filled or */
   /* we encounter EOF.                                            */
   ssize_t GC_repeat_read(int fd, char *buf, size_t count)
   {
       ssize_t num_read = 0;
       ssize_t result;
   
       while (num_read < count) {
           result = READ(fd, buf + num_read, count - num_read);
           if (result < 0) return result;
           if (result == 0) break;
           num_read += result;
       }
       return num_read;
   }
   #endif /* LINUX && ... */
   
   
   #if defined(LINUX) && defined(__ELF__) && !defined(SMALL_CONFIG)
   
   /* Dump /proc/self/maps to GC_stderr, to enable looking up names for
      addresses in FIND_LEAK output. */
   
   void GC_print_address_map()
   {
       int f;
       int result;
       char maps_temp[32768];
       GC_err_printf0("---------- Begin address map ----------\n");
           f = open("/proc/self/maps", O_RDONLY);
           if (-1 == f) ABORT("Couldn't open /proc/self/maps");
           do {
               result = GC_repeat_read(f, maps_temp, sizeof(maps_temp));
               if (result <= 0) ABORT("Couldn't read /proc/self/maps");
               GC_err_write(maps_temp, result);
           } while (result == sizeof(maps_temp));
   
       GC_err_printf0("---------- End address map ----------\n");
   }
   
   #endif
   
   

Legend:
Removed from v.1.3  
changed lines
  Added in v.1.6

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>