[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.2 and 1.4

version 1.2, 2000/04/10 08:31:31 version 1.4, 2001/04/20 07:39:19
Line 17  static int inside_critical_section;
Line 17  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 48  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 57  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.                                                  */
Line 69  static int inside_critical_section;
Line 74  static int inside_critical_section;
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
 # if (defined(SUNOS4) & defined(DYNAMIC_LOADING)) && !defined(PCR)  # if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
Line 78  static int inside_critical_section;
Line 83  static int inside_critical_section;
 # endif  # endif
   
 # if defined(LINUX) && \  # if defined(LINUX) && \
      (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64))       (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64) \
         || defined(MIPS))
 #   define NEED_FIND_LIMIT  #   define NEED_FIND_LIMIT
 # endif  # endif
   
Line 91  static int inside_critical_section;
Line 97  static int inside_critical_section;
 #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 115  static int inside_critical_section;
Line 120  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
   
Line 128  static int inside_critical_section;
Line 136  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 145  static int inside_critical_section;
Line 153  static int inside_critical_section;
 # define OPT_PROT_EXEC 0  # define OPT_PROT_EXEC 0
 #endif  #endif
   
 #if defined(LINUX) && (defined(POWERPC) || defined(SPARC) || defined(ALPHA) \  #if defined(SEARCH_FOR_DATA_START)
                        || defined(IA64))  
   /* 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 (&__data_start != 0) {
             GC_data_start = (ptr_t)(&__data_start);
             return;
         }
         if (&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
   
   #if defined(NETBSD) && 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 267  void GC_enable_signals(void)
Line 305  void GC_enable_signals(void)
 # else  # else
   
 #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \  #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
         && !defined(MSWINCE) \
       && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)        && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)
   
 #   if defined(sigmask) && !defined(UTS4)  #   if defined(sigmask) && !defined(UTS4)
Line 366  void GC_enable_signals()
Line 405  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 397  word GC_page_size;
Line 434  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 434  ptr_t GC_get_stack_base()
Line 471  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 450  ptr_t GC_get_stack_base()
Line 497  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
Line 527  ptr_t GC_get_stack_base()
Line 522  ptr_t GC_get_stack_base()
         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)
           struct sigaction      act;            struct sigaction      act;
   
           act.sa_handler        = GC_fault_handler;            act.sa_handler        = h;
           act.sa_flags          = SA_RESTART | SA_NODEFER;            act.sa_flags          = SA_RESTART | SA_NODEFER;
           /* 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     */
Line 557  ptr_t GC_get_stack_base()
Line 557  ptr_t GC_get_stack_base()
 #               endif  #               endif
 #         endif /* IRIX_THREADS */  #         endif /* 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)
