This is the mail archive of the
guile@sources.redhat.com
mailing list for the Guile project.
Re: GUILE's GC - why we struggling to solve already solved problems ? (was Re: finding the top of the stack in linux)
- To: djurfeldt at nada dot kth dot se, mdj at mdj dot nada dot kth dot se
- Subject: Re: GUILE's GC - why we struggling to solve already solved problems ? (was Re: finding the top of the stack in linux)
- From: "Khimenko Victor" <guile at khim dot sch57 dot msk dot ru>
- Date: Sat, 5 Aug 2000 16:45:34 +0400 (MSD)
- Cc: hanwen at cs dot uu dot nl, guile at sourceware dot cygnus dot com, crayc at kiwi dot pyro dot net
- Organization: MCCME
- References: <ADfHTXvOPM@khim.sch57.msk.ru> <xy7ya2ncbcf.fsf@mdj.nada.kth.se> <14707.2884.864156.799999@dokkum.cs.uu.nl> <ABlUpSv8P1@khim.sch57.msk.ru>
31-Jul-00 23:32 you wrote:
> 28-Jul-00 03:06 you wrote:
>> "Khimenko Victor" <guile@khim.sch57.msk.ru> writes:
>>> But why the hell we are [...] not even using clearly
>>> appropriate parts (like stack placement finding subroitine) from ALREADY
>>> existing and TESTED solutions.
>> [...]
>>> we still can use parts of it to determine stack placement on
>>> different systems.
>> Would you be willing to cut out and prepare the stack finding code for
>> Guile?
> I will try to do it. It's not trivial, unfortunatelly. It's easy to cut this
> code. It's MUCH harder to do so correct. As you can guess it's big pile of
> #ifdef's (if it's Linux then we do it this way, if it's HP-UX then that way
> and if it's Win32 then still another code is used) and so we have verification
> problem :-/ Plus there are other question: how to do this - manual cut and
> paste with tuning or script to convert from GC_ to scm_GC prefix and strip
> out unneeded code from appropriate .h and .c files ? Manual way is easier
> but then we'll need to repeat this process once every month or two (when new
> version of BGC is out).
After some thought I decided to do this manually. Basically stack detection
stuff in BGC has two parts: big, big heap of #ifdef's in gcconfig.h and this
part is VERY straight and much less pleasant heap of #ifdef's in os_dep to
decide what .h files one need to include for all definitions. This part in
guile should be handled by autoconf, I guess. Core is really simple: and
explained well by Boehm:
/*
* STACKBOTTOM is the cool end of the stack, which is usually the
* highest address in the stack.
* Under PCR or OS/2, we have other ways of finding thread stacks.
* For each machine, the following should:
* 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
* 2) define exactly one of
* STACKBOTTOM (should be defined to be an expression)
* HEURISTIC1
* HEURISTIC2
* If either of the last two macros are defined, then STACKBOTTOM is computed
* during collector startup using one of the following two heuristics:
* HEURISTIC1: Take an address inside GC_init's frame, and round it up to
* the next multiple of STACK_GRAN.
* HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly
* in small steps (decrement if STACK_GROWS_UP), and read the value
* at each location. Remember the value when the first
* Segmentation violation or Bus error is signalled. Round that
* to the nearest plausible page boundary, and use that instead
* of STACKBOTTOM.
*/
Thus implementation is simple enough, but since along with stack bottom
detection there are various interesting things are handled as well (data
segment, heap, etc) I removed most of code from both files. It works here
on Linux (with HEURISTIC1, HEURISTIC2 and LINUX_STACKBOTTOM - special version
with /proc usage) but I'm pretty sure I removed some important check and thus
on other platforms it can be broken.
It needs simple function somewhere in other file:
-- cut --
void scm_stack_noop1(word x)
{
static volatile word sink;
sink = x;
}
-- cut --
It must be put in separate file so even VERY "advanced" compiler will not
optimize this call away. Only one function is provided:
void * scm_get_stack_base();
P.S. OS2, Win32 and AMIGA are handled separately and since I have no way to
check them I'm pretty sure right now it does not work there :-/
/*
* This file was created by extracting bits from Boehm's GC
* (see http://somwhere.there/ for more info )
*
* If it does not work (or more likely does not compile) for you on system
* where Boehm's GC works then probably it can be fixed with easy: you need
* minimal C knowleadge, some brain and last but not least acess to system
* headers so you can find right headers combination. If Boehm's GC does not
* work for you then it'll be MUCH harder task.
*/
/*
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
* Copyright (c) 2000 by Hewlett-Packard Company. 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 use or copy this program
* for any purpose, provided the above notices are retained on all copies.
* Permission to modify the code and to distribute modified code is granted,
* provided the above notices are retained, and a notice that the code was
* modified is included with the above copyright notice.
*/
/* First a unified test for Linux: */
# if defined(linux) || defined(__linux__)
# define LINUX
# endif
/* Determine the machine type: */
# if defined(sun) && defined(mc68000)
# define M68K
# define SUNOS4
# define mach_type_known
# endif
# if defined(hp9000s300)
# define M68K
# define HP
# define mach_type_known
# endif
# if defined(__OpenBSD__) && defined(m68k)
# define M68K
# define OPENBSD
# define mach_type_known
# endif
# if defined(__OpenBSD__) && defined(__sparc__)
# define SPARC
# define OPENBSD
# define mach_type_known
# endif
# if defined(__NetBSD__) && defined(m68k)
# define M68K
# define NETBSD
# define mach_type_known
# endif
# if defined(__NetBSD__) && defined(arm32)
# define ARM32
# define NETBSD
# define mach_type_known
# endif
# if defined(vax)
# define VAX
# ifdef ultrix
# define ULTRIX
# else
# define BSD
# endif
# define mach_type_known
# endif
# if defined(mips) || defined(__mips)
# define MIPS
# if !defined(LINUX)
# if defined(ultrix) || defined(__ultrix) || defined(__NetBSD__)
# define ULTRIX
# else
# if defined(_SYSTYPE_SVR4) || defined(SYSTYPE_SVR4) \
|| defined(__SYSTYPE_SVR4__)
# define IRIX5 /* or IRIX 6.X */
# else
# define RISCOS /* or IRIX 4.X */
# endif
# endif
# endif /* !LINUX */
# define mach_type_known
# endif
# if defined(sequent) && defined(i386)
# define I386
# define SEQUENT
# define mach_type_known
# endif
# if defined(sun) && defined(i386)
# define I386
# define SUNOS5
# define mach_type_known
# endif
# if (defined(__OS2__) || defined(__EMX__)) && defined(__32BIT__)
# define I386
# define OS2
# define mach_type_known
# endif
# if defined(ibm032)
# define RT
# define mach_type_known
# endif
# if defined(sun) && (defined(sparc) || defined(__sparc))
# define SPARC
/* Test for SunOS 5.x */
# include <errno.h>
# ifdef ECHRNG
# define SUNOS5
# else
# define SUNOS4
# endif
# define mach_type_known
# endif
# if defined(sparc) && defined(unix) && !defined(sun) && !defined(linux) \
&& !defined(__OpenBSD__)
# define SPARC
# define DRSNX
# define mach_type_known
# endif
# if defined(_IBMR2)
# define RS6000
# define mach_type_known
# endif
# if defined(_M_XENIX) && defined(_M_SYSV) && defined(_M_I386)
/* The above test may need refinement */
# define I386
# if defined(_SCO_ELF)
# define SCO_ELF
# else
# define SCO
# endif
# define mach_type_known
# endif
# if defined(_AUX_SOURCE)
# define M68K
# define SYSV
# define mach_type_known
# endif
# if defined(_PA_RISC1_0) || defined(_PA_RISC1_1) || defined(_PA_RISC2_0) \
|| defined(hppa) || defined(__hppa__)
# define HP_PA
# ifndef LINUX
# define HPUX
# endif
# define mach_type_known
# endif
# if defined(LINUX) && (defined(i386) || defined(__i386__))
# define I386
# define mach_type_known
# endif
# if defined(LINUX) && (defined(__ia64__) || defined(__ia64))
# define IA64
# define mach_type_known
# endif
# if defined(LINUX) && defined(powerpc)
# define POWERPC
# define mach_type_known
# endif
# if defined(LINUX) && defined(__mc68000__)
# define M68K
# define mach_type_known
# endif
# if defined(LINUX) && (defined(sparc) || defined(__sparc__))
# define SPARC
# define mach_type_known
# endif
# if defined(LINUX) && defined(arm)
# define ARM32
# define mach_type_known
# endif
# if defined(__alpha) || defined(__alpha__)
# define ALPHA
# if !defined(LINUX)
# define OSF1 /* a.k.a Digital Unix */
# endif
# define mach_type_known
# endif
# if defined(_AMIGA) && !defined(AMIGA)
# define AMIGA
# endif
# ifdef AMIGA
# define M68K
# define mach_type_known
# endif
# if defined(THINK_C) || defined(__MWERKS__) && !defined(__powerc)
# define M68K
# define MACOS
# define mach_type_known
# endif
# if defined(__MWERKS__) && defined(__powerc)
# define POWERPC
# define MACOS
# define mach_type_known
# endif
# if defined(macosx) || \
defined(__APPLE__) && defined(__MACH__) && defined(__ppc__)
# define MACOSX
# define POWERPC
# define mach_type_known
# endif
# if defined(__APPLE__) && defined(__MACH__) && defined(__i386__)
# define MACOSX
# define I386
--> Not really supported, but at least we recognize it.
# endif
# if defined(NeXT) && defined(mc68000)
# define M68K
# define NEXT
# define mach_type_known
# endif
# if defined(NeXT) && defined(i386)
# define I386
# define NEXT
# define mach_type_known
# endif
# if defined(__OpenBSD__) && defined(i386)
# define I386
# define OPENBSD
# define mach_type_known
# endif
# if defined(__FreeBSD__) && defined(i386)
# define I386
# define FREEBSD
# define mach_type_known
# endif
# if defined(__NetBSD__) && defined(i386)
# define I386
# define NETBSD
# define mach_type_known
# endif
# if defined(bsdi) && defined(i386)
# define I386
# define BSDI
# define mach_type_known
# endif
# if !defined(mach_type_known) && defined(__386BSD__)
# define I386
# define THREE86BSD
# define mach_type_known
# endif
# if defined(_CX_UX) && defined(_M88K)
# define M88K
# define CX_UX
# define mach_type_known
# endif
# if defined(DGUX)
# define M88K
/* DGUX defined */
# define mach_type_known
# endif
# if (defined(_MSDOS) || defined(_MSC_VER)) && (_M_IX86 >= 300) \
|| defined(_WIN32) && !defined(__CYGWIN32__) && !defined(__CYGWIN__)
# define I386
# define MSWIN32 /* or Win32s */
# define mach_type_known
# endif
# if defined(__DJGPP__)
# define I386
# ifndef DJGPP
# define DJGPP /* MSDOS running the DJGPP port of GCC */
# endif
# define mach_type_known
# endif
# if defined(__CYGWIN32__) || defined(__CYGWIN__)
# define I386
# define CYGWIN32
# define mach_type_known
# endif
# if defined(__MINGW32__)
# define I386
# define MSWIN32
# define mach_type_known
# endif
# if defined(__BORLANDC__)
# define I386
# define MSWIN32
# define mach_type_known
# endif
# if defined(_UTS) && !defined(mach_type_known)
# define S370
# define UTS4
# define mach_type_known
# endif
# if defined(__pj__)
# define PJ
# define mach_type_known
# endif
/* Ivan Demakov */
# if defined(__WATCOMC__) && defined(__386__)
# define I386
# if !defined(OS2) && !defined(MSWIN32) && !defined(DOS4GW)
# if defined(__OS2__)
# define OS2
# else
# if defined(__WINDOWS_386__) || defined(__NT__)
# define MSWIN32
# else
# define DOS4GW
# endif
# endif
# endif
# define mach_type_known
# endif
/* A machine type is characterized by the architecture. Some */
/* machine types are further subdivided by OS. */
/* the macros ULTRIX, RISCOS, and BSD to distinguish. */
/* Note that SGI IRIX is treated identically to RISCOS. */
/* SYSV on an M68K actually means A/UX. */
/* The distinction in these cases is usually the stack starting address */
/* Mapping is: M68K ==> Motorola 680X0 */
/* (SUNOS4,HP,NEXT, and SYSV (A/UX), */
/* MACOS and AMIGA variants) */
/* I386 ==> Intel 386 */
/* (SEQUENT, OS2, SCO, LINUX, NETBSD, */
/* FREEBSD, THREE86BSD, MSWIN32, */
/* BSDI,SUNOS5, NEXT, other variants) */
/* NS32K ==> Encore Multimax */
/* MIPS ==> R2000 or R3000 */
/* (RISCOS, ULTRIX variants) */
/* VAX ==> DEC VAX */
/* (BSD, ULTRIX variants) */
/* RS6000 ==> IBM RS/6000 AIX3.X */
/* RT ==> IBM PC/RT */
/* HP_PA ==> HP9000/700 & /800 */
/* HP/UX */
/* SPARC ==> SPARC v7/v8/v9 */
/* (SUNOS4, SUNOS5, LINUX, */
/* DRSNX variants) */
/* ALPHA ==> DEC Alpha */
/* (OSF1 and LINUX variants) */
/* M88K ==> Motorola 88XX0 */
/* (CX_UX and DGUX) */
/* S370 ==> 370-like machine */
/* running Amdahl UTS4 */
/* ARM32 ==> Intel StrongARM */
/* IA64 ==> Intel IA64 */
/* (e.g. Itanium) */
/*
* For each architecture and OS, the following need to be defined:
*
* MACH_TYPE is a string representation of the machine type.
* OS_TYPE is analogous for the OS.
*
* STACKBOTTOM is the cool end of the stack, which is usually the
* highest address in the stack.
* Under PCR or OS/2, we have other ways of finding thread stacks.
* For each machine, the following should:
* 1) define STACK_GROWS_UP if the stack grows toward higher addresses, and
* 2) define exactly one of
* STACKBOTTOM (should be defined to be an expression)
* HEURISTIC1
* HEURISTIC2
* If either of the last two macros are defined, then STACKBOTTOM is computed
* during collector startup using one of the following two heuristics:
* HEURISTIC1: Take an address inside GC_init's frame, and round it up to
* the next multiple of STACK_GRAN.
* HEURISTIC2: Take an address inside GC_init's frame, increment it repeatedly
* in small steps (decrement if STACK_GROWS_UP), and read the value
* at each location. Remember the value when the first
* Segmentation violation or Bus error is signalled. Round that
* to the nearest plausible page boundary, and use that instead
* of STACKBOTTOM.
*
* Gustavo Rodriguez-Rivera points out that on most (all?) Unix machines,
* the value of environ is a pointer that can serve as STACKBOTTOM.
* I expect that HEURISTIC2 can be replaced by this approach, which
* interferes far less with debugging.
*
*/
# define STACK_GRAN 0x1000000
# ifdef M68K
# define MACH_TYPE "M68K"
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
# define HEURISTIC2
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((void *)0xf0000000)
# endif
# ifdef SUNOS4
# define OS_TYPE "SUNOS4"
# define HEURISTIC1 /* differs */
# endif
# ifdef HP
# define OS_TYPE "HP"
# define STACKBOTTOM ((void *) 0xffeffffc)
/* empirically determined. seems to work. */
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
# endif
# ifdef SYSV
# define OS_TYPE "SYSV"
# define STACKBOTTOM ((void *)0xFFFFFFFE)
/* The stack starts at the top of memory, but */
/* 0x0 cannot be used as setjump_test complains */
/* that the stack direction is incorrect. Two */
/* bytes down from 0x0 should be safe enough. */
/* --Parag */
# include <sys/mmu.h>
# define GETPAGESIZE() PAGESIZE /* Is this still right? */
# endif
# ifdef AMIGA
# define OS_TYPE "AMIGA"
/* STACKBOTTOM is handled specially */
# define GETPAGESIZE() 4096
# endif
# ifdef MACOS
# ifndef __LOWMEM__
# include <LowMem.h>
# endif
# define OS_TYPE "MACOS"
# define STACKBOTTOM ((void *) LMGetCurStackBase())
# define GETPAGESIZE() 4096
# endif
# ifdef NEXT
# define OS_TYPE "NEXT"
# define STACKBOTTOM ((void *) 0x4000000)
# endif
# endif
# ifdef POWERPC
# define MACH_TYPE "POWERPC"
# ifdef MACOS
# ifndef __LOWMEM__
# include <LowMem.h>
# endif
# define OS_TYPE "MACOS"
# define STACKBOTTOM ((void *) LMGetCurStackBase())
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define HEURISTIC1
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
/* Stack usually starts at 0x80000000 */
# endif
# ifdef MACOSX
/* There are reasons to suspect this may not be reliable. */
# define OS_TYPE "MACOSX"
# define STACKBOTTOM ((void *) 0xc0000000)
# endif
# endif
# ifdef VAX
# define MACH_TYPE "VAX"
# ifdef BSD
# define OS_TYPE "BSD"
# define HEURISTIC1
/* HEURISTIC2 may be OK, but it's hard to test. */
# endif
# ifdef ULTRIX
# define OS_TYPE "ULTRIX"
# define STACKBOTTOM ((void *) 0x7fffc800)
# endif
# endif
# ifdef RT
# define MACH_TYPE "RT"
# define STACKBOTTOM ((void *) 0x1fffd800)
# endif
# ifdef SPARC
# define MACH_TYPE "SPARC"
# ifdef SUNOS5
# define OS_TYPE "SUNOS5"
/* HEURISTIC1 reportedly no longer works under 2.7. Thus we */
/* switched to HEURISTIC2, eventhough it creates some debugging */
/* issues. */
# define HEURISTIC2
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
/* getpagesize() appeared to be missing from at least one */
/* Solaris 5.4 installation. Weird. */
# endif
# ifdef SUNOS4
# define OS_TYPE "SUNOS4"
# define HEURISTIC1
# endif
# ifdef DRSNX
# define OS_TYPE "DRSNX"
# define STACKBOTTOM ((void *) 0xdfff0000)
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# ifdef __ELF__
# define DYNAMIC_LOADING
# else
Linux Sparc/a.out not supported
# endif
# define SVR4
# ifdef __arch64__
# define STACKBOTTOM ((void *) 0x80000000000ULL)
# else
# define STACKBOTTOM ((void *) 0xf0000000)
# endif
# endif
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
# define STACKBOTTOM ((void *) 0xf8000000)
# endif
# endif
# ifdef I386
# define MACH_TYPE "I386"
# ifdef SEQUENT
# define OS_TYPE "SEQUENT"
# define STACKBOTTOM ((void *) 0x3ffff000)
# endif
# ifdef SUNOS5
# define OS_TYPE "SUNOS5"
extern int _start;
# define STACKBOTTOM ((void *)(&_start))
# endif
# ifdef SCO
# define OS_TYPE "SCO"
# define STACKBOTTOM ((void *) 0x7ffffffc)
# endif
# ifdef SCO_ELF
# define OS_TYPE "SCO_ELF"
# define STACKBOTTOM ((void *) 0x08048000)
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define LINUX_STACKBOTTOM
# if 0
# define HEURISTIC1
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
/* STACKBOTTOM is usually 0xc0000000, but this changes with */
/* different kernel configurations. In particular, systems */
/* with 2GB physical memory will usually move the user */
/* address space limit, and hence initial SP to 0x80000000. */
# endif
# endif
# ifdef CYGWIN32
# define OS_TYPE "CYGWIN32"
# undef STACK_GRAN
# define STACK_GRAN 0x10000
# define HEURISTIC1
# endif
# ifdef OS2
# define OS_TYPE "OS2"
/* STACKBOTTOM is handled specially */
/* OS2 actually has the right system call! */
# endif
# ifdef MSWIN32
# define OS_TYPE "MSWIN32"
/* STACKBOTTOM is handled specially */
# endif
# ifdef DJGPP
# define OS_TYPE "DJGPP"
# include "stubinfo.h"
extern int _stklen;
extern int __djgpp_stack_limit;
/* # define STACKBOTTOM ((void *)((word) _stubinfo + _stubinfo->size \
+ _stklen)) */
# define STACKBOTTOM ((void *)((word) __djgpp_stack_limit + _stklen))
/* This may not be right. */
# endif
# ifdef OPENBSD
# define OS_TYPE "OPENBSD"
# endif
# ifdef FREEBSD
# define OS_TYPE "FREEBSD"
# endif
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# endif
# ifdef THREE86BSD
# define OS_TYPE "THREE86BSD"
# endif
# ifdef BSDI
# define OS_TYPE "BSDI"
# endif
# if defined(OPENBSD) || defined(FREEBSD) || defined(NETBSD) \
|| defined(THREE86BSD) || defined(BSDI)
# define HEURISTIC2
# endif
# ifdef NEXT
# define OS_TYPE "NEXT"
# define STACKBOTTOM ((void *)0xc0000000)
# endif
# ifdef DOS4GW
# define OS_TYPE "DOS4GW"
extern char *_STACKTOP;
# define STACKBOTTOM ((void *) _STACKTOP)
# endif
# endif
# ifdef NS32K
# define MACH_TYPE "NS32K"
# define STACKBOTTOM ((void *) 0xfffff000) /* for Encore */
# endif
# ifdef MIPS
# define MACH_TYPE "MIPS"
/* # define STACKBOTTOM ((void *)0x7fff8000) sometimes also works. */
# ifdef LINUX
/* This was developed for a linuxce style platform. Probably */
/* needs to be tweaked for workstation class machines. */
# define OS_TYPE "LINUX"
# define STACKBOTTOM 0x80000000
/* In many cases, this should probably use LINUX_STACKBOTTOM */
/* instead. But some kernel versions seem to give the wrong */
/* value from /proc. */
# endif /* Linux */
# ifdef ULTRIX
# define OS_TYPE "ULTRIX"
# define HEURISTIC2
# endif
# ifdef RISCOS
# define OS_TYPE "RISCOS"
# define HEURISTIC2
# endif
# ifdef IRIX5
# define OS_TYPE "IRIX5"
# define HEURISTIC2
# endif
# endif
# ifdef RS6000
# define MACH_TYPE "RS6000"
extern int errno;
# define STACKBOTTOM ((void *)((ulong)&errno))
# endif
# ifdef HP_PA
/* OS is assumed to be HP/UX */
# define MACH_TYPE "HP_PA"
# define OS_TYPE "HPUX"
# if 0
/* The following appears to work for 7xx systems running HP/UX */
/* 9.xx Furthermore, it might result in much faster */
/* collections than HEURISTIC2, which may involve scanning */
/* segments that directly precede the stack. It is not the */
/* default, since it may not work on older machine/OS */
/* combinations. (Thanks to Raymond X.T. Nijssen for uncovering */
/* this.) */
# define STACKBOTTOM ((void *) 0x7b033000) /* from /etc/conf/h/param.h */
# else
/* Gustavo Rodriguez-Rivera suggested changing HEURISTIC2 */
/* to this. We'll probably do this on other platforms, too. */
/* For now I'll use it where I can test it. */
extern char ** environ;
# define STACKBOTTOM ((void *)environ)
# endif
# define STACK_GROWS_UP
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGE_SIZE)
# endif
# ifdef ALPHA
# define MACH_TYPE "ALPHA"
# ifdef OSF1
# define OS_TYPE "OSF1"
# define HEURISTIC2
/* Normally HEURISTIC2 is too conervative, since */
/* the text segment immediately follows the stack. */
/* Hence we give an upper pound. */
extern int __start;
# define HEURISTIC2_LIMIT ((void *)((word)(&__start) & ~(getpagesize()-1)))
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((void *) 0x120000000)
# endif
# endif
# ifdef IA64
# define MACH_TYPE "IA64"
# ifdef HPUX
--> needs work
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define STACKBOTTOM ((void *) 0xa000000000000000l)
# endif
# endif
# ifdef M88K
# define MACH_TYPE "M88K"
# ifdef CX_UX
# define OS_TYPE "CX_UX"
# endif
# ifdef DGUX
# define OS_TYPE "DGUX"
# endif
# define STACKBOTTOM ((char*)0xf0000000) /* determined empirically */
# endif
# ifdef S370
# define MACH_TYPE "S370"
# define OS_TYPE "UTS4"
# define HEURISTIC2
# endif
# if defined(PJ)
# define HEURISTIC1
# endif
# ifdef ARM32
# define MACH_TYPE "ARM32"
# ifdef NETBSD
# define OS_TYPE "NETBSD"
# define HEURISTIC2
# endif
# ifdef LINUX
# define OS_TYPE "LINUX"
# define HEURISTIC1
# undef STACK_GRAN
# define STACK_GRAN 0x10000000
# endif
#endif
# ifndef STACK_GROWS_UP
# define STACK_GROWS_DOWN
# endif
# if defined(SVR4) && !defined(GETPAGESIZE)
# include <unistd.h>
# define GETPAGESIZE() sysconf(_SC_PAGESIZE)
# endif
# ifndef GETPAGESIZE
# if defined(SUNOS5) || defined(IRIX5)
# include <unistd.h>
# endif
# define GETPAGESIZE() getpagesize()
# endif
# if defined(SUNOS5) || defined(DRSNX) || defined(UTS4)
/* OS has SVR4 generic features. Probably others also qualify. */
# define SVR4
# endif
# if defined(SUNOS5) || defined(DRSNX) || defined(HPUX)
/* OS has SUNOS5 style signal handlers. */
# define SUNOS5SIGS
# endif
#if !defined(FALSE)
#define FALSE 0
#endif
#if !defined(TRUE)
#define TRUE !FALSE
#endif
#if !defined(NULL)
#define NULL (void *)0
#endif
typedef unsigned long word;
typedef long signed_word;
# ifdef MSWIN32
#ifdef MSWIN32
# define WIN32_LEAN_AND_MEAN
# define NOSERVICE
# include <windows.h>
#endif
# define is_writable(prot) ((prot) == PAGE_READWRITE \
|| (prot) == PAGE_WRITECOPY \
|| (prot) == PAGE_EXECUTE_READWRITE \
|| (prot) == PAGE_EXECUTE_WRITECOPY)
/* Return the number of bytes that are writable starting at p. */
/* The pointer p is assumed to be page aligned. */
/* If base is not 0, *base becomes the beginning of the */
/* allocation region containing p. */
word shm_stack_get_writable_length(void * p, void * *base)
{
MEMORY_BASIC_INFORMATION buf;
word result;
word protect;
result = VirtualQuery(p, &buf, sizeof(buf));
if (result != sizeof(buf)) ABORT("Weird VirtualQuery result");
if (base != 0) *base = (void *)(buf.AllocationBase);
protect = (buf.Protect & ~(PAGE_GUARD | PAGE_NOCACHE));
if (!is_writable(protect)) {
return(0);
}
if (buf.State != MEM_COMMIT) return(0);
return(buf.RegionSize);
}
void * shm_stack_get_stack_base()
{
int dummy;
void * sp = (void *)(&dummy);
void * trunc_sp = (void *)((word)sp & ~(shm_stack_page_size - 1));
word size = shm_stack_get_writable_length(trunc_sp, 0);
return(trunc_sp + size);
}
# else
# ifdef OS2
# define INCL_DOSEXCEPTIONS
# define INCL_DOSPROCESS
# define INCL_DOSERRORS
# define INCL_DOSMODULEMGR
# define INCL_DOSMEMMGR
# include <os2.h>
void * shm_stack_get_stack_base()
{
PTIB ptib;
PPIB ppib;
if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
shm_stack_err_printf0("DosGetInfoBlocks failed\n");
ABORT("DosGetInfoBlocks failed\n");
}
return((void *)(ptib -> tib_pstacklimit));
}
# else
# ifdef AMIGA
# include <proto/exec.h>
# include <proto/dos.h>
# include <dos/dosextens.h>
# include <workbench/startup.h>
void * shm_stack_get_stack_base()
{
struct Process *proc = (struct Process*)SysBase->ThisTask;
/* Reference: Amiga Guru Book Pages: 42,567,574 */
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
&& proc->pr_CLI != NULL) {
/* first ULONG is StackSize */
/*longPtr = proc->pr_ReturnAddr;
size = longPtr[0];*/
return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
} else {
return (char *)proc->pr_Task.tc_SPUpper;
}
}
#else
#ifdef HEURISTIC2
#include <signal.h>
#include <setjmp.h>
/* Some tools to implement HEURISTIC2 */
# define MIN_PAGE_SIZE 256 /* Smallest conceivable page size, bytes */
/* static */ jmp_buf scm_stack_jmp_buf;
/*ARGSUSED*/
void scm_stack_fault_handler(int sig)
{
longjmp(scm_stack_jmp_buf, 1);
}
# ifdef __STDC__
typedef void (*handler)(int);
# else
typedef void (*handler)();
# endif
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
static struct sigaction old_segv_act;
# if defined(_sigargs) || defined(HPUX) /* !Irix6.x */
static struct sigaction old_bus_act;
# endif
# else
static handler old_segv_handler, old_bus_handler;
# endif
void scm_stack_setup_temporary_fault_handler()
{
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
struct sigaction act;
act.sa_handler = schm_stack_fault_handler;
act.sa_flags = SA_RESTART | SA_NODEFER;
/* The presence of SA_NODEFER represents yet another gross */
/* hack. Under Solaris 2.3, siglongjmp doesn't appear to */
/* interact correctly with -lthread. We hide the confusion */
/* by making sure that signal handling doesn't affect the */
/* signal mask. */
(void) sigemptyset(&act.sa_mask);
# ifdef IRIX_THREADS
/* Older versions have a bug related to retrieving and */
/* and setting a handler at the same time. */
(void) sigaction(SIGSEGV, 0, &old_segv_act);
(void) sigaction(SIGSEGV, &act, 0);
# else
(void) sigaction(SIGSEGV, &act, &old_segv_act);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
|| defined(HPUX)
/* Under Irix 5.x or HP/UX, we may get SIGBUS. */
/* Pthreads doesn't exist under Irix 5.x, so we */
/* don't have to worry in the threads case. */
(void) sigaction(SIGBUS, &act, &old_bus_act);
# endif
# endif /* IRIX_THREADS */
# else
old_segv_handler = signal(SIGSEGV, scm_stack_fault_handler);
# ifdef SIGBUS
old_bus_handler = signal(SIGBUS, scm_stack_fault_handler);
# endif
# endif
}
void scm_stack_reset_fault_handler()
{
# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
(void) sigaction(SIGSEGV, &old_segv_act, 0);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
|| defined(HPUX)
(void) sigaction(SIGBUS, &old_bus_act, 0);
# endif
# else
(void) signal(SIGSEGV, old_segv_handler);
# ifdef SIGBUS
(void) signal(SIGBUS, old_bus_handler);
# endif
# endif
}
/* Return the first nonaddressible location > p (up) or */
/* the smallest location q s.t. [q,p] is addressible (!up). */
void * scm_stack_find_limit(void *p, int up)
{
static volatile void *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. */
scm_stack_setup_temporary_fault_handler();
if (setjmp(scm_stack_jmp_buf) == 0) {
result = (void *)(((word)(p))
& ~(MIN_PAGE_SIZE-1));
for (;;) {
if (up) {
result += MIN_PAGE_SIZE;
} else {
result -= MIN_PAGE_SIZE;
}
scm_stack_noop1((word)(*((word *)result)));
}
}
scm_stack_reset_fault_handler();
if (!up) {
result += MIN_PAGE_SIZE;
}
return((void *)result);
}
#endif
#ifdef LINUX_STACKBOTTOM
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
# define STAT_SKIP 27 /* Number of fields preceding startstack */
/* field in /proc/self/stat */
void *scm_stack_linux_stack_base(void)
{
# define STAT_BUF_SIZE 4096
char stat_buf[STAT_BUF_SIZE];
int f;
char c;
word result = 0;
size_t i, buf_offset = 0;
f = open("/proc/self/stat", O_RDONLY);
if (f < 0 || read(f, stat_buf, STAT_BUF_SIZE) < 2 * STAT_SKIP) {
abort("Couldn't read /proc/self/stat");
}
c = stat_buf[buf_offset++];
/* Skip the required number of fields. This number is hopefully */
/* constant across all Linux implementations. */
for (i = 0; i < STAT_SKIP; ++i) {
while (isspace(c)) c = stat_buf[buf_offset++];
while (!isspace(c)) c = stat_buf[buf_offset++];
}
while (isspace(c)) c = stat_buf[buf_offset++];
while (isdigit(c)) {
result *= 10;
result += c - '0';
c = stat_buf[buf_offset++];
}
close(f);
if (result < 0x10000000) abort("Absurd stack bottom value");
return (void *)result;
}
#endif /* LINUX_STACKBOTTOM */
void * scm_get_stack_base() {
word dummy;
void *result;
# define STACKBOTTOM_ALIGNMENT_M1 ((word)STACK_GRAN - 1)
# ifdef STACKBOTTOM
return(STACKBOTTOM);
# else
# ifdef HEURISTIC1
# ifdef STACK_GROWS_DOWN
result = (void *)((((word)(&dummy))
+ STACKBOTTOM_ALIGNMENT_M1)
& ~STACKBOTTOM_ALIGNMENT_M1);
# else
result = (void *)((()(&dummy))
& ~STACKBOTTOM_ALIGNMENT_M1);
# endif
# endif /* HEURISTIC1 */
# ifdef LINUX_STACKBOTTOM
result = scm_stack_linux_stack_base();
# endif
# ifdef HEURISTIC2
# ifdef STACK_GROWS_DOWN
result =
scm_stack_find_limit((void *)(&dummy), TRUE);
# ifdef HEURISTIC2_LIMIT
if (result > HEURISTIC2_LIMIT
&& (void *)(&dummy) < HEURISTIC2_LIMIT) {
result = HEURISTIC2_LIMIT;
}
# endif
# else
result = scm_stack_find_limit((void *)(&dummy), FALSE);
# ifdef HEURISTIC2_LIMIT
if (result < HEURISTIC2_LIMIT
&& (void *)(&dummy) > HEURISTIC2_LIMIT) {
result = HEURISTIC2_LIMIT;
}
# endif
# endif
# endif /* HEURISTIC2 */
# ifdef STACK_GROWS_DOWN
if (result == 0) result = (void *)(signed_word)(-sizeof(void *));
# endif
return(result);
# endif /* STACKBOTTOM */
}
# endif /* ! AMIGA */
# endif /* ! OS2 */
# endif /* ! MSWIN32 */
/* Single argument version, robust against whole program analysis. */
void scm_stack_noop1(word x)
{
static volatile word sink;
sink = x;
}