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

Annotation of OpenXM_contrib2/asir2000/gc/os_dep.c, Revision 1.1

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

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