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

Annotation of OpenXM_contrib/gc/os_dep.c, Revision 1.1

1.1     ! maekawa     1: /*
        !             2:  * Copyright (c) 1991-1995 by Xerox Corporation.  All rights reserved.
        !             3:  * Copyright (c) 1996-1997 by Silicon Graphics.  All rights reserved.
        !             4:  *
        !             5:  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
        !             6:  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
        !             7:  *
        !             8:  * Permission is hereby granted to use or copy this program
        !             9:  * for any purpose,  provided the above notices are retained on all copies.
        !            10:  * Permission to modify the code and to distribute modified code is granted,
        !            11:  * provided the above notices are retained, and a notice that the code was
        !            12:  * modified is included with the above copyright notice.
        !            13:  */
        !            14:
        !            15: # include "gc_priv.h"
        !            16:
        !            17: # if defined(LINUX) && !defined(POWERPC)
        !            18: #   include <linux/version.h>
        !            19: #   if (LINUX_VERSION_CODE <= 0x10400)
        !            20:       /* Ugly hack to get struct sigcontext_struct definition.  Required      */
        !            21:       /* for some early 1.3.X releases.  Will hopefully go away soon. */
        !            22:       /* in some later Linux releases, asm/sigcontext.h may have to   */
        !            23:       /* be included instead.                                         */
        !            24: #     define __KERNEL__
        !            25: #     include <asm/signal.h>
        !            26: #     undef __KERNEL__
        !            27: #   else
        !            28:       /* Kernels prior to 2.1.1 defined struct sigcontext_struct instead of */
        !            29:       /* struct sigcontext.  libc6 (glibc2) uses "struct sigcontext" in     */
        !            30:       /* prototypes, so we have to include the top-level sigcontext.h to    */
        !            31:       /* make sure the former gets defined to be the latter if appropriate. */
        !            32: #     include <features.h>
        !            33: #     if 2 <= __GLIBC__
        !            34: #       if 0 == __GLIBC_MINOR__
        !            35:          /* glibc 2.1 no longer has sigcontext.h.  But signal.h        */
        !            36:          /* has the right declaration for glibc 2.1.                   */
        !            37: #         include <sigcontext.h>
        !            38: #       endif /* 0 == __GLIBC_MINOR__ */
        !            39: #     else /* not 2 <= __GLIBC__ */
        !            40:         /* libc5 doesn't have <sigcontext.h>: go directly with the kernel   */
        !            41:         /* one.  Check LINUX_VERSION_CODE to see which we should reference. */
        !            42: #       include <asm/sigcontext.h>
        !            43: #     endif /* 2 <= __GLIBC__ */
        !            44: #   endif
        !            45: # endif
        !            46: # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) && !defined(MACOS)
        !            47: #   include <sys/types.h>
        !            48: #   if !defined(MSWIN32) && !defined(SUNOS4)
        !            49: #      include <unistd.h>
        !            50: #   endif
        !            51: # endif
        !            52:
        !            53: # include <stdio.h>
        !            54: # include <signal.h>
        !            55:
        !            56: /* Blatantly OS dependent routines, except for those that are related  */
        !            57: /* dynamic loading.                                                    */
        !            58:
        !            59: # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
        !            60: #   define NEED_FIND_LIMIT
        !            61: # endif
        !            62:
        !            63: # if defined(IRIX_THREADS)
        !            64: #   define NEED_FIND_LIMIT
        !            65: # endif
        !            66:
        !            67: # if (defined(SUNOS4) & defined(DYNAMIC_LOADING)) && !defined(PCR)
        !            68: #   define NEED_FIND_LIMIT
        !            69: # endif
        !            70:
        !            71: # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)
        !            72: #   define NEED_FIND_LIMIT
        !            73: # endif
        !            74:
        !            75: # if defined(LINUX) && (defined(POWERPC) || defined(SPARC))
        !            76: #   define NEED_FIND_LIMIT
        !            77: # endif
        !            78:
        !            79: #ifdef NEED_FIND_LIMIT
        !            80: #   include <setjmp.h>
        !            81: #endif
        !            82:
        !            83: #ifdef FREEBSD
        !            84: #  include <machine/trap.h>
        !            85: #endif
        !            86:
        !            87: #ifdef AMIGA
        !            88: # include <proto/exec.h>
        !            89: # include <proto/dos.h>
        !            90: # include <dos/dosextens.h>
        !            91: # include <workbench/startup.h>
        !            92: #endif
        !            93:
        !            94: #ifdef MSWIN32
        !            95: # define WIN32_LEAN_AND_MEAN
        !            96: # define NOSERVICE
        !            97: # include <windows.h>
        !            98: #endif
        !            99:
        !           100: #ifdef MACOS
        !           101: # include <Processes.h>
        !           102: #endif
        !           103:
        !           104: #ifdef IRIX5
        !           105: # include <sys/uio.h>
        !           106: # include <malloc.h>   /* for locking */
        !           107: #endif
        !           108: #ifdef USE_MMAP
        !           109: # include <sys/types.h>
        !           110: # include <sys/mman.h>
        !           111: # include <sys/stat.h>
        !           112: # include <fcntl.h>
        !           113: #endif
        !           114:
        !           115: #ifdef SUNOS5SIGS
        !           116: # include <sys/siginfo.h>
        !           117: # undef setjmp
        !           118: # undef longjmp
        !           119: # define setjmp(env) sigsetjmp(env, 1)
        !           120: # define longjmp(env, val) siglongjmp(env, val)
        !           121: # define jmp_buf sigjmp_buf
        !           122: #endif
        !           123:
        !           124: #ifdef DJGPP
        !           125:   /* Apparently necessary for djgpp 2.01.  May casuse problems with    */
        !           126:   /* other versions.                                                   */
        !           127:   typedef long unsigned int caddr_t;
        !           128: #endif
        !           129:
        !           130: #ifdef PCR
        !           131: # include "il/PCR_IL.h"
        !           132: # include "th/PCR_ThCtl.h"
        !           133: # include "mm/PCR_MM.h"
        !           134: #endif
        !           135:
        !           136: #if !defined(NO_EXECUTE_PERMISSION)
        !           137: # define OPT_PROT_EXEC PROT_EXEC
        !           138: #else
        !           139: # define OPT_PROT_EXEC 0
        !           140: #endif
        !           141:
        !           142: #if defined(LINUX) && defined(POWERPC)
        !           143:   ptr_t GC_data_start;
        !           144:
        !           145:   void GC_init_linuxppc()
        !           146:   {
        !           147:     extern ptr_t GC_find_limit();
        !           148:     extern char **_environ;
        !           149:        /* This may need to be environ, without the underscore, for     */
        !           150:        /* some versions.                                               */
        !           151:     GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE);
        !           152:   }
        !           153: #endif
        !           154:
        !           155: #if defined(LINUX) && defined(SPARC)
        !           156:   ptr_t GC_data_start;
        !           157:
        !           158:   void GC_init_linuxsparc()
        !           159:   {
        !           160:     extern ptr_t GC_find_limit();
        !           161:     extern char **_environ;
        !           162:       /* This may need to be environ, without the underscore, for     */
        !           163:       /* some versions.                                               */
        !           164:     GC_data_start = GC_find_limit((ptr_t)&_environ, FALSE);
        !           165:   }
        !           166: #endif
        !           167:
        !           168: # ifdef OS2
        !           169:
        !           170: # include <stddef.h>
        !           171:
        !           172: # if !defined(__IBMC__) && !defined(__WATCOMC__) /* e.g. EMX */
        !           173:
        !           174: struct exe_hdr {
        !           175:     unsigned short      magic_number;
        !           176:     unsigned short      padding[29];
        !           177:     long                new_exe_offset;
        !           178: };
        !           179:
        !           180: #define E_MAGIC(x)      (x).magic_number
        !           181: #define EMAGIC          0x5A4D
        !           182: #define E_LFANEW(x)     (x).new_exe_offset
        !           183:
        !           184: struct e32_exe {
        !           185:     unsigned char       magic_number[2];
        !           186:     unsigned char       byte_order;
        !           187:     unsigned char       word_order;
        !           188:     unsigned long       exe_format_level;
        !           189:     unsigned short      cpu;
        !           190:     unsigned short      os;
        !           191:     unsigned long       padding1[13];
        !           192:     unsigned long       object_table_offset;
        !           193:     unsigned long       object_count;
        !           194:     unsigned long       padding2[31];
        !           195: };
        !           196:
        !           197: #define E32_MAGIC1(x)   (x).magic_number[0]
        !           198: #define E32MAGIC1       'L'
        !           199: #define E32_MAGIC2(x)   (x).magic_number[1]
        !           200: #define E32MAGIC2       'X'
        !           201: #define E32_BORDER(x)   (x).byte_order
        !           202: #define E32LEBO         0
        !           203: #define E32_WORDER(x)   (x).word_order
        !           204: #define E32LEWO         0
        !           205: #define E32_CPU(x)      (x).cpu
        !           206: #define E32CPU286       1
        !           207: #define E32_OBJTAB(x)   (x).object_table_offset
        !           208: #define E32_OBJCNT(x)   (x).object_count
        !           209:
        !           210: struct o32_obj {
        !           211:     unsigned long       size;
        !           212:     unsigned long       base;
        !           213:     unsigned long       flags;
        !           214:     unsigned long       pagemap;
        !           215:     unsigned long       mapsize;
        !           216:     unsigned long       reserved;
        !           217: };
        !           218:
        !           219: #define O32_FLAGS(x)    (x).flags
        !           220: #define OBJREAD         0x0001L
        !           221: #define OBJWRITE        0x0002L
        !           222: #define OBJINVALID      0x0080L
        !           223: #define O32_SIZE(x)     (x).size
        !           224: #define O32_BASE(x)     (x).base
        !           225:
        !           226: # else  /* IBM's compiler */
        !           227:
        !           228: /* A kludge to get around what appears to be a header file bug */
        !           229: # ifndef WORD
        !           230: #   define WORD unsigned short
        !           231: # endif
        !           232: # ifndef DWORD
        !           233: #   define DWORD unsigned long
        !           234: # endif
        !           235:
        !           236: # define EXE386 1
        !           237: # include <newexe.h>
        !           238: # include <exe386.h>
        !           239:
        !           240: # endif  /* __IBMC__ */
        !           241:
        !           242: # define INCL_DOSEXCEPTIONS
        !           243: # define INCL_DOSPROCESS
        !           244: # define INCL_DOSERRORS
        !           245: # define INCL_DOSMODULEMGR
        !           246: # define INCL_DOSMEMMGR
        !           247: # include <os2.h>
        !           248:
        !           249:
        !           250: /* Disable and enable signals during nontrivial allocations    */
        !           251:
        !           252: void GC_disable_signals(void)
        !           253: {
        !           254:     ULONG nest;
        !           255:
        !           256:     DosEnterMustComplete(&nest);
        !           257:     if (nest != 1) ABORT("nested GC_disable_signals");
        !           258: }
        !           259:
        !           260: void GC_enable_signals(void)
        !           261: {
        !           262:     ULONG nest;
        !           263:
        !           264:     DosExitMustComplete(&nest);
        !           265:     if (nest != 0) ABORT("GC_enable_signals");
        !           266: }
        !           267:
        !           268:
        !           269: # else
        !           270:
        !           271: #  if !defined(PCR) && !defined(AMIGA) && !defined(MSWIN32) \
        !           272:       && !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)
        !           273:
        !           274: #   if defined(sigmask) && !defined(UTS4)
        !           275:        /* Use the traditional BSD interface */
        !           276: #      define SIGSET_T int
        !           277: #      define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
        !           278: #      define SIG_FILL(set)  (set) = 0x7fffffff
        !           279:          /* Setting the leading bit appears to provoke a bug in some   */
        !           280:          /* longjmp implementations.  Most systems appear not to have  */
        !           281:          /* a signal 32.                                               */
        !           282: #      define SIGSETMASK(old, new) (old) = sigsetmask(new)
        !           283: #   else
        !           284:        /* Use POSIX/SYSV interface     */
        !           285: #      define SIGSET_T sigset_t
        !           286: #      define SIG_DEL(set, signal) sigdelset(&(set), (signal))
        !           287: #      define SIG_FILL(set) sigfillset(&set)
        !           288: #      define SIGSETMASK(old, new) sigprocmask(SIG_SETMASK, &(new), &(old))
        !           289: #   endif
        !           290:
        !           291: static GC_bool mask_initialized = FALSE;
        !           292:
        !           293: static SIGSET_T new_mask;
        !           294:
        !           295: static SIGSET_T old_mask;
        !           296:
        !           297: static SIGSET_T dummy;
        !           298:
        !           299: #if defined(PRINTSTATS) && !defined(THREADS)
        !           300: # define CHECK_SIGNALS
        !           301:   int GC_sig_disabled = 0;
        !           302: #endif
        !           303:
        !           304: void GC_disable_signals()
        !           305: {
        !           306:     if (!mask_initialized) {
        !           307:        SIG_FILL(new_mask);
        !           308:
        !           309:        SIG_DEL(new_mask, SIGSEGV);
        !           310:        SIG_DEL(new_mask, SIGILL);
        !           311:        SIG_DEL(new_mask, SIGQUIT);
        !           312: #      ifdef SIGBUS
        !           313:            SIG_DEL(new_mask, SIGBUS);
        !           314: #      endif
        !           315: #      ifdef SIGIOT
        !           316:            SIG_DEL(new_mask, SIGIOT);
        !           317: #      endif
        !           318: #      ifdef SIGEMT
        !           319:            SIG_DEL(new_mask, SIGEMT);
        !           320: #      endif
        !           321: #      ifdef SIGTRAP
        !           322:            SIG_DEL(new_mask, SIGTRAP);
        !           323: #      endif
        !           324:        mask_initialized = TRUE;
        !           325:     }
        !           326: #   ifdef CHECK_SIGNALS
        !           327:        if (GC_sig_disabled != 0) ABORT("Nested disables");
        !           328:        GC_sig_disabled++;
        !           329: #   endif
        !           330:     SIGSETMASK(old_mask,new_mask);
        !           331: }
        !           332:
        !           333: void GC_enable_signals()
        !           334: {
        !           335: #   ifdef CHECK_SIGNALS
        !           336:        if (GC_sig_disabled != 1) ABORT("Unmatched enable");
        !           337:        GC_sig_disabled--;
        !           338: #   endif
        !           339:     SIGSETMASK(dummy,old_mask);
        !           340: }
        !           341:
        !           342: #  endif  /* !PCR */
        !           343:
        !           344: # endif /*!OS/2 */
        !           345:
        !           346: /* Ivan Demakov: simplest way (to me) */
        !           347: #ifdef DOS4GW
        !           348:   void GC_disable_signals() { }
        !           349:   void GC_enable_signals() { }
        !           350: #endif
        !           351:
        !           352: /* Find the page size */
        !           353: word GC_page_size;
        !           354:
        !           355: # ifdef MSWIN32
        !           356:   void GC_setpagesize()
        !           357:   {
        !           358:     SYSTEM_INFO sysinfo;
        !           359:
        !           360:     GetSystemInfo(&sysinfo);
        !           361:     GC_page_size = sysinfo.dwPageSize;
        !           362:   }
        !           363:
        !           364: # else
        !           365: #   if defined(MPROTECT_VDB) || defined(PROC_VDB) || defined(USE_MMAP)
        !           366:        void GC_setpagesize()
        !           367:        {
        !           368:            GC_page_size = GETPAGESIZE();
        !           369:        }
        !           370: #   else
        !           371:        /* It's acceptable to fake it. */
        !           372:        void GC_setpagesize()
        !           373:        {
        !           374:            GC_page_size = HBLKSIZE;
        !           375:        }
        !           376: #   endif
        !           377: # endif
        !           378:
        !           379: /*
        !           380:  * Find the base of the stack.
        !           381:  * Used only in single-threaded environment.
        !           382:  * With threads, GC_mark_roots needs to know how to do this.
        !           383:  * Called with allocator lock held.
        !           384:  */
        !           385: # ifdef MSWIN32
        !           386: # define is_writable(prot) ((prot) == PAGE_READWRITE \
        !           387:                            || (prot) == PAGE_WRITECOPY \
        !           388:                            || (prot) == PAGE_EXECUTE_READWRITE \
        !           389:                            || (prot) == PAGE_EXECUTE_WRITECOPY)
        !           390: /* Return the number of bytes that are writable starting at p. */
        !           391: /* The pointer p is assumed to be page aligned.                        */
        !           392: /* If base is not 0, *base becomes the beginning of the        */
        !           393: /* allocation region containing p.                             */
        !           394: word GC_get_writable_length(ptr_t p, ptr_t *base)
        !           395: {
        !           396:     MEMORY_BASIC_INFORMATION buf;
        !           397:     word result;
        !           398:     word protect;
        !           399:
        !           400:     result = VirtualQuery(p, &buf, sizeof(buf));
        !           401:     if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
        !           402:     if (base != 0) *base = (ptr_t)(buf.AllocationBase);
        !           403:     protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
        !           404:     if (!is_writable(protect)) {
        !           405:         return(0);
        !           406:     }
        !           407:     if (buf.State != MEM_COMMIT) return(0);
        !           408:     return(buf.RegionSize);
        !           409: }
        !           410:
        !           411: ptr_t GC_get_stack_base()
        !           412: {
        !           413:     int dummy;
        !           414:     ptr_t sp = (ptr_t)(&dummy);
        !           415:     ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
        !           416:     word size = GC_get_writable_length(trunc_sp, 0);
        !           417:
        !           418:     return(trunc_sp + size);
        !           419: }
        !           420:
        !           421:
        !           422: # else
        !           423:
        !           424: # ifdef OS2
        !           425:
        !           426: ptr_t GC_get_stack_base()
        !           427: {
        !           428:     PTIB ptib;
        !           429:     PPIB ppib;
        !           430:
        !           431:     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
        !           432:        GC_err_printf0("DosGetInfoBlocks failed\n");
        !           433:        ABORT("DosGetInfoBlocks failed\n");
        !           434:     }
        !           435:     return((ptr_t)(ptib -> tib_pstacklimit));
        !           436: }
        !           437:
        !           438: # else
        !           439:
        !           440: # ifdef AMIGA
        !           441:
        !           442: ptr_t GC_get_stack_base()
        !           443: {
        !           444:     extern struct WBStartup *_WBenchMsg;
        !           445:     extern long __base;
        !           446:     extern long __stack;
        !           447:     struct Task *task;
        !           448:     struct Process *proc;
        !           449:     struct CommandLineInterface *cli;
        !           450:     long size;
        !           451:
        !           452:     if ((task = FindTask(0)) == 0) {
        !           453:        GC_err_puts("Cannot find own task structure\n");
        !           454:        ABORT("task missing");
        !           455:     }
        !           456:     proc = (struct Process *)task;
        !           457:     cli = BADDR(proc->pr_CLI);
        !           458:
        !           459:     if (_WBenchMsg != 0 || cli == 0) {
        !           460:        size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;
        !           461:     } else {
        !           462:        size = cli->cli_DefaultStack * 4;
        !           463:     }
        !           464:     return (ptr_t)(__base + GC_max(size, __stack));
        !           465: }
        !           466:
        !           467: # else
        !           468:
        !           469:
        !           470:
        !           471: # ifdef NEED_FIND_LIMIT
        !           472:   /* Some tools to implement HEURISTIC2        */
        !           473: #   define MIN_PAGE_SIZE 256   /* Smallest conceivable page size, bytes */
        !           474:     /* static */ jmp_buf GC_jmp_buf;
        !           475:
        !           476:     /*ARGSUSED*/
        !           477:     void GC_fault_handler(sig)
        !           478:     int sig;
        !           479:     {
        !           480:         longjmp(GC_jmp_buf, 1);
        !           481:     }
        !           482:
        !           483: #   ifdef __STDC__
        !           484:        typedef void (*handler)(int);
        !           485: #   else
        !           486:        typedef void (*handler)();
        !           487: #   endif
        !           488:
        !           489: #   if defined(SUNOS5SIGS) || defined(IRIX5)
        !           490:        static struct sigaction old_segv_act;
        !           491: #      if defined(_sigargs) /* !Irix6.x */
        !           492:            static struct sigaction old_bus_act;
        !           493: #      endif
        !           494: #   else
        !           495:         static handler old_segv_handler, old_bus_handler;
        !           496: #   endif
        !           497:
        !           498:     void GC_setup_temporary_fault_handler()
        !           499:     {
        !           500: #      if defined(SUNOS5SIGS) || defined(IRIX5)
        !           501:          struct sigaction      act;
        !           502:
        !           503:          act.sa_handler        = GC_fault_handler;
        !           504:           act.sa_flags          = SA_RESTART | SA_NODEFER;
        !           505:           /* The presence of SA_NODEFER represents yet another gross    */
        !           506:           /* hack.  Under Solaris 2.3, siglongjmp doesn't appear to     */
        !           507:           /* interact correctly with -lthread.  We hide the confusion   */
        !           508:           /* by making sure that signal handling doesn't affect the     */
        !           509:           /* signal mask.                                               */
        !           510:
        !           511:          (void) sigemptyset(&act.sa_mask);
        !           512: #        ifdef IRIX_THREADS
        !           513:                /* Older versions have a bug related to retrieving and  */
        !           514:                /* and setting a handler at the same time.              */
        !           515:                (void) sigaction(SIGSEGV, 0, &old_segv_act);
        !           516:                (void) sigaction(SIGSEGV, &act, 0);
        !           517: #        else
        !           518:                (void) sigaction(SIGSEGV, &act, &old_segv_act);
        !           519: #              ifdef _sigargs  /* Irix 5.x, not 6.x */
        !           520:                    /* Under 5.x, we may get SIGBUS.                    */
        !           521:                    /* Pthreads doesn't exist under 5.x, so we don't    */
        !           522:                    /* have to worry in the threads case.               */
        !           523:                    (void) sigaction(SIGBUS, &act, &old_bus_act);
        !           524: #              endif
        !           525: #        endif /* IRIX_THREADS */
        !           526: #      else
        !           527:          old_segv_handler = signal(SIGSEGV, GC_fault_handler);
        !           528: #        ifdef SIGBUS
        !           529:            old_bus_handler = signal(SIGBUS, GC_fault_handler);
        !           530: #        endif
        !           531: #      endif
        !           532:     }
        !           533:
        !           534:     void GC_reset_fault_handler()
        !           535:     {
        !           536: #       if defined(SUNOS5SIGS) || defined(IRIX5)
        !           537:          (void) sigaction(SIGSEGV, &old_segv_act, 0);
        !           538: #        ifdef _sigargs        /* Irix 5.x, not 6.x */
        !           539:              (void) sigaction(SIGBUS, &old_bus_act, 0);
        !           540: #        endif
        !           541: #       else
        !           542:          (void) signal(SIGSEGV, old_segv_handler);
        !           543: #        ifdef SIGBUS
        !           544:            (void) signal(SIGBUS, old_bus_handler);
        !           545: #        endif
        !           546: #       endif
        !           547:     }
        !           548:
        !           549:     /* Return the first nonaddressible location > p (up) or    */
        !           550:     /* the smallest location q s.t. [q,p] is addressible (!up).        */
        !           551:     ptr_t GC_find_limit(p, up)
        !           552:     ptr_t p;
        !           553:     GC_bool up;
        !           554:     {
        !           555:         static VOLATILE ptr_t result;
        !           556:                /* Needs to be static, since otherwise it may not be    */
        !           557:                /* preserved across the longjmp.  Can safely be         */
        !           558:                /* static since it's only called once, with the         */
        !           559:                /* allocation lock held.                                */
        !           560:
        !           561:
        !           562:        GC_setup_temporary_fault_handler();
        !           563:        if (setjmp(GC_jmp_buf) == 0) {
        !           564:            result = (ptr_t)(((word)(p))
        !           565:                              & ~(MIN_PAGE_SIZE-1));
        !           566:            for (;;) {
        !           567:                if (up) {
        !           568:                    result += MIN_PAGE_SIZE;
        !           569:                } else {
        !           570:                    result -= MIN_PAGE_SIZE;
        !           571:                }
        !           572:                GC_noop1((word)(*result));
        !           573:            }
        !           574:        }
        !           575:        GC_reset_fault_handler();
        !           576:        if (!up) {
        !           577:            result += MIN_PAGE_SIZE;
        !           578:        }
        !           579:        return(result);
        !           580:     }
        !           581: # endif
        !           582:
        !           583:
        !           584: ptr_t GC_get_stack_base()
        !           585: {
        !           586:     word dummy;
        !           587:     ptr_t result;
        !           588:
        !           589: #   define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
        !           590:
        !           591: #   ifdef STACKBOTTOM
        !           592:        return(STACKBOTTOM);
        !           593: #   else
        !           594: #      ifdef HEURISTIC1
        !           595: #         ifdef STACK_GROWS_DOWN
        !           596:             result = (ptr_t)((((word)(&dummy))
        !           597:                               + STACKBOTTOM_ALIGNMENT_M1)
        !           598:                              & ~STACKBOTTOM_ALIGNMENT_M1);
        !           599: #         else
        !           600:             result = (ptr_t)(((word)(&dummy))
        !           601:                              & ~STACKBOTTOM_ALIGNMENT_M1);
        !           602: #         endif
        !           603: #      endif /* HEURISTIC1 */
        !           604: #      ifdef HEURISTIC2
        !           605: #          ifdef STACK_GROWS_DOWN
        !           606:                result = GC_find_limit((ptr_t)(&dummy), TRUE);
        !           607: #              ifdef HEURISTIC2_LIMIT
        !           608:                    if (result > HEURISTIC2_LIMIT
        !           609:                        && (ptr_t)(&dummy) < HEURISTIC2_LIMIT) {
        !           610:                            result = HEURISTIC2_LIMIT;
        !           611:                    }
        !           612: #              endif
        !           613: #          else
        !           614:                result = GC_find_limit((ptr_t)(&dummy), FALSE);
        !           615: #              ifdef HEURISTIC2_LIMIT
        !           616:                    if (result < HEURISTIC2_LIMIT
        !           617:                        && (ptr_t)(&dummy) > HEURISTIC2_LIMIT) {
        !           618:                            result = HEURISTIC2_LIMIT;
        !           619:                    }
        !           620: #              endif
        !           621: #          endif
        !           622:
        !           623: #      endif /* HEURISTIC2 */
        !           624: #      ifdef STACK_GROWS_DOWN
        !           625:            if (result == 0) result = (ptr_t)(signed_word)(-sizeof(ptr_t));
        !           626: #      endif
        !           627:        return(result);
        !           628: #   endif /* STACKBOTTOM */
        !           629: }
        !           630:
        !           631: # endif /* ! AMIGA */
        !           632: # endif /* ! OS2 */
        !           633: # endif /* ! MSWIN32 */
        !           634:
        !           635: /*
        !           636:  * Register static data segment(s) as roots.
        !           637:  * If more data segments are added later then they need to be registered
        !           638:  * add that point (as we do with SunOS dynamic loading),
        !           639:  * or GC_mark_roots needs to check for them (as we do with PCR).
        !           640:  * Called with allocator lock held.
        !           641:  */
        !           642:
        !           643: # ifdef OS2
        !           644:
        !           645: void GC_register_data_segments()
        !           646: {
        !           647:     PTIB ptib;
        !           648:     PPIB ppib;
        !           649:     HMODULE module_handle;
        !           650: #   define PBUFSIZ 512
        !           651:     UCHAR path[PBUFSIZ];
        !           652:     FILE * myexefile;
        !           653:     struct exe_hdr hdrdos;     /* MSDOS header.        */
        !           654:     struct e32_exe hdr386;     /* Real header for my executable */
        !           655:     struct o32_obj seg;        /* Currrent segment */
        !           656:     int nsegs;
        !           657:
        !           658:
        !           659:     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
        !           660:        GC_err_printf0("DosGetInfoBlocks failed\n");
        !           661:        ABORT("DosGetInfoBlocks failed\n");
        !           662:     }
        !           663:     module_handle = ppib -> pib_hmte;
        !           664:     if (DosQueryModuleName(module_handle, PBUFSIZ, path) != NO_ERROR) {
        !           665:        GC_err_printf0("DosQueryModuleName failed\n");
        !           666:        ABORT("DosGetInfoBlocks failed\n");
        !           667:     }
        !           668:     myexefile = fopen(path, "rb");
        !           669:     if (myexefile == 0) {
        !           670:         GC_err_puts("Couldn't open executable ");
        !           671:         GC_err_puts(path); GC_err_puts("\n");
        !           672:         ABORT("Failed to open executable\n");
        !           673:     }
        !           674:     if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) {
        !           675:         GC_err_puts("Couldn't read MSDOS header from ");
        !           676:         GC_err_puts(path); GC_err_puts("\n");
        !           677:         ABORT("Couldn't read MSDOS header");
        !           678:     }
        !           679:     if (E_MAGIC(hdrdos) != EMAGIC) {
        !           680:         GC_err_puts("Executable has wrong DOS magic number: ");
        !           681:         GC_err_puts(path); GC_err_puts("\n");
        !           682:         ABORT("Bad DOS magic number");
        !           683:     }
        !           684:     if (fseek(myexefile, E_LFANEW(hdrdos), SEEK_SET) != 0) {
        !           685:         GC_err_puts("Seek to new header failed in ");
        !           686:         GC_err_puts(path); GC_err_puts("\n");
        !           687:         ABORT("Bad DOS magic number");
        !           688:     }
        !           689:     if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) {
        !           690:         GC_err_puts("Couldn't read MSDOS header from ");
        !           691:         GC_err_puts(path); GC_err_puts("\n");
        !           692:         ABORT("Couldn't read OS/2 header");
        !           693:     }
        !           694:     if (E32_MAGIC1(hdr386) != E32MAGIC1 || E32_MAGIC2(hdr386) != E32MAGIC2) {
        !           695:         GC_err_puts("Executable has wrong OS/2 magic number:");
        !           696:         GC_err_puts(path); GC_err_puts("\n");
        !           697:         ABORT("Bad OS/2 magic number");
        !           698:     }
        !           699:     if ( E32_BORDER(hdr386) != E32LEBO || E32_WORDER(hdr386) != E32LEWO) {
        !           700:         GC_err_puts("Executable %s has wrong byte order: ");
        !           701:         GC_err_puts(path); GC_err_puts("\n");
        !           702:         ABORT("Bad byte order");
        !           703:     }
        !           704:     if ( E32_CPU(hdr386) == E32CPU286) {
        !           705:         GC_err_puts("GC can't handle 80286 executables: ");
        !           706:         GC_err_puts(path); GC_err_puts("\n");
        !           707:         EXIT();
        !           708:     }
        !           709:     if (fseek(myexefile, E_LFANEW(hdrdos) + E32_OBJTAB(hdr386),
        !           710:              SEEK_SET) != 0) {
        !           711:         GC_err_puts("Seek to object table failed: ");
        !           712:         GC_err_puts(path); GC_err_puts("\n");
        !           713:         ABORT("Seek to object table failed");
        !           714:     }
        !           715:     for (nsegs = E32_OBJCNT(hdr386); nsegs > 0; nsegs--) {
        !           716:       int flags;
        !           717:       if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) {
        !           718:         GC_err_puts("Couldn't read obj table entry from ");
        !           719:         GC_err_puts(path); GC_err_puts("\n");
        !           720:         ABORT("Couldn't read obj table entry");
        !           721:       }
        !           722:       flags = O32_FLAGS(seg);
        !           723:       if (!(flags & OBJWRITE)) continue;
        !           724:       if (!(flags & OBJREAD)) continue;
        !           725:       if (flags & OBJINVALID) {
        !           726:           GC_err_printf0("Object with invalid pages?\n");
        !           727:           continue;
        !           728:       }
        !           729:       GC_add_roots_inner(O32_BASE(seg), O32_BASE(seg)+O32_SIZE(seg), FALSE);
        !           730:     }
        !           731: }
        !           732:
        !           733: # else
        !           734:
        !           735: # ifdef MSWIN32
        !           736:   /* Unfortunately, we have to handle win32s very differently from NT,         */
        !           737:   /* Since VirtualQuery has very different semantics.  In particular,  */
        !           738:   /* under win32s a VirtualQuery call on an unmapped page returns an   */
        !           739:   /* invalid result.  Under GC_register_data_segments is a noop and    */
        !           740:   /* all real work is done by GC_register_dynamic_libraries.  Under    */
        !           741:   /* win32s, we cannot find the data segments associated with dll's.   */
        !           742:   /* We rgister the main data segment here.                            */
        !           743:   GC_bool GC_win32s = FALSE;   /* We're running under win32s.  */
        !           744:
        !           745:   GC_bool GC_is_win32s()
        !           746:   {
        !           747:       DWORD v = GetVersion();
        !           748:
        !           749:       /* Check that this is not NT, and Windows major version <= 3     */
        !           750:       return ((v & 0x80000000) && (v & 0xff) <= 3);
        !           751:   }
        !           752:
        !           753:   void GC_init_win32()
        !           754:   {
        !           755:       GC_win32s = GC_is_win32s();
        !           756:   }
        !           757:
        !           758:   /* Return the smallest address a such that VirtualQuery              */
        !           759:   /* returns correct results for all addresses between a and start.    */
        !           760:   /* Assumes VirtualQuery returns correct information for start.       */
        !           761:   ptr_t GC_least_described_address(ptr_t start)
        !           762:   {
        !           763:     MEMORY_BASIC_INFORMATION buf;
        !           764:     SYSTEM_INFO sysinfo;
        !           765:     DWORD result;
        !           766:     LPVOID limit;
        !           767:     ptr_t p;
        !           768:     LPVOID q;
        !           769:
        !           770:     GetSystemInfo(&sysinfo);
        !           771:     limit = sysinfo.lpMinimumApplicationAddress;
        !           772:     p = (ptr_t)((word)start & ~(GC_page_size - 1));
        !           773:     for (;;) {
        !           774:        q = (LPVOID)(p - GC_page_size);
        !           775:        if ((ptr_t)q > (ptr_t)p /* underflow */ || q < limit) break;
        !           776:        result = VirtualQuery(q, &buf, sizeof(buf));
        !           777:        if (result != sizeof(buf) || buf.AllocationBase == 0) break;
        !           778:        p = (ptr_t)(buf.AllocationBase);
        !           779:     }
        !           780:     return(p);
        !           781:   }
        !           782:
        !           783:   /* Is p the start of either the malloc heap, or of one of our */
        !           784:   /* heap sections?                                            */
        !           785:   GC_bool GC_is_heap_base (ptr_t p)
        !           786:   {
        !           787:
        !           788:      register unsigned i;
        !           789:
        !           790: #    ifndef REDIRECT_MALLOC
        !           791:        static ptr_t malloc_heap_pointer = 0;
        !           792:
        !           793:        if (0 == malloc_heap_pointer) {
        !           794:          MEMORY_BASIC_INFORMATION buf;
        !           795:          register DWORD result = VirtualQuery(malloc(1), &buf, sizeof(buf));
        !           796:
        !           797:          if (result != sizeof(buf)) {
        !           798:              ABORT("Weird VirtualQuery result");
        !           799:          }
        !           800:          malloc_heap_pointer = (ptr_t)(buf.AllocationBase);
        !           801:        }
        !           802:        if (p == malloc_heap_pointer) return(TRUE);
        !           803: #    endif
        !           804:      for (i = 0; i < GC_n_heap_bases; i++) {
        !           805:          if (GC_heap_bases[i] == p) return(TRUE);
        !           806:      }
        !           807:      return(FALSE);
        !           808:   }
        !           809:
        !           810:   void GC_register_root_section(ptr_t static_root)
        !           811:   {
        !           812:       MEMORY_BASIC_INFORMATION buf;
        !           813:       SYSTEM_INFO sysinfo;
        !           814:       DWORD result;
        !           815:       DWORD protect;
        !           816:       LPVOID p;
        !           817:       char * base;
        !           818:       char * limit, * new_limit;
        !           819:
        !           820:       if (!GC_win32s) return;
        !           821:       p = base = limit = GC_least_described_address(static_root);
        !           822:       GetSystemInfo(&sysinfo);
        !           823:       while (p < sysinfo.lpMaximumApplicationAddress) {
        !           824:         result = VirtualQuery(p, &buf, sizeof(buf));
        !           825:         if (result != sizeof(buf) || buf.AllocationBase == 0
        !           826:             || GC_is_heap_base(buf.AllocationBase)) break;
        !           827:         new_limit = (char *)p + buf.RegionSize;
        !           828:         protect = buf.Protect;
        !           829:         if (buf.State == MEM_COMMIT
        !           830:             && is_writable(protect)) {
        !           831:             if ((char *)p == limit) {
        !           832:                 limit = new_limit;
        !           833:             } else {
        !           834:                 if (base != limit) GC_add_roots_inner(base, limit, FALSE);
        !           835:                 base = p;
        !           836:                 limit = new_limit;
        !           837:             }
        !           838:         }
        !           839:         if (p > (LPVOID)new_limit /* overflow */) break;
        !           840:         p = (LPVOID)new_limit;
        !           841:       }
        !           842:       if (base != limit) GC_add_roots_inner(base, limit, FALSE);
        !           843:   }
        !           844:
        !           845:   void GC_register_data_segments()
        !           846:   {
        !           847:       static char dummy;
        !           848:
        !           849:       GC_register_root_section((ptr_t)(&dummy));
        !           850:   }
        !           851: # else
        !           852: # ifdef AMIGA
        !           853:
        !           854:   void GC_register_data_segments()
        !           855:   {
        !           856:     extern struct WBStartup *_WBenchMsg;
        !           857:     struct Process     *proc;
        !           858:     struct CommandLineInterface *cli;
        !           859:     BPTR myseglist;
        !           860:     ULONG *data;
        !           861:
        !           862:     if ( _WBenchMsg != 0 ) {
        !           863:        if ((myseglist = _WBenchMsg->sm_Segment) == 0) {
        !           864:            GC_err_puts("No seglist from workbench\n");
        !           865:            return;
        !           866:        }
        !           867:     } else {
        !           868:        if ((proc = (struct Process *)FindTask(0)) == 0) {
        !           869:            GC_err_puts("Cannot find process structure\n");
        !           870:            return;
        !           871:        }
        !           872:        if ((cli = BADDR(proc->pr_CLI)) == 0) {
        !           873:            GC_err_puts("No CLI\n");
        !           874:            return;
        !           875:        }
        !           876:        if ((myseglist = cli->cli_Module) == 0) {
        !           877:            GC_err_puts("No seglist from CLI\n");
        !           878:            return;
        !           879:        }
        !           880:     }
        !           881:
        !           882:     for (data = (ULONG *)BADDR(myseglist); data != 0;
        !           883:          data = (ULONG *)BADDR(data[0])) {
        !           884: #        ifdef AMIGA_SKIP_SEG
        !           885:            if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
        !           886:            ((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
        !           887: #       else
        !           888:           {
        !           889: #       endif /* AMIGA_SKIP_SEG */
        !           890:           GC_add_roots_inner((char *)&data[1],
        !           891:                             ((char *)&data[1]) + data[-1], FALSE);
        !           892:          }
        !           893:     }
        !           894:   }
        !           895:
        !           896:
        !           897: # else
        !           898:
        !           899: # if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)
        !           900: char * GC_SysVGetDataStart(max_page_size, etext_addr)
        !           901: int max_page_size;
        !           902: int * etext_addr;
        !           903: {
        !           904:     word text_end = ((word)(etext_addr) + sizeof(word) - 1)
        !           905:                    & ~(sizeof(word) - 1);
        !           906:        /* etext rounded to word boundary       */
        !           907:     word next_page = ((text_end + (word)max_page_size - 1)
        !           908:                      & ~((word)max_page_size - 1));
        !           909:     word page_offset = (text_end & ((word)max_page_size - 1));
        !           910:     VOLATILE char * result = (char *)(next_page + page_offset);
        !           911:     /* Note that this isnt equivalent to just adding           */
        !           912:     /* max_page_size to &etext if &etext is at a page boundary */
        !           913:
        !           914:     GC_setup_temporary_fault_handler();
        !           915:     if (setjmp(GC_jmp_buf) == 0) {
        !           916:        /* Try writing to the address.  */
        !           917:        *result = *result;
        !           918:         GC_reset_fault_handler();
        !           919:     } else {
        !           920:         GC_reset_fault_handler();
        !           921:        /* We got here via a longjmp.  The address is not readable.     */
        !           922:        /* This is known to happen under Solaris 2.4 + gcc, which place */
        !           923:        /* string constants in the text segment, but after etext.       */
        !           924:        /* Use plan B.  Note that we now know there is a gap between    */
        !           925:        /* text and data segments, so plan A bought us something.       */
        !           926:        result = (char *)GC_find_limit((ptr_t)(DATAEND) - MIN_PAGE_SIZE, FALSE);
        !           927:     }
        !           928:     return((char *)result);
        !           929: }
        !           930: # endif
        !           931:
        !           932:
        !           933: void GC_register_data_segments()
        !           934: {
        !           935: #   if !defined(PCR) && !defined(SRC_M3) && !defined(NEXT) && !defined(MACOS)
        !           936: #     if defined(REDIRECT_MALLOC) && defined(SOLARIS_THREADS)
        !           937:        /* As of Solaris 2.3, the Solaris threads implementation        */
        !           938:        /* allocates the data structure for the initial thread with     */
        !           939:        /* sbrk at process startup.  It needs to be scanned, so that    */
        !           940:        /* we don't lose some malloc allocated data structures          */
        !           941:        /* hanging from it.  We're on thin ice here ...                 */
        !           942:         extern caddr_t sbrk();
        !           943:
        !           944:        GC_add_roots_inner(DATASTART, (char *)sbrk(0), FALSE);
        !           945: #     else
        !           946:        GC_add_roots_inner(DATASTART, (char *)(DATAEND), FALSE);
        !           947: #     endif
        !           948: #   endif
        !           949: #   if !defined(PCR) && defined(NEXT)
        !           950:       GC_add_roots_inner(DATASTART, (char *) get_end(), FALSE);
        !           951: #   endif
        !           952: #   if defined(MACOS)
        !           953:     {
        !           954: #   if defined(THINK_C)
        !           955:        extern void* GC_MacGetDataStart(void);
        !           956:        /* globals begin above stack and end at a5. */
        !           957:        GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
        !           958:                           (ptr_t)LMGetCurrentA5(), FALSE);
        !           959: #   else
        !           960: #     if defined(__MWERKS__)
        !           961: #       if !__POWERPC__
        !           962:          extern void* GC_MacGetDataStart(void);
        !           963:          /* MATTHEW: Function to handle Far Globals (CW Pro 3) */
        !           964: #         if __option(far_data)
        !           965:          extern void* GC_MacGetDataEnd(void);
        !           966: #         endif
        !           967:          /* globals begin above stack and end at a5. */
        !           968:          GC_add_roots_inner((ptr_t)GC_MacGetDataStart(),
        !           969:                             (ptr_t)LMGetCurrentA5(), FALSE);
        !           970:          /* MATTHEW: Handle Far Globals */
        !           971: #         if __option(far_data)
        !           972:       /* Far globals follow he QD globals: */
        !           973:          GC_add_roots_inner((ptr_t)LMGetCurrentA5(),
        !           974:                             (ptr_t)GC_MacGetDataEnd(), FALSE);
        !           975: #         endif
        !           976: #       else
        !           977:          extern char __data_start__[], __data_end__[];
        !           978:          GC_add_roots_inner((ptr_t)&__data_start__,
        !           979:                             (ptr_t)&__data_end__, FALSE);
        !           980: #       endif /* __POWERPC__ */
        !           981: #     endif /* __MWERKS__ */
        !           982: #   endif /* !THINK_C */
        !           983:     }
        !           984: #   endif /* MACOS */
        !           985:
        !           986:     /* Dynamic libraries are added at every collection, since they may  */
        !           987:     /* change.                                                         */
        !           988: }
        !           989:
        !           990: # endif  /* ! AMIGA */
        !           991: # endif  /* ! MSWIN32 */
        !           992: # endif  /* ! OS2 */
        !           993:
        !           994: /*
        !           995:  * Auxiliary routines for obtaining memory from OS.
        !           996:  */
        !           997:
        !           998: # if !defined(OS2) && !defined(PCR) && !defined(AMIGA) \
        !           999:        && !defined(MSWIN32) && !defined(MACOS) && !defined(DOS4GW)
        !          1000:
        !          1001: # ifdef SUNOS4
        !          1002:     extern caddr_t sbrk();
        !          1003: # endif
        !          1004: # ifdef __STDC__
        !          1005: #   define SBRK_ARG_T ptrdiff_t
        !          1006: # else
        !          1007: #   define SBRK_ARG_T int
        !          1008: # endif
        !          1009:
        !          1010: # ifdef RS6000
        !          1011: /* The compiler seems to generate speculative reads one past the end of        */
        !          1012: /* an allocated object.  Hence we need to make sure that the page      */
        !          1013: /* following the last heap page is also mapped.                                */
        !          1014: ptr_t GC_unix_get_mem(bytes)
        !          1015: word bytes;
        !          1016: {
        !          1017:     caddr_t cur_brk = (caddr_t)sbrk(0);
        !          1018:     caddr_t result;
        !          1019:     SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
        !          1020:     static caddr_t my_brk_val = 0;
        !          1021:
        !          1022:     if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
        !          1023:     if (lsbs != 0) {
        !          1024:         if((caddr_t)(sbrk(GC_page_size - lsbs)) == (caddr_t)(-1)) return(0);
        !          1025:     }
        !          1026:     if (cur_brk == my_brk_val) {
        !          1027:        /* Use the extra block we allocated last time. */
        !          1028:         result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
        !          1029:         if (result == (caddr_t)(-1)) return(0);
        !          1030:         result -= GC_page_size;
        !          1031:     } else {
        !          1032:         result = (ptr_t)sbrk(GC_page_size + (SBRK_ARG_T)bytes);
        !          1033:         if (result == (caddr_t)(-1)) return(0);
        !          1034:     }
        !          1035:     my_brk_val = result + bytes + GC_page_size;        /* Always page aligned */
        !          1036:     return((ptr_t)result);
        !          1037: }
        !          1038:
        !          1039: #else  /* Not RS6000 */
        !          1040:
        !          1041: #if defined(USE_MMAP)
        !          1042: /* Tested only under IRIX5 and Solaris 2 */
        !          1043:
        !          1044: #ifdef USE_MMAP_FIXED
        !          1045: #   define GC_MMAP_FLAGS MAP_FIXED | MAP_PRIVATE
        !          1046:        /* Seems to yield better performance on Solaris 2, but can      */
        !          1047:        /* be unreliable if something is already mapped at the address. */
        !          1048: #else
        !          1049: #   define GC_MMAP_FLAGS MAP_PRIVATE
        !          1050: #endif
        !          1051:
        !          1052: ptr_t GC_unix_get_mem(bytes)
        !          1053: word bytes;
        !          1054: {
        !          1055:     static GC_bool initialized = FALSE;
        !          1056:     static int fd;
        !          1057:     void *result;
        !          1058:     static ptr_t last_addr = HEAP_START;
        !          1059:
        !          1060:     if (!initialized) {
        !          1061:        fd = open("/dev/zero", O_RDONLY);
        !          1062:        initialized = TRUE;
        !          1063:     }
        !          1064:     if (bytes & (GC_page_size -1)) ABORT("Bad GET_MEM arg");
        !          1065:     result = mmap(last_addr, bytes, PROT_READ | PROT_WRITE | OPT_PROT_EXEC,
        !          1066:                  GC_MMAP_FLAGS, fd, 0/* offset */);
        !          1067:     if (result == MAP_FAILED) return(0);
        !          1068:     last_addr = (ptr_t)result + bytes + GC_page_size - 1;
        !          1069:     last_addr = (ptr_t)((word)last_addr & ~(GC_page_size - 1));
        !          1070:     return((ptr_t)result);
        !          1071: }
        !          1072:
        !          1073: #else /* Not RS6000, not USE_MMAP */
        !          1074: ptr_t GC_unix_get_mem(bytes)
        !          1075: word bytes;
        !          1076: {
        !          1077:   ptr_t result;
        !          1078: # ifdef IRIX5
        !          1079:     /* Bare sbrk isn't thread safe.  Play by malloc rules.     */
        !          1080:     /* The equivalent may be needed on other systems as well.  */
        !          1081:     __LOCK_MALLOC();
        !          1082: # endif
        !          1083:   {
        !          1084:     ptr_t cur_brk = (ptr_t)sbrk(0);
        !          1085:     SBRK_ARG_T lsbs = (word)cur_brk & (GC_page_size-1);
        !          1086:
        !          1087:     if ((SBRK_ARG_T)bytes < 0) return(0); /* too big */
        !          1088:     if (lsbs != 0) {
        !          1089:         if((ptr_t)sbrk(GC_page_size - lsbs) == (ptr_t)(-1)) return(0);
        !          1090:     }
        !          1091:     result = (ptr_t)sbrk((SBRK_ARG_T)bytes);
        !          1092:     if (result == (ptr_t)(-1)) result = 0;
        !          1093:   }
        !          1094: # ifdef IRIX5
        !          1095:     __UNLOCK_MALLOC();
        !          1096: # endif
        !          1097:   return(result);
        !          1098: }
        !          1099:
        !          1100: #endif /* Not USE_MMAP */
        !          1101: #endif /* Not RS6000 */
        !          1102:
        !          1103: # endif /* UN*X */
        !          1104:
        !          1105: # ifdef OS2
        !          1106:
        !          1107: void * os2_alloc(size_t bytes)
        !          1108: {
        !          1109:     void * result;
        !          1110:
        !          1111:     if (DosAllocMem(&result, bytes, PAG_EXECUTE | PAG_READ |
        !          1112:                                    PAG_WRITE | PAG_COMMIT)
        !          1113:                    != NO_ERROR) {
        !          1114:        return(0);
        !          1115:     }
        !          1116:     if (result == 0) return(os2_alloc(bytes));
        !          1117:     return(result);
        !          1118: }
        !          1119:
        !          1120: # endif /* OS2 */
        !          1121:
        !          1122:
        !          1123: # ifdef MSWIN32
        !          1124: word GC_n_heap_bases = 0;
        !          1125:
        !          1126: ptr_t GC_win32_get_mem(bytes)
        !          1127: word bytes;
        !          1128: {
        !          1129:     ptr_t result;
        !          1130:
        !          1131:     if (GC_win32s) {
        !          1132:        /* VirtualAlloc doesn't like PAGE_EXECUTE_READWRITE.    */
        !          1133:        /* There are also unconfirmed rumors of other           */
        !          1134:        /* problems, so we dodge the issue.                     */
        !          1135:         result = (ptr_t) GlobalAlloc(0, bytes + HBLKSIZE);
        !          1136:         result = (ptr_t)(((word)result + HBLKSIZE) & ~(HBLKSIZE-1));
        !          1137:     } else {
        !          1138:         result = (ptr_t) VirtualAlloc(NULL, bytes,
        !          1139:                                      MEM_COMMIT | MEM_RESERVE,
        !          1140:                                      PAGE_EXECUTE_READWRITE);
        !          1141:     }
        !          1142:     if (HBLKDISPL(result) != 0) ABORT("Bad VirtualAlloc result");
        !          1143:        /* If I read the documentation correctly, this can      */
        !          1144:        /* only happen if HBLKSIZE > 64k or not a power of 2.   */
        !          1145:     if (GC_n_heap_bases >= MAX_HEAP_SECTS) ABORT("Too many heap sections");
        !          1146:     GC_heap_bases[GC_n_heap_bases++] = result;
        !          1147:     return(result);
        !          1148: }
        !          1149:
        !          1150: void GC_win32_free_heap ()
        !          1151: {
        !          1152:     if (GC_win32s) {
        !          1153:        while (GC_n_heap_bases > 0) {
        !          1154:            GlobalFree (GC_heap_bases[--GC_n_heap_bases]);
        !          1155:            GC_heap_bases[GC_n_heap_bases] = 0;
        !          1156:        }
        !          1157:     }
        !          1158: }
        !          1159:
        !          1160:
        !          1161: # endif
        !          1162:
        !          1163: /* Routine for pushing any additional roots.  In THREADS       */
        !          1164: /* environment, this is also responsible for marking from      */
        !          1165: /* thread stacks.  In the SRC_M3 case, it also handles         */
        !          1166: /* global variables.                                           */
        !          1167: #ifndef THREADS
        !          1168: void (*GC_push_other_roots)() = 0;
        !          1169: #else /* THREADS */
        !          1170:
        !          1171: # ifdef PCR
        !          1172: PCR_ERes GC_push_thread_stack(PCR_Th_T *t, PCR_Any dummy)
        !          1173: {
        !          1174:     struct PCR_ThCtl_TInfoRep info;
        !          1175:     PCR_ERes result;
        !          1176:
        !          1177:     info.ti_stkLow = info.ti_stkHi = 0;
        !          1178:     result = PCR_ThCtl_GetInfo(t, &info);
        !          1179:     GC_push_all_stack((ptr_t)(info.ti_stkLow), (ptr_t)(info.ti_stkHi));
        !          1180:     return(result);
        !          1181: }
        !          1182:
        !          1183: /* Push the contents of an old object. We treat this as stack  */
        !          1184: /* data only becasue that makes it robust against mark stack   */
        !          1185: /* overflow.                                                   */
        !          1186: PCR_ERes GC_push_old_obj(void *p, size_t size, PCR_Any data)
        !          1187: {
        !          1188:     GC_push_all_stack((ptr_t)p, (ptr_t)p + size);
        !          1189:     return(PCR_ERes_okay);
        !          1190: }
        !          1191:
        !          1192:
        !          1193: void GC_default_push_other_roots()
        !          1194: {
        !          1195:     /* Traverse data allocated by previous memory managers.            */
        !          1196:        {
        !          1197:          extern struct PCR_MM_ProcsRep * GC_old_allocator;
        !          1198:
        !          1199:          if ((*(GC_old_allocator->mmp_enumerate))(PCR_Bool_false,
        !          1200:                                                   GC_push_old_obj, 0)
        !          1201:              != PCR_ERes_okay) {
        !          1202:              ABORT("Old object enumeration failed");
        !          1203:          }
        !          1204:        }
        !          1205:     /* Traverse all thread stacks. */
        !          1206:        if (PCR_ERes_IsErr(
        !          1207:                 PCR_ThCtl_ApplyToAllOtherThreads(GC_push_thread_stack,0))
        !          1208:               || PCR_ERes_IsErr(GC_push_thread_stack(PCR_Th_CurrThread(), 0))) {
        !          1209:               ABORT("Thread stack marking failed\n");
        !          1210:        }
        !          1211: }
        !          1212:
        !          1213: # endif /* PCR */
        !          1214:
        !          1215: # ifdef SRC_M3
        !          1216:
        !          1217: # ifdef ALL_INTERIOR_POINTERS
        !          1218:     --> misconfigured
        !          1219: # endif
        !          1220:
        !          1221:
        !          1222: extern void ThreadF__ProcessStacks();
        !          1223:
        !          1224: void GC_push_thread_stack(start, stop)
        !          1225: word start, stop;
        !          1226: {
        !          1227:    GC_push_all_stack((ptr_t)start, (ptr_t)stop + sizeof(word));
        !          1228: }
        !          1229:
        !          1230: /* Push routine with M3 specific calling convention. */
        !          1231: GC_m3_push_root(dummy1, p, dummy2, dummy3)
        !          1232: word *p;
        !          1233: ptr_t dummy1, dummy2;
        !          1234: int dummy3;
        !          1235: {
        !          1236:     word q = *p;
        !          1237:
        !          1238:     if ((ptr_t)(q) >= GC_least_plausible_heap_addr
        !          1239:         && (ptr_t)(q) < GC_greatest_plausible_heap_addr) {
        !          1240:         GC_push_one_checked(q,FALSE);
        !          1241:     }
        !          1242: }
        !          1243:
        !          1244: /* M3 set equivalent to RTHeap.TracedRefTypes */
        !          1245: typedef struct { int elts[1]; }  RefTypeSet;
        !          1246: RefTypeSet GC_TracedRefTypes = {{0x1}};
        !          1247:
        !          1248: /* From finalize.c */
        !          1249: extern void GC_push_finalizer_structures();
        !          1250:
        !          1251: /* From stubborn.c: */
        !          1252: # ifdef STUBBORN_ALLOC
        !          1253:     extern GC_PTR * GC_changing_list_start;
        !          1254: # endif
        !          1255:
        !          1256:
        !          1257: void GC_default_push_other_roots()
        !          1258: {
        !          1259:     /* Use the M3 provided routine for finding static roots.   */
        !          1260:     /* This is a bit dubious, since it presumes no C roots.    */
        !          1261:     /* We handle the collector roots explicitly.               */
        !          1262:        {
        !          1263: #       ifdef STUBBORN_ALLOC
        !          1264:            GC_push_one(GC_changing_list_start);
        !          1265: #       endif
        !          1266:         GC_push_finalizer_structures();
        !          1267:         RTMain__GlobalMapProc(GC_m3_push_root, 0, GC_TracedRefTypes);
        !          1268:        }
        !          1269:        if (GC_words_allocd > 0) {
        !          1270:            ThreadF__ProcessStacks(GC_push_thread_stack);
        !          1271:        }
        !          1272:        /* Otherwise this isn't absolutely necessary, and we have       */
        !          1273:        /* startup ordering problems.                                   */
        !          1274: }
        !          1275:
        !          1276: # endif /* SRC_M3 */
        !          1277:
        !          1278: # if defined(SOLARIS_THREADS) || defined(WIN32_THREADS) \
        !          1279:      || defined(IRIX_THREADS) || defined(LINUX_THREADS) \
        !          1280:      || defined(IRIX_PCR_THREADS)
        !          1281:
        !          1282: extern void GC_push_all_stacks();
        !          1283:
        !          1284: void GC_default_push_other_roots()
        !          1285: {
        !          1286:     GC_push_all_stacks();
        !          1287: }
        !          1288:
        !          1289: # endif /* SOLARIS_THREADS || ... */
        !          1290:
        !          1291: void (*GC_push_other_roots)() = GC_default_push_other_roots;
        !          1292:
        !          1293: #endif
        !          1294:
        !          1295: /*
        !          1296:  * Routines for accessing dirty  bits on virtual pages.
        !          1297:  * We plan to eventaually implement four strategies for doing so:
        !          1298:  * DEFAULT_VDB:        A simple dummy implementation that treats every page
        !          1299:  *             as possibly dirty.  This makes incremental collection
        !          1300:  *             useless, but the implementation is still correct.
        !          1301:  * PCR_VDB:    Use PPCRs virtual dirty bit facility.
        !          1302:  * PROC_VDB:   Use the /proc facility for reading dirty bits.  Only
        !          1303:  *             works under some SVR4 variants.  Even then, it may be
        !          1304:  *             too slow to be entirely satisfactory.  Requires reading
        !          1305:  *             dirty bits for entire address space.  Implementations tend
        !          1306:  *             to assume that the client is a (slow) debugger.
        !          1307:  * MPROTECT_VDB:Protect pages and then catch the faults to keep track of
        !          1308:  *             dirtied pages.  The implementation (and implementability)
        !          1309:  *             is highly system dependent.  This usually fails when system
        !          1310:  *             calls write to a protected page.  We prevent the read system
        !          1311:  *             call from doing so.  It is the clients responsibility to
        !          1312:  *             make sure that other system calls are similarly protected
        !          1313:  *             or write only to the stack.
        !          1314:  */
        !          1315:
        !          1316: GC_bool GC_dirty_maintained = FALSE;
        !          1317:
        !          1318: # ifdef DEFAULT_VDB
        !          1319:
        !          1320: /* All of the following assume the allocation lock is held, and        */
        !          1321: /* signals are disabled.                                       */
        !          1322:
        !          1323: /* The client asserts that unallocated pages in the heap are never     */
        !          1324: /* written.                                                            */
        !          1325:
        !          1326: /* Initialize virtual dirty bit implementation.                        */
        !          1327: void GC_dirty_init()
        !          1328: {
        !          1329:     GC_dirty_maintained = TRUE;
        !          1330: }
        !          1331:
        !          1332: /* Retrieve system dirty bits for heap to a local buffer.      */
        !          1333: /* Restore the systems notion of which pages are dirty.                */
        !          1334: void GC_read_dirty()
        !          1335: {}
        !          1336:
        !          1337: /* Is the HBLKSIZE sized page at h marked dirty in the local buffer?   */
        !          1338: /* If the actual page size is different, this returns TRUE if any      */
        !          1339: /* of the pages overlapping h are dirty.  This routine may err on the  */
        !          1340: /* side of labelling pages as dirty (and this implementation does).    */
        !          1341: /*ARGSUSED*/
        !          1342: GC_bool GC_page_was_dirty(h)
        !          1343: struct hblk *h;
        !          1344: {
        !          1345:     return(TRUE);
        !          1346: }
        !          1347:
        !          1348: /*
        !          1349:  * The following two routines are typically less crucial.  They matter
        !          1350:  * most with large dynamic libraries, or if we can't accurately identify
        !          1351:  * stacks, e.g. under Solaris 2.X.  Otherwise the following default
        !          1352:  * versions are adequate.
        !          1353:  */
        !          1354:
        !          1355: /* Could any valid GC heap pointer ever have been written to this page?        */
        !          1356: /*ARGSUSED*/
        !          1357: GC_bool GC_page_was_ever_dirty(h)
        !          1358: struct hblk *h;
        !          1359: {
        !          1360:     return(TRUE);
        !          1361: }
        !          1362:
        !          1363: /* Reset the n pages starting at h to "was never dirty" status.        */
        !          1364: void GC_is_fresh(h, n)
        !          1365: struct hblk *h;
        !          1366: word n;
        !          1367: {
        !          1368: }
        !          1369:
        !          1370: /* A call hints that h is about to be written. */
        !          1371: /* May speed up some dirty bit implementations.        */
        !          1372: /*ARGSUSED*/
        !          1373: void GC_write_hint(h)
        !          1374: struct hblk *h;
        !          1375: {
        !          1376: }
        !          1377:
        !          1378: # endif /* DEFAULT_VDB */
        !          1379:
        !          1380:
        !          1381: # ifdef MPROTECT_VDB
        !          1382:
        !          1383: /*
        !          1384:  * See DEFAULT_VDB for interface descriptions.
        !          1385:  */
        !          1386:
        !          1387: /*
        !          1388:  * This implementation maintains dirty bits itself by catching write
        !          1389:  * faults and keeping track of them.  We assume nobody else catches
        !          1390:  * SIGBUS or SIGSEGV.  We assume no write faults occur in system calls
        !          1391:  * except as a result of a read system call.  This means clients must
        !          1392:  * either ensure that system calls do not touch the heap, or must
        !          1393:  * provide their own wrappers analogous to the one for read.
        !          1394:  * We assume the page size is a multiple of HBLKSIZE.
        !          1395:  * This implementation is currently SunOS 4.X and IRIX 5.X specific, though we
        !          1396:  * tried to use portable code where easily possible.  It is known
        !          1397:  * not to work under a number of other systems.
        !          1398:  */
        !          1399:
        !          1400: # ifndef MSWIN32
        !          1401:
        !          1402: #   include <sys/mman.h>
        !          1403: #   include <signal.h>
        !          1404: #   include <sys/syscall.h>
        !          1405:
        !          1406: #   define PROTECT(addr, len) \
        !          1407:          if (mprotect((caddr_t)(addr), (int)(len), \
        !          1408:                       PROT_READ | OPT_PROT_EXEC) < 0) { \
        !          1409:            ABORT("mprotect failed"); \
        !          1410:          }
        !          1411: #   define UNPROTECT(addr, len) \
        !          1412:          if (mprotect((caddr_t)(addr), (int)(len), \
        !          1413:                       PROT_WRITE | PROT_READ | OPT_PROT_EXEC ) < 0) { \
        !          1414:            ABORT("un-mprotect failed"); \
        !          1415:          }
        !          1416:
        !          1417: # else
        !          1418:
        !          1419: #   include <signal.h>
        !          1420:
        !          1421:     static DWORD protect_junk;
        !          1422: #   define PROTECT(addr, len) \
        !          1423:          if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READ, \
        !          1424:                              &protect_junk)) { \
        !          1425:            DWORD last_error = GetLastError(); \
        !          1426:            GC_printf1("Last error code: %lx\n", last_error); \
        !          1427:            ABORT("VirtualProtect failed"); \
        !          1428:          }
        !          1429: #   define UNPROTECT(addr, len) \
        !          1430:          if (!VirtualProtect((addr), (len), PAGE_EXECUTE_READWRITE, \
        !          1431:                              &protect_junk)) { \
        !          1432:            ABORT("un-VirtualProtect failed"); \
        !          1433:          }
        !          1434:
        !          1435: # endif
        !          1436:
        !          1437: #if defined(SUNOS4) || defined(FREEBSD)
        !          1438:     typedef void (* SIG_PF)();
        !          1439: #endif
        !          1440: #if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX)
        !          1441:     typedef void (* SIG_PF)(int);
        !          1442: #endif
        !          1443: #if defined(MSWIN32)
        !          1444:     typedef LPTOP_LEVEL_EXCEPTION_FILTER SIG_PF;
        !          1445: #   undef SIG_DFL
        !          1446: #   define SIG_DFL (LPTOP_LEVEL_EXCEPTION_FILTER) (-1)
        !          1447: #endif
        !          1448:
        !          1449: #if defined(IRIX5) || defined(OSF1)
        !          1450:     typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
        !          1451: #endif
        !          1452: #if defined(SUNOS5SIGS)
        !          1453:     typedef void (* REAL_SIG_PF)(int, struct siginfo *, void *);
        !          1454: #endif
        !          1455: #if defined(LINUX)
        !          1456: #   include <linux/version.h>
        !          1457: #   if (LINUX_VERSION_CODE >= 0x20100) && !defined(M68K) || defined(ALPHA)
        !          1458:       typedef struct sigcontext s_c;
        !          1459: #   else
        !          1460:       typedef struct sigcontext_struct s_c;
        !          1461: #   endif
        !          1462: #   ifdef ALPHA
        !          1463:     typedef void (* REAL_SIG_PF)(int, int, s_c *);
        !          1464:     /* Retrieve fault address from sigcontext structure by decoding    */
        !          1465:     /* instruction.                                                    */
        !          1466:     char * get_fault_addr(s_c *sc) {
        !          1467:         unsigned instr;
        !          1468:        word faultaddr;
        !          1469:
        !          1470:        instr = *((unsigned *)(sc->sc_pc));
        !          1471:        faultaddr = sc->sc_regs[(instr >> 16) & 0x1f];
        !          1472:        faultaddr += (word) (((int)instr << 16) >> 16);
        !          1473:        return (char *)faultaddr;
        !          1474:     }
        !          1475: #   else /* !ALPHA */
        !          1476:     typedef void (* REAL_SIG_PF)(int, s_c);
        !          1477: #   endif /* !ALPHA */
        !          1478: # endif
        !          1479:
        !          1480: SIG_PF GC_old_bus_handler;
        !          1481: SIG_PF GC_old_segv_handler;    /* Also old MSWIN32 ACCESS_VIOLATION filter */
        !          1482:
        !          1483: /*ARGSUSED*/
        !          1484: # if defined (SUNOS4) || defined(FREEBSD)
        !          1485:     void GC_write_fault_handler(sig, code, scp, addr)
        !          1486:     int sig, code;
        !          1487:     struct sigcontext *scp;
        !          1488:     char * addr;
        !          1489: #   ifdef SUNOS4
        !          1490: #     define SIG_OK (sig == SIGSEGV || sig == SIGBUS)
        !          1491: #     define CODE_OK (FC_CODE(code) == FC_PROT \
        !          1492:                    || (FC_CODE(code) == FC_OBJERR \
        !          1493:                       && FC_ERRNO(code) == FC_PROT))
        !          1494: #   endif
        !          1495: #   ifdef FREEBSD
        !          1496: #     define SIG_OK (sig == SIGBUS)
        !          1497: #     define CODE_OK (code == BUS_PAGE_FAULT)
        !          1498: #   endif
        !          1499: # endif
        !          1500: # if defined(IRIX5) || defined(OSF1)
        !          1501: #   include <errno.h>
        !          1502:     void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
        !          1503: #   define SIG_OK (sig == SIGSEGV)
        !          1504: #   ifdef OSF1
        !          1505: #     define CODE_OK (code == 2 /* experimentally determined */)
        !          1506: #   endif
        !          1507: #   ifdef IRIX5
        !          1508: #     define CODE_OK (code == EACCES)
        !          1509: #   endif
        !          1510: # endif
        !          1511: # if defined(LINUX)
        !          1512: #   ifdef ALPHA
        !          1513:       void GC_write_fault_handler(int sig, int code, s_c * sc)
        !          1514: #   else
        !          1515:       void GC_write_fault_handler(int sig, s_c sc)
        !          1516: #   endif
        !          1517: #   define SIG_OK (sig == SIGSEGV)
        !          1518: #   define CODE_OK TRUE
        !          1519:        /* Empirically c.trapno == 14, but is that useful?      */
        !          1520:        /* We assume Intel architecture, so alignment           */
        !          1521:        /* faults are not possible.                             */
        !          1522: # endif
        !          1523: # if defined(SUNOS5SIGS)
        !          1524:     void GC_write_fault_handler(int sig, struct siginfo *scp, void * context)
        !          1525: #   define SIG_OK (sig == SIGSEGV)
        !          1526: #   define CODE_OK (scp -> si_code == SEGV_ACCERR)
        !          1527: # endif
        !          1528: # if defined(MSWIN32)
        !          1529:     LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info)
        !          1530: #   define SIG_OK (exc_info -> ExceptionRecord -> ExceptionCode == \
        !          1531:                        EXCEPTION_ACCESS_VIOLATION)
        !          1532: #   define CODE_OK (exc_info -> ExceptionRecord -> ExceptionInformation[0] == 1)
        !          1533:                        /* Write fault */
        !          1534: # endif
        !          1535: {
        !          1536:     register unsigned i;
        !          1537: #   ifdef IRIX5
        !          1538:        char * addr = (char *) (size_t) (scp -> sc_badvaddr);
        !          1539: #   endif
        !          1540: #   if defined(OSF1) && defined(ALPHA)
        !          1541:        char * addr = (char *) (scp -> sc_traparg_a0);
        !          1542: #   endif
        !          1543: #   ifdef SUNOS5SIGS
        !          1544:        char * addr = (char *) (scp -> si_addr);
        !          1545: #   endif
        !          1546: #   ifdef LINUX
        !          1547: #     ifdef I386
        !          1548:        char * addr = (char *) (sc.cr2);
        !          1549: #     else
        !          1550: #      if defined(M68K)
        !          1551:           char * addr = NULL;
        !          1552:
        !          1553:          struct sigcontext *scp = (struct sigcontext *)(&sc);
        !          1554:
        !          1555:          int format = (scp->sc_formatvec >> 12) & 0xf;
        !          1556:          unsigned long *framedata = (unsigned long *)(scp + 1);
        !          1557:          unsigned long ea;
        !          1558:
        !          1559:          if (format == 0xa || format == 0xb) {
        !          1560:                /* 68020/030 */
        !          1561:                ea = framedata[2];
        !          1562:          } else if (format == 7) {
        !          1563:                /* 68040 */
        !          1564:                ea = framedata[3];
        !          1565:          } else if (format == 4) {
        !          1566:                /* 68060 */
        !          1567:                ea = framedata[0];
        !          1568:                if (framedata[1] & 0x08000000) {
        !          1569:                        /* correct addr on misaligned access */
        !          1570:                        ea = (ea+4095)&(~4095);
        !          1571:                }
        !          1572:          }
        !          1573:          addr = (char *)ea;
        !          1574: #      else
        !          1575: #        ifdef ALPHA
        !          1576:             char * addr = get_fault_addr(sc);
        !          1577: #        else
        !          1578:                --> architecture not supported
        !          1579: #        endif
        !          1580: #      endif
        !          1581: #     endif
        !          1582: #   endif
        !          1583: #   if defined(MSWIN32)
        !          1584:        char * addr = (char *) (exc_info -> ExceptionRecord
        !          1585:                                -> ExceptionInformation[1]);
        !          1586: #      define sig SIGSEGV
        !          1587: #   endif
        !          1588:
        !          1589:     if (SIG_OK && CODE_OK) {
        !          1590:         register struct hblk * h =
        !          1591:                        (struct hblk *)((word)addr & ~(GC_page_size-1));
        !          1592:         GC_bool in_allocd_block;
        !          1593:
        !          1594: #      ifdef SUNOS5SIGS
        !          1595:            /* Address is only within the correct physical page.        */
        !          1596:            in_allocd_block = FALSE;
        !          1597:             for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
        !          1598:               if (HDR(h+i) != 0) {
        !          1599:                 in_allocd_block = TRUE;
        !          1600:               }
        !          1601:             }
        !          1602: #      else
        !          1603:            in_allocd_block = (HDR(addr) != 0);
        !          1604: #      endif
        !          1605:         if (!in_allocd_block) {
        !          1606:            /* Heap blocks now begin and end on page boundaries */
        !          1607:             SIG_PF old_handler;
        !          1608:
        !          1609:             if (sig == SIGSEGV) {
        !          1610:                old_handler = GC_old_segv_handler;
        !          1611:             } else {
        !          1612:                 old_handler = GC_old_bus_handler;
        !          1613:             }
        !          1614:             if (old_handler == SIG_DFL) {
        !          1615: #              ifndef MSWIN32
        !          1616:                    GC_err_printf1("Segfault at 0x%lx\n", addr);
        !          1617:                     ABORT("Unexpected bus error or segmentation fault");
        !          1618: #              else
        !          1619:                    return(EXCEPTION_CONTINUE_SEARCH);
        !          1620: #              endif
        !          1621:             } else {
        !          1622: #              if defined (SUNOS4) || defined(FREEBSD)
        !          1623:                    (*old_handler) (sig, code, scp, addr);
        !          1624:                    return;
        !          1625: #              endif
        !          1626: #              if defined (SUNOS5SIGS)
        !          1627:                    (*(REAL_SIG_PF)old_handler) (sig, scp, context);
        !          1628:                    return;
        !          1629: #              endif
        !          1630: #              if defined (LINUX)
        !          1631: #                  ifdef ALPHA
        !          1632:                        (*(REAL_SIG_PF)old_handler) (sig, code, sc);
        !          1633: #                  else
        !          1634:                        (*(REAL_SIG_PF)old_handler) (sig, sc);
        !          1635: #                  endif
        !          1636:                    return;
        !          1637: #              endif
        !          1638: #              if defined (IRIX5) || defined(OSF1)
        !          1639:                    (*(REAL_SIG_PF)old_handler) (sig, code, scp);
        !          1640:                    return;
        !          1641: #              endif
        !          1642: #              ifdef MSWIN32
        !          1643:                    return((*old_handler)(exc_info));
        !          1644: #              endif
        !          1645:             }
        !          1646:         }
        !          1647:         for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
        !          1648:             register int index = PHT_HASH(h+i);
        !          1649:
        !          1650:             set_pht_entry_from_index(GC_dirty_pages, index);
        !          1651:         }
        !          1652:         UNPROTECT(h, GC_page_size);
        !          1653: #      if defined(OSF1) || defined(LINUX)
        !          1654:            /* These reset the signal handler each time by default. */
        !          1655:            signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
        !          1656: #      endif
        !          1657:        /* The write may not take place before dirty bits are read.     */
        !          1658:        /* But then we'll fault again ...                               */
        !          1659: #      ifdef MSWIN32
        !          1660:            return(EXCEPTION_CONTINUE_EXECUTION);
        !          1661: #      else
        !          1662:            return;
        !          1663: #      endif
        !          1664:     }
        !          1665: #ifdef MSWIN32
        !          1666:     return EXCEPTION_CONTINUE_SEARCH;
        !          1667: #else
        !          1668:     GC_err_printf1("Segfault at 0x%lx\n", addr);
        !          1669:     ABORT("Unexpected bus error or segmentation fault");
        !          1670: #endif
        !          1671: }
        !          1672:
        !          1673: /*
        !          1674:  * We hold the allocation lock.  We expect block h to be written
        !          1675:  * shortly.
        !          1676:  */
        !          1677: void GC_write_hint(h)
        !          1678: struct hblk *h;
        !          1679: {
        !          1680:     register struct hblk * h_trunc;
        !          1681:     register unsigned i;
        !          1682:     register GC_bool found_clean;
        !          1683:
        !          1684:     if (!GC_dirty_maintained) return;
        !          1685:     h_trunc = (struct hblk *)((word)h & ~(GC_page_size-1));
        !          1686:     found_clean = FALSE;
        !          1687:     for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
        !          1688:         register int index = PHT_HASH(h_trunc+i);
        !          1689:
        !          1690:         if (!get_pht_entry_from_index(GC_dirty_pages, index)) {
        !          1691:             found_clean = TRUE;
        !          1692:             set_pht_entry_from_index(GC_dirty_pages, index);
        !          1693:         }
        !          1694:     }
        !          1695:     if (found_clean) {
        !          1696:        UNPROTECT(h_trunc, GC_page_size);
        !          1697:     }
        !          1698: }
        !          1699:
        !          1700: void GC_dirty_init()
        !          1701: {
        !          1702: #if defined(SUNOS5SIGS) || defined(IRIX5)
        !          1703:     struct sigaction   act, oldact;
        !          1704: #   ifdef IRIX5
        !          1705:        act.sa_flags    = SA_RESTART;
        !          1706:         act.sa_handler  = GC_write_fault_handler;
        !          1707: #   else
        !          1708:        act.sa_flags    = SA_RESTART | SA_SIGINFO;
        !          1709:         act.sa_sigaction = GC_write_fault_handler;
        !          1710: #   endif
        !          1711:     (void)sigemptyset(&act.sa_mask);
        !          1712: #endif
        !          1713: #   ifdef PRINTSTATS
        !          1714:        GC_printf0("Inititalizing mprotect virtual dirty bit implementation\n");
        !          1715: #   endif
        !          1716:     GC_dirty_maintained = TRUE;
        !          1717:     if (GC_page_size % HBLKSIZE != 0) {
        !          1718:         GC_err_printf0("Page size not multiple of HBLKSIZE\n");
        !          1719:         ABORT("Page size not multiple of HBLKSIZE");
        !          1720:     }
        !          1721: #   if defined(SUNOS4) || defined(FREEBSD)
        !          1722:       GC_old_bus_handler = signal(SIGBUS, GC_write_fault_handler);
        !          1723:       if (GC_old_bus_handler == SIG_IGN) {
        !          1724:         GC_err_printf0("Previously ignored bus error!?");
        !          1725:         GC_old_bus_handler = SIG_DFL;
        !          1726:       }
        !          1727:       if (GC_old_bus_handler != SIG_DFL) {
        !          1728: #      ifdef PRINTSTATS
        !          1729:           GC_err_printf0("Replaced other SIGBUS handler\n");
        !          1730: #      endif
        !          1731:       }
        !          1732: #   endif
        !          1733: #   if defined(OSF1) || defined(SUNOS4) || defined(LINUX)
        !          1734:       GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
        !          1735:       if (GC_old_segv_handler == SIG_IGN) {
        !          1736:         GC_err_printf0("Previously ignored segmentation violation!?");
        !          1737:         GC_old_segv_handler = SIG_DFL;
        !          1738:       }
        !          1739:       if (GC_old_segv_handler != SIG_DFL) {
        !          1740: #      ifdef PRINTSTATS
        !          1741:           GC_err_printf0("Replaced other SIGSEGV handler\n");
        !          1742: #      endif
        !          1743:       }
        !          1744: #   endif
        !          1745: #   if defined(SUNOS5SIGS) || defined(IRIX5)
        !          1746: #     if defined(IRIX_THREADS) || defined(IRIX_PCR_THREADS)
        !          1747:        sigaction(SIGSEGV, 0, &oldact);
        !          1748:        sigaction(SIGSEGV, &act, 0);
        !          1749: #     else
        !          1750:        sigaction(SIGSEGV, &act, &oldact);
        !          1751: #     endif
        !          1752: #     if defined(_sigargs)
        !          1753:        /* This is Irix 5.x, not 6.x.  Irix 5.x does not have   */
        !          1754:        /* sa_sigaction.                                        */
        !          1755:        GC_old_segv_handler = oldact.sa_handler;
        !          1756: #     else /* Irix 6.x or SUNOS5SIGS */
        !          1757:         if (oldact.sa_flags & SA_SIGINFO) {
        !          1758:           GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
        !          1759:         } else {
        !          1760:           GC_old_segv_handler = oldact.sa_handler;
        !          1761:         }
        !          1762: #     endif
        !          1763:       if (GC_old_segv_handler == SIG_IGN) {
        !          1764:             GC_err_printf0("Previously ignored segmentation violation!?");
        !          1765:             GC_old_segv_handler = SIG_DFL;
        !          1766:       }
        !          1767:       if (GC_old_segv_handler != SIG_DFL) {
        !          1768: #       ifdef PRINTSTATS
        !          1769:          GC_err_printf0("Replaced other SIGSEGV handler\n");
        !          1770: #       endif
        !          1771:       }
        !          1772: #    endif
        !          1773: #   if defined(MSWIN32)
        !          1774:       GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
        !          1775:       if (GC_old_segv_handler != NULL) {
        !          1776: #      ifdef PRINTSTATS
        !          1777:           GC_err_printf0("Replaced other UnhandledExceptionFilter\n");
        !          1778: #      endif
        !          1779:       } else {
        !          1780:           GC_old_segv_handler = SIG_DFL;
        !          1781:       }
        !          1782: #   endif
        !          1783: }
        !          1784:
        !          1785:
        !          1786:
        !          1787: void GC_protect_heap()
        !          1788: {
        !          1789:     ptr_t start;
        !          1790:     word len;
        !          1791:     unsigned i;
        !          1792:
        !          1793:     for (i = 0; i < GC_n_heap_sects; i++) {
        !          1794:         start = GC_heap_sects[i].hs_start;
        !          1795:         len = GC_heap_sects[i].hs_bytes;
        !          1796:         PROTECT(start, len);
        !          1797:     }
        !          1798: }
        !          1799:
        !          1800: /* We assume that either the world is stopped or its OK to lose dirty  */
        !          1801: /* bits while this is happenning (as in GC_enable_incremental).                */
        !          1802: void GC_read_dirty()
        !          1803: {
        !          1804:     BCOPY((word *)GC_dirty_pages, GC_grungy_pages,
        !          1805:           (sizeof GC_dirty_pages));
        !          1806:     BZERO((word *)GC_dirty_pages, (sizeof GC_dirty_pages));
        !          1807:     GC_protect_heap();
        !          1808: }
        !          1809:
        !          1810: GC_bool GC_page_was_dirty(h)
        !          1811: struct hblk * h;
        !          1812: {
        !          1813:     register word index = PHT_HASH(h);
        !          1814:
        !          1815:     return(HDR(h) == 0 || get_pht_entry_from_index(GC_grungy_pages, index));
        !          1816: }
        !          1817:
        !          1818: /*
        !          1819:  * Acquiring the allocation lock here is dangerous, since this
        !          1820:  * can be called from within GC_call_with_alloc_lock, and the cord
        !          1821:  * package does so.  On systems that allow nested lock acquisition, this
        !          1822:  * happens to work.
        !          1823:  * On other systems, SET_LOCK_HOLDER and friends must be suitably defined.
        !          1824:  */
        !          1825:
        !          1826: void GC_begin_syscall()
        !          1827: {
        !          1828:     if (!I_HOLD_LOCK()) LOCK();
        !          1829: }
        !          1830:
        !          1831: void GC_end_syscall()
        !          1832: {
        !          1833:     if (!I_HOLD_LOCK()) UNLOCK();
        !          1834: }
        !          1835:
        !          1836: void GC_unprotect_range(addr, len)
        !          1837: ptr_t addr;
        !          1838: word len;
        !          1839: {
        !          1840:     struct hblk * start_block;
        !          1841:     struct hblk * end_block;
        !          1842:     register struct hblk *h;
        !          1843:     ptr_t obj_start;
        !          1844:
        !          1845:     if (!GC_incremental) return;
        !          1846:     obj_start = GC_base(addr);
        !          1847:     if (obj_start == 0) return;
        !          1848:     if (GC_base(addr + len - 1) != obj_start) {
        !          1849:         ABORT("GC_unprotect_range(range bigger than object)");
        !          1850:     }
        !          1851:     start_block = (struct hblk *)((word)addr & ~(GC_page_size - 1));
        !          1852:     end_block = (struct hblk *)((word)(addr + len - 1) & ~(GC_page_size - 1));
        !          1853:     end_block += GC_page_size/HBLKSIZE - 1;
        !          1854:     for (h = start_block; h <= end_block; h++) {
        !          1855:         register word index = PHT_HASH(h);
        !          1856:
        !          1857:         set_pht_entry_from_index(GC_dirty_pages, index);
        !          1858:     }
        !          1859:     UNPROTECT(start_block,
        !          1860:              ((ptr_t)end_block - (ptr_t)start_block) + HBLKSIZE);
        !          1861: }
        !          1862:
        !          1863: #ifndef MSWIN32
        !          1864: /* Replacement for UNIX system call.    */
        !          1865: /* Other calls that write to the heap   */
        !          1866: /* should be handled similarly.                 */
        !          1867: # if defined(__STDC__) && !defined(SUNOS4)
        !          1868: #   include <unistd.h>
        !          1869:     ssize_t read(int fd, void *buf, size_t nbyte)
        !          1870: # else
        !          1871: #   ifndef LINT
        !          1872:       int read(fd, buf, nbyte)
        !          1873: #   else
        !          1874:       int GC_read(fd, buf, nbyte)
        !          1875: #   endif
        !          1876:     int fd;
        !          1877:     char *buf;
        !          1878:     int nbyte;
        !          1879: # endif
        !          1880: {
        !          1881:     int result;
        !          1882:
        !          1883:     GC_begin_syscall();
        !          1884:     GC_unprotect_range(buf, (word)nbyte);
        !          1885: #   ifdef IRIX5
        !          1886:        /* Indirect system call may not always be easily available.     */
        !          1887:        /* We could call _read, but that would interfere with the       */
        !          1888:        /* libpthread interception of read.                             */
        !          1889:        {
        !          1890:            struct iovec iov;
        !          1891:
        !          1892:            iov.iov_base = buf;
        !          1893:            iov.iov_len = nbyte;
        !          1894:            result = readv(fd, &iov, 1);
        !          1895:        }
        !          1896: #   else
        !          1897:        result = syscall(SYS_read, fd, buf, nbyte);
        !          1898: #   endif
        !          1899:     GC_end_syscall();
        !          1900:     return(result);
        !          1901: }
        !          1902: #endif /* !MSWIN32 */
        !          1903:
        !          1904: /*ARGSUSED*/
        !          1905: GC_bool GC_page_was_ever_dirty(h)
        !          1906: struct hblk *h;
        !          1907: {
        !          1908:     return(TRUE);
        !          1909: }
        !          1910:
        !          1911: /* Reset the n pages starting at h to "was never dirty" status.        */
        !          1912: /*ARGSUSED*/
        !          1913: void GC_is_fresh(h, n)
        !          1914: struct hblk *h;
        !          1915: word n;
        !          1916: {
        !          1917: }
        !          1918:
        !          1919: # endif /* MPROTECT_VDB */
        !          1920:
        !          1921: # ifdef PROC_VDB
        !          1922:
        !          1923: /*
        !          1924:  * See DEFAULT_VDB for interface descriptions.
        !          1925:  */
        !          1926:
        !          1927: /*
        !          1928:  * This implementaion assumes a Solaris 2.X like /proc pseudo-file-system
        !          1929:  * from which we can read page modified bits.  This facility is far from
        !          1930:  * optimal (e.g. we would like to get the info for only some of the
        !          1931:  * address space), but it avoids intercepting system calls.
        !          1932:  */
        !          1933:
        !          1934: #include <errno.h>
        !          1935: #include <sys/types.h>
        !          1936: #include <sys/signal.h>
        !          1937: #include <sys/fault.h>
        !          1938: #include <sys/syscall.h>
        !          1939: #include <sys/procfs.h>
        !          1940: #include <sys/stat.h>
        !          1941: #include <fcntl.h>
        !          1942:
        !          1943: #define INITIAL_BUF_SZ 4096
        !          1944: word GC_proc_buf_size = INITIAL_BUF_SZ;
        !          1945: char *GC_proc_buf;
        !          1946:
        !          1947: #ifdef SOLARIS_THREADS
        !          1948: /* We don't have exact sp values for threads.  So we count on  */
        !          1949: /* occasionally declaring stack pages to be fresh.  Thus we    */
        !          1950: /* need a real implementation of GC_is_fresh.  We can't clear  */
        !          1951: /* entries in GC_written_pages, since that would declare all   */
        !          1952: /* pages with the given hash address to be fresh.              */
        !          1953: #   define MAX_FRESH_PAGES 8*1024      /* Must be power of 2 */
        !          1954:     struct hblk ** GC_fresh_pages;     /* A direct mapped cache.       */
        !          1955:                                        /* Collisions are dropped.      */
        !          1956:
        !          1957: #   define FRESH_PAGE_SLOT(h) (divHBLKSZ((word)(h)) & (MAX_FRESH_PAGES-1))
        !          1958: #   define ADD_FRESH_PAGE(h) \
        !          1959:        GC_fresh_pages[FRESH_PAGE_SLOT(h)] = (h)
        !          1960: #   define PAGE_IS_FRESH(h) \
        !          1961:        (GC_fresh_pages[FRESH_PAGE_SLOT(h)] == (h) && (h) != 0)
        !          1962: #endif
        !          1963:
        !          1964: /* Add all pages in pht2 to pht1 */
        !          1965: void GC_or_pages(pht1, pht2)
        !          1966: page_hash_table pht1, pht2;
        !          1967: {
        !          1968:     register int i;
        !          1969:
        !          1970:     for (i = 0; i < PHT_SIZE; i++) pht1[i] |= pht2[i];
        !          1971: }
        !          1972:
        !          1973: int GC_proc_fd;
        !          1974:
        !          1975: void GC_dirty_init()
        !          1976: {
        !          1977:     int fd;
        !          1978:     char buf[30];
        !          1979:
        !          1980:     GC_dirty_maintained = TRUE;
        !          1981:     if (GC_words_allocd != 0 || GC_words_allocd_before_gc != 0) {
        !          1982:        register int i;
        !          1983:
        !          1984:         for (i = 0; i < PHT_SIZE; i++) GC_written_pages[i] = (word)(-1);
        !          1985: #       ifdef PRINTSTATS
        !          1986:            GC_printf1("Allocated words:%lu:all pages may have been written\n",
        !          1987:                       (unsigned long)
        !          1988:                                (GC_words_allocd + GC_words_allocd_before_gc));
        !          1989: #      endif
        !          1990:     }
        !          1991:     sprintf(buf, "/proc/%d", getpid());
        !          1992:     fd = open(buf, O_RDONLY);
        !          1993:     if (fd < 0) {
        !          1994:        ABORT("/proc open failed");
        !          1995:     }
        !          1996:     GC_proc_fd = syscall(SYS_ioctl, fd, PIOCOPENPD, 0);
        !          1997:     close(fd);
        !          1998:     if (GC_proc_fd < 0) {
        !          1999:        ABORT("/proc ioctl failed");
        !          2000:     }
        !          2001:     GC_proc_buf = GC_scratch_alloc(GC_proc_buf_size);
        !          2002: #   ifdef SOLARIS_THREADS
        !          2003:        GC_fresh_pages = (struct hblk **)
        !          2004:          GC_scratch_alloc(MAX_FRESH_PAGES * sizeof (struct hblk *));
        !          2005:        if (GC_fresh_pages == 0) {
        !          2006:            GC_err_printf0("No space for fresh pages\n");
        !          2007:            EXIT();
        !          2008:        }
        !          2009:        BZERO(GC_fresh_pages, MAX_FRESH_PAGES * sizeof (struct hblk *));
        !          2010: #   endif
        !          2011: }
        !          2012:
        !          2013: /* Ignore write hints. They don't help us here.        */
        !          2014: /*ARGSUSED*/
        !          2015: void GC_write_hint(h)
        !          2016: struct hblk *h;
        !          2017: {
        !          2018: }
        !          2019:
        !          2020: #ifdef SOLARIS_THREADS
        !          2021: #   define READ(fd,buf,nbytes) syscall(SYS_read, fd, buf, nbytes)
        !          2022: #else
        !          2023: #   define READ(fd,buf,nbytes) read(fd, buf, nbytes)
        !          2024: #endif
        !          2025:
        !          2026: void GC_read_dirty()
        !          2027: {
        !          2028:     unsigned long ps, np;
        !          2029:     int nmaps;
        !          2030:     ptr_t vaddr;
        !          2031:     struct prasmap * map;
        !          2032:     char * bufp;
        !          2033:     ptr_t current_addr, limit;
        !          2034:     int i;
        !          2035: int dummy;
        !          2036:
        !          2037:     BZERO(GC_grungy_pages, (sizeof GC_grungy_pages));
        !          2038:
        !          2039:     bufp = GC_proc_buf;
        !          2040:     if (READ(GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
        !          2041: #      ifdef PRINTSTATS
        !          2042:             GC_printf1("/proc read failed: GC_proc_buf_size = %lu\n",
        !          2043:                       GC_proc_buf_size);
        !          2044: #      endif
        !          2045:         {
        !          2046:             /* Retry with larger buffer. */
        !          2047:             word new_size = 2 * GC_proc_buf_size;
        !          2048:             char * new_buf = GC_scratch_alloc(new_size);
        !          2049:
        !          2050:             if (new_buf != 0) {
        !          2051:                 GC_proc_buf = bufp = new_buf;
        !          2052:                 GC_proc_buf_size = new_size;
        !          2053:             }
        !          2054:             if (syscall(SYS_read, GC_proc_fd, bufp, GC_proc_buf_size) <= 0) {
        !          2055:                 WARN("Insufficient space for /proc read\n", 0);
        !          2056:                 /* Punt:       */
        !          2057:                memset(GC_grungy_pages, 0xff, sizeof (page_hash_table));
        !          2058:                memset(GC_written_pages, 0xff, sizeof(page_hash_table));
        !          2059: #              ifdef SOLARIS_THREADS
        !          2060:                    BZERO(GC_fresh_pages,
        !          2061:                          MAX_FRESH_PAGES * sizeof (struct hblk *));
        !          2062: #              endif
        !          2063:                return;
        !          2064:             }
        !          2065:         }
        !          2066:     }
        !          2067:     /* Copy dirty bits into GC_grungy_pages */
        !          2068:        nmaps = ((struct prpageheader *)bufp) -> pr_nmap;
        !          2069:        /* printf( "nmaps = %d, PG_REFERENCED = %d, PG_MODIFIED = %d\n",
        !          2070:                     nmaps, PG_REFERENCED, PG_MODIFIED); */
        !          2071:        bufp = bufp + sizeof(struct prpageheader);
        !          2072:        for (i = 0; i < nmaps; i++) {
        !          2073:            map = (struct prasmap *)bufp;
        !          2074:            vaddr = (ptr_t)(map -> pr_vaddr);
        !          2075:            ps = map -> pr_pagesize;
        !          2076:            np = map -> pr_npage;
        !          2077:            /* printf("vaddr = 0x%X, ps = 0x%X, np = 0x%X\n", vaddr, ps, np); */
        !          2078:            limit = vaddr + ps * np;
        !          2079:            bufp += sizeof (struct prasmap);
        !          2080:            for (current_addr = vaddr;
        !          2081:                 current_addr < limit; current_addr += ps){
        !          2082:                if ((*bufp++) & PG_MODIFIED) {
        !          2083:                    register struct hblk * h = (struct hblk *) current_addr;
        !          2084:
        !          2085:                    while ((ptr_t)h < current_addr + ps) {
        !          2086:                        register word index = PHT_HASH(h);
        !          2087:
        !          2088:                        set_pht_entry_from_index(GC_grungy_pages, index);
        !          2089: #                      ifdef SOLARIS_THREADS
        !          2090:                          {
        !          2091:                            register int slot = FRESH_PAGE_SLOT(h);
        !          2092:
        !          2093:                            if (GC_fresh_pages[slot] == h) {
        !          2094:                                GC_fresh_pages[slot] = 0;
        !          2095:                            }
        !          2096:                          }
        !          2097: #                      endif
        !          2098:                        h++;
        !          2099:                    }
        !          2100:                }
        !          2101:            }
        !          2102:            bufp += sizeof(long) - 1;
        !          2103:            bufp = (char *)((unsigned long)bufp & ~(sizeof(long)-1));
        !          2104:        }
        !          2105:     /* Update GC_written_pages. */
        !          2106:         GC_or_pages(GC_written_pages, GC_grungy_pages);
        !          2107: #   ifdef SOLARIS_THREADS
        !          2108:       /* Make sure that old stacks are considered completely clean     */
        !          2109:       /* unless written again.                                         */
        !          2110:        GC_old_stacks_are_fresh();
        !          2111: #   endif
        !          2112: }
        !          2113:
        !          2114: #undef READ
        !          2115:
        !          2116: GC_bool GC_page_was_dirty(h)
        !          2117: struct hblk *h;
        !          2118: {
        !          2119:     register word index = PHT_HASH(h);
        !          2120:     register GC_bool result;
        !          2121:
        !          2122:     result = get_pht_entry_from_index(GC_grungy_pages, index);
        !          2123: #   ifdef SOLARIS_THREADS
        !          2124:        if (result && PAGE_IS_FRESH(h)) result = FALSE;
        !          2125:        /* This happens only if page was declared fresh since   */
        !          2126:        /* the read_dirty call, e.g. because it's in an unused  */
        !          2127:        /* thread stack.  It's OK to treat it as clean, in      */
        !          2128:        /* that case.  And it's consistent with                 */
        !          2129:        /* GC_page_was_ever_dirty.                              */
        !          2130: #   endif
        !          2131:     return(result);
        !          2132: }
        !          2133:
        !          2134: GC_bool GC_page_was_ever_dirty(h)
        !          2135: struct hblk *h;
        !          2136: {
        !          2137:     register word index = PHT_HASH(h);
        !          2138:     register GC_bool result;
        !          2139:
        !          2140:     result = get_pht_entry_from_index(GC_written_pages, index);
        !          2141: #   ifdef SOLARIS_THREADS
        !          2142:        if (result && PAGE_IS_FRESH(h)) result = FALSE;
        !          2143: #   endif
        !          2144:     return(result);
        !          2145: }
        !          2146:
        !          2147: /* Caller holds allocation lock.       */
        !          2148: void GC_is_fresh(h, n)
        !          2149: struct hblk *h;
        !          2150: word n;
        !          2151: {
        !          2152:
        !          2153:     register word index;
        !          2154:
        !          2155: #   ifdef SOLARIS_THREADS
        !          2156:       register word i;
        !          2157:
        !          2158:       if (GC_fresh_pages != 0) {
        !          2159:         for (i = 0; i < n; i++) {
        !          2160:           ADD_FRESH_PAGE(h + i);
        !          2161:         }
        !          2162:       }
        !          2163: #   endif
        !          2164: }
        !          2165:
        !          2166: # endif /* PROC_VDB */
        !          2167:
        !          2168:
        !          2169: # ifdef PCR_VDB
        !          2170:
        !          2171: # include "vd/PCR_VD.h"
        !          2172:
        !          2173: # define NPAGES (32*1024)      /* 128 MB */
        !          2174:
        !          2175: PCR_VD_DB  GC_grungy_bits[NPAGES];
        !          2176:
        !          2177: ptr_t GC_vd_base;      /* Address corresponding to GC_grungy_bits[0]   */
        !          2178:                        /* HBLKSIZE aligned.                            */
        !          2179:
        !          2180: void GC_dirty_init()
        !          2181: {
        !          2182:     GC_dirty_maintained = TRUE;
        !          2183:     /* For the time being, we assume the heap generally grows up */
        !          2184:     GC_vd_base = GC_heap_sects[0].hs_start;
        !          2185:     if (GC_vd_base == 0) {
        !          2186:        ABORT("Bad initial heap segment");
        !          2187:     }
        !          2188:     if (PCR_VD_Start(HBLKSIZE, GC_vd_base, NPAGES*HBLKSIZE)
        !          2189:        != PCR_ERes_okay) {
        !          2190:        ABORT("dirty bit initialization failed");
        !          2191:     }
        !          2192: }
        !          2193:
        !          2194: void GC_read_dirty()
        !          2195: {
        !          2196:     /* lazily enable dirty bits on newly added heap sects */
        !          2197:     {
        !          2198:         static int onhs = 0;
        !          2199:         int nhs = GC_n_heap_sects;
        !          2200:         for( ; onhs < nhs; onhs++ ) {
        !          2201:             PCR_VD_WriteProtectEnable(
        !          2202:                     GC_heap_sects[onhs].hs_start,
        !          2203:                     GC_heap_sects[onhs].hs_bytes );
        !          2204:         }
        !          2205:     }
        !          2206:
        !          2207:
        !          2208:     if (PCR_VD_Clear(GC_vd_base, NPAGES*HBLKSIZE, GC_grungy_bits)
        !          2209:         != PCR_ERes_okay) {
        !          2210:        ABORT("dirty bit read failed");
        !          2211:     }
        !          2212: }
        !          2213:
        !          2214: GC_bool GC_page_was_dirty(h)
        !          2215: struct hblk *h;
        !          2216: {
        !          2217:     if((ptr_t)h < GC_vd_base || (ptr_t)h >= GC_vd_base + NPAGES*HBLKSIZE) {
        !          2218:        return(TRUE);
        !          2219:     }
        !          2220:     return(GC_grungy_bits[h - (struct hblk *)GC_vd_base] & PCR_VD_DB_dirtyBit);
        !          2221: }
        !          2222:
        !          2223: /*ARGSUSED*/
        !          2224: void GC_write_hint(h)
        !          2225: struct hblk *h;
        !          2226: {
        !          2227:     PCR_VD_WriteProtectDisable(h, HBLKSIZE);
        !          2228:     PCR_VD_WriteProtectEnable(h, HBLKSIZE);
        !          2229: }
        !          2230:
        !          2231: # endif /* PCR_VDB */
        !          2232:
        !          2233: /*
        !          2234:  * Call stack save code for debugging.
        !          2235:  * Should probably be in mach_dep.c, but that requires reorganization.
        !          2236:  */
        !          2237: #if defined(SPARC) && !defined(LINUX)
        !          2238: #   if defined(SUNOS4)
        !          2239: #     include <machine/frame.h>
        !          2240: #   else
        !          2241: #     if defined (DRSNX)
        !          2242: #      include <sys/sparc/frame.h>
        !          2243: #     else
        !          2244: #       include <sys/frame.h>
        !          2245: #     endif
        !          2246: #   endif
        !          2247: #   if NARGS > 6
        !          2248:        --> We only know how to to get the first 6 arguments
        !          2249: #   endif
        !          2250:
        !          2251: #ifdef SAVE_CALL_CHAIN
        !          2252: /* Fill in the pc and argument information for up to NFRAMES of my     */
        !          2253: /* callers.  Ignore my frame and my callers frame.                     */
        !          2254: void GC_save_callers (info)
        !          2255: struct callinfo info[NFRAMES];
        !          2256: {
        !          2257:   struct frame *frame;
        !          2258:   struct frame *fp;
        !          2259:   int nframes = 0;
        !          2260:   word GC_save_regs_in_stack();
        !          2261:
        !          2262:   frame = (struct frame *) GC_save_regs_in_stack ();
        !          2263:
        !          2264:   for (fp = frame -> fr_savfp; fp != 0 && nframes < NFRAMES;
        !          2265:        fp = fp -> fr_savfp, nframes++) {
        !          2266:       register int i;
        !          2267:
        !          2268:       info[nframes].ci_pc = fp->fr_savpc;
        !          2269:       for (i = 0; i < NARGS; i++) {
        !          2270:        info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
        !          2271:       }
        !          2272:   }
        !          2273:   if (nframes < NFRAMES) info[nframes].ci_pc = 0;
        !          2274: }
        !          2275:
        !          2276: #endif /* SAVE_CALL_CHAIN */
        !          2277: #endif /* SPARC */
        !          2278:
        !          2279:
        !          2280:

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