/* Blatantly OS dependent routines, except for those that are related */
/* to dynamic loading. */
-# if !defined(THREADS) && !defined(STACKBOTTOM) && defined(HEURISTIC2)
+# if defined(HEURISTIC2) || defined(SEARCH_FOR_DATA_START)
# define NEED_FIND_LIMIT
# endif
-# if defined(IRIX_THREADS) || defined(HPUX_THREADS)
+# if !defined(STACKBOTTOM) && defined(HEURISTIC2)
# define NEED_FIND_LIMIT
# endif
-# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
+# if defined(IRIX_THREADS) || defined(HPUX_THREADS)
# define NEED_FIND_LIMIT
# endif
-# if (defined(SVR4) || defined(AUX) || defined(DGUX)) && !defined(PCR)
+# if (defined(SUNOS4) && defined(DYNAMIC_LOADING)) && !defined(PCR)
# define NEED_FIND_LIMIT
# endif
-# if defined(LINUX) && \
- (defined(POWERPC) || defined(SPARC) || defined(ALPHA) || defined(IA64) \
- || defined(MIPS))
+# if (defined(SVR4) || defined(AUX) || defined(DGUX) \
+ || (defined(LINUX) && defined(SPARC))) && !defined(PCR)
# define NEED_FIND_LIMIT
# endif
# include <fcntl.h>
#endif
-#ifdef SUNOS5SIGS
-# include <sys/siginfo.h>
+#if defined(SUNOS5SIGS) || defined (HURD) || defined(LINUX)
+# ifdef SUNOS5SIGS
+# include <sys/siginfo.h>
+# endif
# undef setjmp
# undef longjmp
# define setjmp(env) sigsetjmp(env, 1)
&& !defined(MSWINCE) \
&& !defined(MACOS) && !defined(DJGPP) && !defined(DOS4GW)
-# if defined(sigmask) && !defined(UTS4)
+# if defined(sigmask) && !defined(UTS4) && !defined(HURD)
/* Use the traditional BSD interface */
# define SIGSET_T int
# define SIG_DEL(set, signal) (set) &= ~(sigmask(signal))
# undef GC_AMIGA_SB
# endif /* AMIGA */
-# if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
+# if defined(NEED_FIND_LIMIT) || (defined(UNIX_LIKE) && !defined(ECOS))
# ifdef __STDC__
typedef void (*handler)(int);
typedef void (*handler)();
# endif
-# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
+# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1) || defined(HURD)
static struct sigaction old_segv_act;
-# if defined(_sigargs) || defined(HPUX) /* !Irix6.x */
+# if defined(_sigargs) /* !Irix6.x */ || defined(HPUX) || defined(HURD)
static struct sigaction old_bus_act;
# endif
# else
# endif
{
# ifndef ECOS
-# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
+# if defined(SUNOS5SIGS) || defined(IRIX5) \
+ || defined(OSF1) || defined(HURD)
struct sigaction act;
act.sa_handler = h;
- act.sa_flags = SA_RESTART | SA_NODEFER;
+# ifdef SUNOS5SIGS
+ act.sa_flags = SA_RESTART | SA_NODEFER;
+# else
+ act.sa_flags = SA_RESTART;
+# endif
/* 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 */
# else
(void) sigaction(SIGSEGV, &act, &old_segv_act);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
- || defined(HPUX)
+ || defined(HPUX) || defined(HURD)
/* 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 GC_reset_fault_handler()
{
# ifndef ECOS
-# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(OSF1)
+# if defined(SUNOS5SIGS) || defined(IRIX5) \
+ || defined(OSF1) || defined(HURD)
(void) sigaction(SIGSEGV, &old_segv_act, 0);
# if defined(IRIX5) && defined(_sigargs) /* Irix 5.x, not 6.x */ \
- || defined(HPUX)
+ || defined(HPUX) || defined(HURD)
(void) sigaction(SIGBUS, &old_bus_act, 0);
# endif
# else
#endif /* FREEBSD_STACKBOTTOM */
#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
- && !defined(MSWINCE) && !defined(OS2)
+ && !defined(MSWINCE) && !defined(OS2) && !defined(ECOS)
ptr_t GC_get_stack_base()
{
#if defined(SUNOS4) || defined(FREEBSD)
typedef void (* SIG_PF)();
#endif
-#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) || defined(MACOSX)
+#if defined(SUNOS5SIGS) || defined(OSF1) || defined(LINUX) \
+ || defined(MACOSX) || defined(HURD)
# ifdef __STDC__
typedef void (* SIG_PF)(int);
# else
# define SIG_DFL (SIG_PF) (-1)
#endif
-#if defined(IRIX5) || defined(OSF1)
+#if defined(IRIX5) || defined(OSF1) || defined(HURD)
typedef void (* REAL_SIG_PF)(int, int, struct sigcontext *);
#endif
#if defined(SUNOS5SIGS)
#ifdef GC_TEST_AND_SET_DEFINED
static VOLATILE unsigned int fault_handler_lock = 0;
void async_set_pht_entry_from_index(VOLATILE page_hash_table db, int index) {
- while (GC_test_and_set(&fault_handler_lock));
+ while (GC_test_and_set(&fault_handler_lock)) {}
/* Could also revert to set_pht_entry_from_index_safe if initial */
/* GC_test_and_set fails. */
set_pht_entry_from_index(db, index);
# define CODE_OK (code == BUS_PAGE_FAULT)
# endif
# endif
-# if defined(IRIX5) || defined(OSF1)
+# if defined(IRIX5) || defined(OSF1) || defined(HURD)
# include <errno.h>
void GC_write_fault_handler(int sig, int code, struct sigcontext *scp)
-# define SIG_OK (sig == SIGSEGV)
# ifdef OSF1
+# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (code == 2 /* experimentally determined */)
# endif
# ifdef IRIX5
+# define SIG_OK (sig == SIGSEGV)
# define CODE_OK (code == EACCES)
# endif
+# ifdef HURD
+# define SIG_OK (sig == SIGBUS || sig == SIGSEGV)
+# define CODE_OK TRUE
+# endif
# endif
# if defined(LINUX)
# if defined(ALPHA) || defined(M68K)
# endif
{
register unsigned i;
+# if defined(HURD)
+ char *addr = (char *) code;
+# endif
# ifdef IRIX5
char * addr = (char *) (size_t) (scp -> sc_badvaddr);
# endif
# endif
return;
# endif
-# if defined (IRIX5) || defined(OSF1)
+# if defined (IRIX5) || defined(OSF1) || defined(HURD)
(*(REAL_SIG_PF)old_handler) (sig, code, scp);
return;
# endif
# endif
}
}
+ UNPROTECT(h, GC_page_size);
+ /* We need to make sure that no collection occurs between */
+ /* the UNPROTECT and the setting of the dirty bit. Otherwise */
+ /* a write by a third thread might go unnoticed. Reversing */
+ /* the order is just as bad, since we would end up unprotecting */
+ /* a page in a GC cycle during which it's not marked. */
+ /* Currently we do this by disabling the thread stopping */
+ /* signals while this handler is running. An alternative might */
+ /* be to record the fact that we're about to unprotect, or */
+ /* have just unprotected a page in the GC's thread structure, */
+ /* and then to have the thread stopping code set the dirty */
+ /* flag, if necessary. */
for (i = 0; i < divHBLKSZ(GC_page_size); i++) {
register int index = PHT_HASH(h+i);
async_set_pht_entry_from_index(GC_dirty_pages, index);
}
- UNPROTECT(h, GC_page_size);
-# if defined(OSF1) || defined(LINUX)
+# if defined(OSF1)
/* These reset the signal handler each time by default. */
signal(SIGSEGV, (SIG_PF) GC_write_fault_handler);
# endif
void GC_dirty_init()
{
-# if defined(SUNOS5SIGS) || defined(IRIX5) /* || defined(OSF1) */
+# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) || \
+ defined(OSF1) || defined(HURD)
struct sigaction act, oldact;
-# ifdef IRIX5
+ /* We should probably specify SA_SIGINFO for Linux, and handle */
+ /* the different architectures more uniformly. */
+# if defined(IRIX5) || defined(LINUX) || defined(OSF1) || defined(HURD)
act.sa_flags = SA_RESTART;
- act.sa_handler = GC_write_fault_handler;
+ act.sa_handler = (SIG_PF)GC_write_fault_handler;
# else
act.sa_flags = SA_RESTART | SA_SIGINFO;
act.sa_sigaction = GC_write_fault_handler;
# endif
(void)sigemptyset(&act.sa_mask);
+# ifdef SIG_SUSPEND
+ /* Arrange to postpone SIG_SUSPEND while we're in a write fault */
+ /* handler. This effectively makes the handler atomic w.r.t. */
+ /* stopping the world for GC. */
+ (void)sigaddset(&act.sa_mask, SIG_SUSPEND);
+# endif /* SIG_SUSPEND */
# endif
# if defined(MACOSX)
struct sigaction act, oldact;
# endif
}
# endif
-# if defined(OSF1) || defined(SUNOS4) || defined(LINUX)
+# if defined(SUNOS4)
GC_old_segv_handler = signal(SIGSEGV, (SIG_PF)GC_write_fault_handler);
if (GC_old_segv_handler == SIG_IGN) {
GC_err_printf0("Previously ignored segmentation violation!?");
# endif
}
# endif
-# if defined(SUNOS5SIGS) || defined(IRIX5)
+# if defined(SUNOS5SIGS) || defined(IRIX5) || defined(LINUX) \
+ || defined(OSF1) || defined(HURD)
+ /* SUNOS5SIGS includes HPUX */
# if defined(IRIX_THREADS)
sigaction(SIGSEGV, 0, &oldact);
sigaction(SIGSEGV, &act, 0);
# else
sigaction(SIGSEGV, &act, &oldact);
# endif
-# if defined(_sigargs)
+# if defined(_sigargs) || defined(HURD)
/* This is Irix 5.x, not 6.x. Irix 5.x does not have */
/* sa_sigaction. */
GC_old_segv_handler = oldact.sa_handler;
-# else /* Irix 6.x or SUNOS5SIGS */
+# else /* Irix 6.x or SUNOS5SIGS or LINUX */
if (oldact.sa_flags & SA_SIGINFO) {
GC_old_segv_handler = (SIG_PF)(oldact.sa_sigaction);
} else {
# endif
}
# endif
-# if defined(MACOSX) || defined(HPUX)
+# if defined(MACOSX) || defined(HPUX) || defined(LINUX) || defined(HURD)
sigaction(SIGBUS, &act, &oldact);
GC_old_bus_handler = oldact.sa_handler;
if (GC_old_bus_handler == SIG_IGN) {
GC_err_printf0("Replaced other SIGBUS handler\n");
# endif
}
-# endif /* MACOS || HPUX */
+# endif /* MACOS || HPUX || LINUX */
# if defined(MSWIN32)
GC_old_segv_handler = SetUnhandledExceptionFilter(GC_write_fault_handler);
if (GC_old_segv_handler != NULL) {
result = readv(fd, &iov, 1);
}
# else
+# if defined(HURD)
+ result = __read(fd, buf, nbyte);
+# else
/* The two zero args at the end of this list are because one
IA-64 syscall() implementation actually requires six args
to be passed, even though they aren't always used. */
result = syscall(SYS_read, fd, buf, nbyte, 0, 0);
+# endif /* !HURD */
# endif
GC_end_syscall();
return(result);
register int i;
info[nframes].ci_pc = fp->FR_SAVPC;
- for (i = 0; i < NARGS; i++) {
- info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
- }
+# if NARGS > 0
+ for (i = 0; i < NARGS; i++) {
+ info[nframes].ci_arg[i] = ~(fp->fr_arg[i]);
+ }
+# endif /* NARGS > 0 */
}
if (nframes < NFRAMES) info[nframes].ci_pc = 0;
}