summaryrefslogtreecommitdiff
path: root/os_dep.c
diff options
context:
space:
mode:
authorivmai <ivmai>2009-10-20 21:27:25 +0000
committerIvan Maidanski <ivmai@mail.ru>2011-07-26 21:06:51 +0400
commitc4e4721f491632c2039cece14400f353794273f4 (patch)
tree81ea0ea761bfcdc92d55a67d28fc0f83659cf9dd /os_dep.c
parentf2127b50f72ad5449c24f1e0bd4b3d4ca88185d8 (diff)
downloadbdwgc-c4e4721f491632c2039cece14400f353794273f4.tar.gz
2009-10-20 Ivan Maidanski <ivmai@mail.ru> (really mostly OpenBSD contributors)
* configure.ac (openbsd): Define GC_OPENBSD_THREADS. * configure.ac: Add AM_CONDITIONAL(OPENBSD_THREADS). * configure.ac: Add sparc-openbsd case. * doc/README.macros (GC_NETBSD_THREADS, GC_OPENBSD_THREADS): Document. * tests/test.c (main): Handle OpenBSD case. * extra/threadlibs.c: Add the copyright header; expand all tabs to spaces; remove trailing spaces at EOLn. * include/private/pthread_stop_world.h: Ditto. * extra/threadlibs.c (main): Replace K&R-style function definition with the ANSI C one. * extra/threadlibs.c (main): Handle GC_OPENBSD_THREADS case. * dyn_load.c (OPENBSD): Recognize (similar to NETBSD). * include/gc_config_macros.h (GC_SOLARIS_THREADS): Recognize; define it for OpenBSD. * include/gc_pthread_redirects.h (GC_pthread_sigmask, pthread_sigmask): Don't declare and redefine for OpenBSD. * include/private/gcconfig.h: Handle OpenBSD (on arm, sh, i386, amd64, powerpc). * mach_dep.c (NO_GETCONTEXT): Ditto. * include/private/pthread_stop_world.h (thread_stop_info): Don't define last_stop_count field if OpenBSD. * misc.c (GC_init_dyld): Add declaration (if NetBSD). * misc.c (GC_init): Don't call GC_init_netbsd_elf() for OpenBSD. * os_dep.c (GC_init_netbsd_elf): Don't define for OpenBSD. * os_dep.c (old_segv_act, GC_jmp_buf_openbsd): New static variable (only if OpenBSD). * os_dep.c (GC_fault_handler_openbsd, GC_find_limit_openbsd, GC_skip_hole_openbsd): New static function (only if OpenBSD). * os_dep.c (GC_get_stack_base, GC_get_main_stack_base, GC_register_data_segments): Define specially for OpenBSD case. * os_dep.c (GC_fault_handler_lock): Initialize to AO_TS_INITIALIZER (instead of 0). * pthread_support.c (GC_allocate_lock): Ditto. * pthread_stop_world.c (NSIG, GC_print_sig_mask, GC_remove_allowed_signals, suspend_handler_mask, GC_stop_count, GC_world_is_stopped, GC_retry_signals, SIG_THR_RESTART, GC_suspend_ack_sem, GC_suspend_handler_inner, GC_suspend_handler, GC_restart_handler): Don't define and use if OpenBSD. * pthread_stop_world.c (GC_suspend_all, GC_stop_world, GC_start_world): Handle OpenBSD case. * pthread_stop_world.c (GC_stop_init): Define as empty if OpenBSD. * pthread_support.c (pthread_sigmask): Don't undefine the macro and don't define the wrapper function if OpenBSD. * pthread_support.c (GC_thr_init): Handle OpenBSD case. * configure: Regenerate. * include/private/config.h.in: Ditto.
Diffstat (limited to 'os_dep.c')
-rw-r--r--os_dep.c154
1 files changed, 146 insertions, 8 deletions
diff --git a/os_dep.c b/os_dep.c
index 3a8c7a98..41cecf99 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -502,7 +502,7 @@ static void *tiny_sbrk(ptrdiff_t increment)
#define sbrk tiny_sbrk
# endif /* ECOS */
-#if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
+#if defined(NETBSD) && defined(__ELF__)
ptr_t GC_data_start = NULL;
ptr_t GC_find_limit(ptr_t, GC_bool);
extern char **environ;
@@ -515,6 +515,99 @@ static void *tiny_sbrk(ptrdiff_t increment)
}
#endif
+#ifdef OPENBSD
+ static struct sigaction old_segv_act;
+ STATIC sigjmp_buf GC_jmp_buf_openbsd;
+
+# ifdef THREADS
+# include <sys/syscall.h>
+ extern sigset_t __syscall(quad_t, ...);
+# endif
+
+ /* Dont use GC_find_limit() because siglongjmp() outside of the */
+ /* signal handler by-passes our userland pthreads lib, leaving */
+ /* SIGSEGV and SIGPROF masked. Instead, use this custom one that */
+ /* works-around the issues. */
+
+ /*ARGSUSED*/
+ STATIC void GC_fault_handler_openbsd(int sig)
+ {
+ siglongjmp(GC_jmp_buf_openbsd, 1);
+ }
+
+ /* Return the first non-addressible location > p or bound. */
+ /* Requires the allocation lock. */
+ STATIC ptr_t GC_find_limit_openbsd(ptr_t p, ptr_t bound)
+ {
+ static volatile ptr_t result;
+ /* Safer if static, since otherwise it may not be */
+ /* preserved across the longjmp. Can safely be */
+ /* static since it's only called with the */
+ /* allocation lock held. */
+
+ struct sigaction act;
+ size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
+ GC_ASSERT(I_HOLD_LOCK());
+
+ act.sa_handler = GC_fault_handler_openbsd;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ sigaction(SIGSEGV, &act, &old_segv_act);
+
+ if (sigsetjmp(GC_jmp_buf_openbsd, 1) == 0) {
+ result = (ptr_t)((word)p & ~(pgsz-1));
+ for (;;) {
+ result += pgsz;
+ if (result >= bound) {
+ result = bound;
+ break;
+ }
+ GC_noop1((word)(*result));
+ }
+ }
+
+# ifdef THREADS
+ /* Due to the siglongjump we need to manually unmask SIGPROF. */
+ __syscall(SYS_sigprocmask, SIG_UNBLOCK, sigmask(SIGPROF));
+# endif
+
+ sigaction(SIGSEGV, &old_segv_act, 0);
+ return(result);
+ }
+
+ /* Return first addressable location > p or bound. */
+ /* Requires the allocation lock. */
+ STATIC ptr_t GC_skip_hole_openbsd(ptr_t p, ptr_t bound)
+ {
+ static volatile ptr_t result;
+ static volatile int firstpass;
+
+ struct sigaction act;
+ size_t pgsz = (size_t)sysconf(_SC_PAGESIZE);
+ GC_ASSERT(I_HOLD_LOCK());
+
+ act.sa_handler = GC_fault_handler_openbsd;
+ sigemptyset(&act.sa_mask);
+ act.sa_flags = SA_NODEFER | SA_RESTART;
+ sigaction(SIGSEGV, &act, &old_segv_act);
+
+ firstpass = 1;
+ result = (ptr_t)((word)p & ~(pgsz-1));
+ if (sigsetjmp(GC_jmp_buf_openbsd, 1) != 0 || firstpass) {
+ firstpass = 0;
+ result += pgsz;
+ if (result >= bound) {
+ result = bound;
+ } else {
+ GC_noop1((word)(*result));
+ }
+ }
+
+ sigaction(SIGSEGV, &old_segv_act, 0);
+ return(result);
+ }
+#endif /* OPENBSD */
+
# ifdef OS2
# include <stddef.h>
@@ -706,14 +799,12 @@ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *sb)
#endif /* CYGWIN32 */
-
-#define HAVE_GET_STACK_BASE
+# define HAVE_GET_STACK_BASE
/* This is always called from the main thread. */
ptr_t GC_get_main_stack_base(void)
{
struct GC_stack_base sb;
-
GC_get_stack_base(&sb);
GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
return (ptr_t)sb.mem_base;
@@ -1053,7 +1144,7 @@ ptr_t GC_get_main_stack_base(void)
#if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
&& !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS) \
- && !defined(CYGWIN32)
+ && !defined(CYGWIN32) && !defined(GC_OPENBSD_THREADS)
ptr_t GC_get_main_stack_base(void)
{
@@ -1164,10 +1255,38 @@ GC_API int GC_CALL GC_get_stack_base(struct GC_stack_base *b)
return GC_SUCCESS;
}
-#define HAVE_GET_STACK_BASE
+# define HAVE_GET_STACK_BASE
#endif /* GC_LINUX_THREADS */
+#ifdef GC_OPENBSD_THREADS
+
+# include <sys/signal.h>
+# include <pthread.h>
+# include <pthread_np.h>
+
+ /* Find the stack using pthread_stackseg_np(). */
+ int GC_get_stack_base(struct GC_stack_base *sb)
+ {
+ stack_t stack;
+ pthread_stackseg_np(pthread_self(), &stack);
+ sb->mem_base = stack.ss_sp;
+ return GC_SUCCESS;
+ }
+
+# define HAVE_GET_STACK_BASE
+
+ /* This is always called from the main thread. */
+ ptr_t GC_get_main_stack_base(void)
+ {
+ struct GC_stack_base sb;
+ GC_get_stack_base(&sb);
+ GC_ASSERT((void *)&sb HOTTER_THAN sb.mem_base);
+ return (ptr_t)sb.mem_base;
+ }
+
+#endif /* GC_OPENBSD_THREADS */
+
#ifndef HAVE_GET_STACK_BASE
/* Retrieve stack base. */
/* Using the GC_find_limit version is risky. */
@@ -1664,7 +1783,26 @@ ptr_t GC_FreeBSDGetDataStart(size_t max_page_size, ptr_t etext_addr)
# include "extra/AmigaOS.c"
# undef GC_AMIGA_DS
-#else /* !OS2 && !Windows && !AMIGA */
+#elif defined(OPENBSD)
+
+/* Depending on arch alignment, there can be multiple holes */
+/* between DATASTART and DATAEND. Scan in DATASTART .. DATAEND */
+/* and register each region. */
+void GC_register_data_segments(void)
+{
+ ptr_t region_start = DATASTART;
+ ptr_t region_end;
+
+ for (;;) {
+ region_end = GC_find_limit_openbsd(region_start, DATAEND);
+ GC_add_roots_inner(region_start, region_end, FALSE);
+ if (region_end >= DATAEND)
+ break;
+ region_start = GC_skip_hole_openbsd(region_end, DATAEND);
+ }
+}
+
+# else /* !OS2 && !Windows && !AMIGA && !OPENBSD */
void GC_register_data_segments(void)
{
@@ -2694,7 +2832,7 @@ STATIC GC_bool GC_old_segv_handler_used_si = FALSE;
/* Contention should be very rare, so we do the minimum to handle it */
/* correctly. */
#ifdef AO_HAVE_test_and_set_acquire
- GC_INNER volatile AO_TS_t GC_fault_handler_lock = 0;
+ GC_INNER volatile AO_TS_t GC_fault_handler_lock = AO_TS_INITIALIZER;
static void async_set_pht_entry_from_index(volatile page_hash_table db,
size_t index)
{