Line 616  ptr_t GC_get_stack_base()
Line 634  ptr_t GC_get_stack_base()
   
 #ifdef LINUX_STACKBOTTOM  #ifdef LINUX_STACKBOTTOM
   
   #include <sys/types.h>
   #include <sys/stat.h>
   
 # define STAT_SKIP 27   /* Number of fields preceding startstack        */  # define STAT_SKIP 27   /* Number of fields preceding startstack        */
                         /* field in /proc/<pid>/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) {
           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)
   {    {
     char buf[50];      /* We read the stack base value from /proc/self/stat.  We do this   */
     FILE *f;      /* using direct I/O system calls in order to avoid calling malloc   */
       /* in case REDIRECT_MALLOC is defined.                              */
   #   define STAT_BUF_SIZE 4096
   #   if defined(GC_USE_LD_WRAP)
   #       define STAT_READ __real_read
   #   else
   #       define STAT_READ read
   #   endif
       char stat_buf[STAT_BUF_SIZE];
       int f;
     char c;      char c;
     word result = 0;      word result = 0;
     int i;      size_t i, buf_offset = 0;
   
     sprintf(buf, "/proc/%d/stat", getpid());      /* First try the easy way.  This should work for glibc 2.2  */
     f = fopen(buf, "r");        if (0 != &__libc_stack_end) {
     if (NULL == f) ABORT("Couldn't open /proc/<pid>/stat");          return __libc_stack_end;
     c = getc(f);        }
       f = open("/proc/self/stat", O_RDONLY);
       if (f < 0 || STAT_READ(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
           ABORT("Couldn't read /proc/self/stat");
       }
       c = stat_buf[buf_offset++];
     /* Skip the required number of fields.  This number is hopefully    */      /* Skip the required number of fields.  This number is hopefully    */
     /* constant across all Linux implementations.                       */      /* constant across all Linux implementations.                       */
       for (i = 0; i < STAT_SKIP; ++i) {        for (i = 0; i < STAT_SKIP; ++i) {
         while (isspace(c)) c = getc(f);          while (isspace(c)) c = stat_buf[buf_offset++];
         while (!isspace(c)) c = getc(f);          while (!isspace(c)) c = stat_buf[buf_offset++];
       }        }
     while (isspace(c)) c = getc(f);      while (isspace(c)) c = stat_buf[buf_offset++];
     while (isdigit(c)) {      while (isdigit(c)) {
       result *= 10;        result *= 10;
       result += c - '0';        result += c - '0';
       c = getc(f);        c = stat_buf[buf_offset++];
     }      }
       close(f);
     if (result < 0x10000000) ABORT("Absurd stack bottom value");      if (result < 0x10000000) ABORT("Absurd stack bottom value");
     return (ptr_t)result;      return (ptr_t)result;
   }    }
   
 #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}, base, len, r;
   
       len = sizeof(int);
       r = sysctl(nm, 2, &base, &len, NULL, 0);
   
       if (r) ABORT("Error getting stack base");
   
       return (ptr_t)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 672  ptr_t GC_get_stack_base()
Line 754  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 699  ptr_t GC_get_stack_base()
Line 784  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 801  void GC_register_data_segments()
Line 884  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,   */
Line 825  void GC_register_data_segments()
Line 910  void GC_register_data_segments()
   {    {
       GC_win32s = GC_is_win32s();        GC_win32s = GC_is_win32s();
   }    }
   
   /* 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 850  void GC_register_data_segments()
Line 933  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 863  void GC_register_data_segments()
Line 947  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 877  void GC_register_data_segments()
Line 965  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;
Line 890  void GC_register_data_segments()
Line 978  void GC_register_data_segments()
   
       if (!GC_win32s) return;        if (!GC_win32s) 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 912  void GC_register_data_segments()
Line 999  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 1068  int * etext_addr;
Line 1046  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) \
Line 1127  void GC_register_data_segments()
Line 1113  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 1146  void GC_register_data_segments()
Line 1133  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 1178  word bytes;
Line 1166  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 1188  word bytes;
Line 1176  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 1206  word bytes;
Line 1198  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 1259  void * os2_alloc(size_t bytes)
Line 1263  void * os2_alloc(size_t bytes)
 # endif /* OS2 */  # endif /* OS2 */
   
   
   # if defined(MSWIN32) || defined(MSWINCE)
   SYSTEM_INFO GC_sysinfo;
   # endif
   
   
 # ifdef MSWIN32  # ifdef MSWIN32
 word GC_n_heap_bases = 0;  word GC_n_heap_bases = 0;
   
Line 1266  ptr_t GC_win32_get_mem(bytes)
Line 1275  ptr_t GC_win32_get_mem(bytes)
 word bytes;  word bytes;
 {  {
     ptr_t result;      ptr_t result;
   
     if (GC_win32s) {      if (GC_win32s) {
         /* 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           */
Line 1295  void GC_win32_free_heap ()
Line 1304  void GC_win32_free_heap ()
         }          }
     }      }
 }  }
   # 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);
           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 1332  ptr_t GC_unmap_end(ptr_t start, word bytes)
