/* * Copyright (c) 1991-1993 by Xerox Corporation. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. * * Permission is hereby granted to copy this garbage collector for any purpose, * provided the above notices are retained on all copies. */ # include "gc←private.h" # include <stdio.h> # include <signal.h> /* Blatantly OS dependent routines, except for those that are related */ /* dynamic loading. */ # ifdef SUNOS5 # undef sigmask # endif /* Disable and enable signals during nontrivial allocations */ # ifdef OS2 # define INCL←DOSEXCEPTIONS # define INCL←DOSPROCESS # define INCL←DOSERRORS # define INCL←DOSMODULEMGR # include <os2.h> /* A kludge to get around what appears to be a header file bug */ # ifndef WORD # define WORD unsigned short # endif # ifndef DWORD # define DWORD unsigned long # endif # define EXE386 1 # include <newexe.h> # include <exe386.h> void GC←disable←signals(void) { ULONG nest; DosEnterMustComplete(&nest); if (nest != 1) ABORT("nested GC←disable←signals"); } void GC←enable←signals(void) { ULONG nest; DosExitMustComplete(&nest); if (nest != 0) ABORT("GC←enable←signals"); } # else # ifndef PCR # ifdef sigmask /* Use the traditional BSD interface */ # define SIGSET←T int # define SIG←DEL(set, signal) (set) &= ~(sigmask(signal)) # define SIG←FILL(set) (set) = 0x7fffffff /* Setting the leading bit appears to provoke a bug in some */ /* longjmp implementations. Most systems appear not to have */ /* a signal 32. */ # define SIGSETMASK(old, new) (old) = sigsetmask(new) # else /* Use POSIX/SYSV interface */ # define SIGSET←T sigset←t # define SIG←DEL(set, signal) sigdelset(&(set), (signal)) # define SIG←FILL(set) sigfillset(&set) # define SIGSETMASK(old, new) sigprocmask(SIG←SETMASK, &(new), &(old)) # endif static bool mask←initialized = FALSE; static SIGSET←T new←mask; static SIGSET←T old←mask; static SIGSET←T dummy; void GC←disable←signals() { if (!mask←initialized) { SIG←FILL(new←mask); SIG←DEL(new←mask, SIGSEGV); SIG←DEL(new←mask, SIGILL); SIG←DEL(new←mask, SIGQUIT); # ifdef SIGBUS SIG←DEL(new←mask, SIGBUS); # endif # ifdef SIGIOT SIG←DEL(new←mask, SIGIOT); # endif # ifdef SIGEMT SIG←DEL(new←mask, SIGEMT); # endif # ifdef SIGTRAP SIG←DEL(new←mask, SIGTRAP); # endif mask←initialized = TRUE; } SIGSETMASK(old←mask,new←mask); } void GC←enable←signals() { SIGSETMASK(dummy,old←mask); } # endif /* !PCR */ # endif /*!OS/2 */ /* * Find the base of the stack. * Used only in single-threaded environment. * With threads, GC←mark←roots needs to know how to do this. * Called with allocator lock held. */ # ifdef OS2 ptr←t GC←get←stack←base() { PTIB ptib; PPIB ppib; if (DosGetInfoBlocks(&ptib, &ppib) != NO←ERROR) { GC←err←printf0("DosGetInfoBlocks failed\n"); ABORT("DosGetInfoBlocks failed\n"); } return((ptr←t)(ptib -> tib←pstacklimit)); } # else # if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2) /* Some tools to implement HEURISTIC2 */ # define MIN←PAGE←SIZE 256 /* Smallest conceivable page size, bytes */ # include <setjmp.h> /* static */ jmp←buf GC←jmp←buf; /*ARGSUSED*/ void GC←fault←handler(sig) int sig; { longjmp(GC←jmp←buf, 1); } # endif ptr←t GC←get←stack←base() { word dummy; static ptr←t result; /* Needs to be static, since otherwise it may not be */ /* preserved across the longjmp. Can safely be */ /* static since it's only called once, with the */ /* allocation lock held. */ # ifdef ←←STDC←← typedef void (*handler)(int); # else typedef void (*handler)(); # endif # ifdef HEURISTIC2 static handler old←segv←handler, old←bus←handler; /* See above for static declaration. */ # endif # define STACKBOTTOM←ALIGNMENT←M1 0xffffff # ifdef STACKBOTTOM return(STACKBOTTOM); # else # ifdef HEURISTIC1 # ifdef STACK←GROWS←DOWN result = (ptr←t)((((word)(&dummy)) + STACKBOTTOM←ALIGNMENT←M1) & ~STACKBOTTOM←ALIGNMENT←M1); # else result = (ptr←t)(((word)(&dummy)) & ~STACKBOTTOM←ALIGNMENT←M1); # endif # endif /* HEURISTIC1 */ # ifdef HEURISTIC2 old←segv←handler = signal(SIGSEGV, GC←fault←handler); # ifdef SIGBUS old←bus←handler = signal(SIGBUS, GC←fault←handler); # endif if (setjmp(GC←jmp←buf) == 0) { result = (ptr←t)(((word)(&dummy)) & ~(MIN←PAGE←SIZE-1)); for (;;) { # ifdef STACK←GROWS←DOWN result += MIN←PAGE←SIZE; # else result -= MIN←PAGE←SIZE; # endif GC←noop(*result); } } (void) signal(SIGSEGV, old←segv←handler); # ifdef SIGBUS (void) signal(SIGBUS, old←bus←handler); # endif # ifdef STACK←GROWS←UP result += MIN←PAGE←SIZE; # endif # endif /* HEURISTIC2 */ return(result); # endif /* STACKBOTTOM */ } # endif /* ! OS2 */ /* * Register static data segment(s) as roots. * If more data segments are added later then they need to be registered * add that point (as we do with SunOS dynamic loading), * or GC←mark←roots needs to check for them (as we do with PCR). * Called with allocator lock held. */ # ifdef OS2 void GC←register←data←segments() { PTIB ptib; PPIB ppib; HMODULE module←handle; # define PBUFSIZ 512 UCHAR path[PBUFSIZ]; FILE * myexefile; struct exe←hdr hdrdos; /* MSDOS header. */ struct e32←exe hdr386; /* Real header for my executable */ struct o32←obj seg; /* Currrent segment */ int nsegs; if (DosGetInfoBlocks(&ptib, &ppib) != NO←ERROR) { GC←err←printf0("DosGetInfoBlocks failed\n"); ABORT("DosGetInfoBlocks failed\n"); } module←handle = ppib -> pib←hmte; if (DosQueryModuleName(module←handle, PBUFSIZ, path) != NO←ERROR) { GC←err←printf0("DosQueryModuleName failed\n"); ABORT("DosGetInfoBlocks failed\n"); } myexefile = fopen(path, "rb"); if (myexefile == 0) { GC←err←puts("Couldn't open executable "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Failed to open executable\n"); } if (fread((char *)(&hdrdos), 1, sizeof hdrdos, myexefile) < sizeof hdrdos) { GC←err←puts("Couldn't read MSDOS header from "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Couldn't read MSDOS header"); } if (E←MAGIC(hdrdos) != EMAGIC) { GC←err←puts("Executable has wrong DOS magic number: "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Bad DOS magic number"); } if (fseek(myexefile, E←LFANEW(hdrdos), SEEK←SET) != 0) { GC←err←puts("Seek to new header failed in "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Bad DOS magic number"); } if (fread((char *)(&hdr386), 1, sizeof hdr386, myexefile) < sizeof hdr386) { GC←err←puts("Couldn't read MSDOS header from "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Couldn't read OS/2 header"); } if (E32←MAGIC1(hdr386) != E32MAGIC1 || E32←MAGIC2(hdr386) != E32MAGIC2) { GC←err←puts("Executable has wrong OS/2 magic number:"); GC←err←puts(path); GC←err←puts("\n"); ABORT("Bad OS/2 magic number"); } if ( E32←BORDER(hdr386) != E32LEBO || E32←WORDER(hdr386) != E32LEWO) { GC←err←puts("Executable %s has wrong byte order: "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Bad byte order"); } if ( E32←CPU(hdr386) == E32CPU286) { GC←err←puts("GC can't handle 80286 executables: "); GC←err←puts(path); GC←err←puts("\n"); EXIT(); } if (fseek(myexefile, E←LFANEW(hdrdos) + E32←OBJTAB(hdr386), SEEK←SET) != 0) { GC←err←puts("Seek to object table failed: "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Seek to object table failed"); } for (nsegs = E32←OBJCNT(hdr386); nsegs > 0; nsegs--) { int flags; if (fread((char *)(&seg), 1, sizeof seg, myexefile) < sizeof seg) { GC←err←puts("Couldn't read obj table entry from "); GC←err←puts(path); GC←err←puts("\n"); ABORT("Couldn't read obj table entry"); } flags = O32←FLAGS(seg); if (!(flags & OBJWRITE)) continue; if (!(flags & OBJREAD)) continue; if (flags & OBJINVALID) { GC←err←printf0("Object with invalid pages?\n"); continue; } GC←add←roots←inner(O32←BASE(seg), O32←BASE(seg)+O32←SIZE(seg)); } } # else void GC←register←data←segments() { extern int end; # ifndef PCR GC←add←roots←inner(DATASTART, (char *)(&end)); # endif /* Dynamic libraries are added at every collection, since they may */ /* change. */ } # endif /* ! OS2 */