Line 1402  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 1341  void GC_unmap(ptr_t start, word bytes)
Line 1419  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 1354  void GC_remap(ptr_t start, word bytes)
Line 1448  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 1382  void GC_unmap_gap(ptr_t start1, word bytes1, ptr_t sta
Line 1497  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 1418  PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any
Line 1548  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 1446  void GC_default_push_other_roots()
Line 1576  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 1463  int dummy3;
Line 1597  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 1505  void GC_default_push_other_roots()
Line 1621  void GC_default_push_other_roots()
   
 # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \  # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
      || defined(IRIX_THREADS) || defined(LINUX_THREADS) \       || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
      || defined(IRIX_JDK_THREADS) || defined(HPUX_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 /* SOLARIS_THREADS || ... */
   
 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
   
 /*  /*
  * 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 1625  struct hblk *h;
Line 1741  struct hblk *h;
  * not to work under a number of other systems.   * 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 1644  struct hblk *h;
Line 1760  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 1665  struct hblk *h;
Line 1783  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)
 # ifdef __STDC__  # ifdef __STDC__
     typedef void (* SIG_PF)(int);      typedef void (* SIG_PF)(int);
 # else  # else
Line 1677  struct hblk *h;
Line 1795  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)
     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);      typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
Line 1703  struct hblk *h;
Line 1826  struct hblk *h;
 #   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 1724  struct hblk *h;
Line 1847  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 1759  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2057  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #   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)          void GC_write_fault_handler(int sig, s_c sc)
Line 1792  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2090  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
Line 1817  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2122  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 1829  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2134  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 1842  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2151  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 */
                 /* Linux 2.3.47 and later.  Hopefully we don't have to    */
                 /* worry about earlier kernels on IA64.                   */
 #           else  #           else
 #             if defined(POWERPC)  #             if defined(POWERPC)
                 char * addr = (char *) (sc.regs->dar);                  char * addr = (char *) (sc.regs->dar);
Line 1855  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2167  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #       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 1887  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2202  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 1906  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2221  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 1918  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2233  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
                     (*(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
Line 1926  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2244  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
         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);          UNPROTECT(h, GC_page_size);
 #       if defined(OSF1) || defined(LINUX)  #       if defined(OSF1) || defined(LINUX)
Line 1935  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
Line 2253  SIG_PF GC_old_segv_handler; /* Also old MSWIN32 ACCESS
 #       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 1968  struct hblk *h;
Line 2286  struct hblk *h;
   
         if (!get_pht_entry_from_index(GC_dirty_pages, index)) {          if (!get_pht_entry_from_index(GC_dirty_pages, index)) {
             found_clean = TRUE;              found_clean = TRUE;
             set_pht_entry_from_index(GC_dirty_pages, index);              async_set_pht_entry_from_index(GC_dirty_pages, index);
         }          }
     }      }
     if (found_clean) {      if (found_clean) {
Line 1978  struct hblk *h;
Line 2296  struct hblk *h;
   
 void GC_dirty_init()  void GC_dirty_init()
 {  {
 #if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */  #   if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */
     struct sigaction    act, oldact;        struct sigaction  act, oldact;
 #   ifdef IRIX5  #     ifdef IRIX5
         act.sa_flags    = SA_RESTART;          act.sa_flags    = SA_RESTART;
         act.sa_handler  = GC_write_fault_handler;          act.sa_handler  = 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);
   #    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 2022  void GC_dirty_init()
Line 2347  void GC_dirty_init()
       }        }
 #   endif  #   endif
 #   if defined(SUNOS5SIGS) || defined(IRIX5)  #   if defined(SUNOS5SIGS) || defined(IRIX5)
 #     if defined(IRIX_THREADS) || defined(IRIX_JDK_THREADS)  #     if defined(IRIX_THREADS)
         sigaction(SIGSEGV, 0, &oldact);          sigaction(SIGSEGV, 0, &oldact);
         sigaction(SIGSEGV, &act, 0);          sigaction(SIGSEGV, &act, 0);
 #     else  #     else
Line 2048  void GC_dirty_init()
Line 2373  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)
           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 */
 #   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 2110  struct hblk * h;
Line 2439  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 2142  word len;
Line 2479  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);
 }  }
   
 #ifndef MSWIN32  #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(LINUX_THREADS) \
       && !defined(GC_USE_LD_WRAP)
 /* Replacement for UNIX system call.     */  /* Replacement for UNIX system call.     */
 /* Other calls that write to the heap    */  /* Other calls that write to the heap    */
 /* should be handled similarly.          */  /* should be handled similarly.          */
 # if defined(__STDC__) && !defined(SUNOS4)  # if defined(__STDC__) && !defined(SUNOS4)
 #   include <unistd.h>  #   include <unistd.h>
   #   include <sys/uio.h>
     ssize_t read(int fd, void *buf, size_t nbyte)      ssize_t read(int fd, void *buf, size_t nbyte)
 # else  # else
 #   ifndef LINT  #   ifndef LINT
Line 2170  word len;
Line 2509  word len;
   
     GC_begin_syscall();      GC_begin_syscall();
     GC_unprotect_range(buf, (word)nbyte);      GC_unprotect_range(buf, (word)nbyte);
 #   ifdef IRIX5  #   if defined(IRIX5) || defined(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.                             */
           /* On Linux, we have to be careful with the linuxthreads        */
           /* read interception.                                           */
         {          {
             struct iovec iov;              struct iovec iov;
   
Line 2182  word len;
Line 2523  word len;
             result = readv(fd, &iov, 1);              result = readv(fd, &iov, 1);
         }          }
 #   else  #   else
         result = syscall(SYS_read, fd, buf, nbyte);          /* 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  #   endif
     GC_end_syscall();      GC_end_syscall();
     return(result);      return(result);
 }  }
 #endif /* !MSWIN32 */  #endif /* !MSWIN32 && !MSWINCE && !LINUX_THREADS */
   
   #ifdef GC_USE_LD_WRAP
       /* We use the GNU ld call wrapping facility.                        */
       /* This requires that the linker be invoked with "--wrap read".     */
       /* This can be done by passing -Wl,"--wrap read" to gcc.            */
       /* I'm not sure that this actually wraps whatever version of read   */
       /* is called by stdio.  That code also mentions __read.             */
   #   include <unistd.h>
       ssize_t __wrap_read(int fd, void *buf, size_t nbyte)
       {
           int result;
   
           GC_begin_syscall();
           GC_unprotect_range(buf, (word)nbyte);
           result = __real_read(fd, buf, nbyte);
           GC_end_syscall();
           return(result);
       }
   
       /* We should probably also do this for __read, or whatever stdio    */
       /* actually calls.                                                  */
   #endif
   
 /*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 2204  word n;
Line 2570  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 2226  word n;
Line 2599  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;
Line 2522  struct hblk *h;
Line 2894  struct hblk *h;
  * 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>      struct frame {
 #     else          struct frame *fr_savfp;
 #        if defined(OPENBSD)          long    fr_savpc;
 #          include <frame.h>          long    fr_arg[NARGS];  /* All the arguments go here.   */
 #        else      };
 #          include <sys/frame.h>  #endif
 #        endif  
 #     endif  #if defined(SPARC)
 #   endif  #  if defined(LINUX)
 #   if NARGS > 6       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 SAVE_CALL_CHAIN
 /* 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  #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 2552  struct hblk *h;
Line 2951  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;
Line 2575  struct callinfo info[NFRAMES];
Line 2988  struct callinfo info[NFRAMES];
 }  }
   
 #endif /* SAVE_CALL_CHAIN */  #endif /* SAVE_CALL_CHAIN */
 #endif /* SPARC */  
   
   #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.2  
changed lines
  Added in v.1.4

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