struct roots {
ptr_t r_start;
ptr_t r_end;
- # if !defined(MSWIN32) && !defined(MSWINCE)
+ # if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
struct roots * r_next;
# endif
GC_bool r_tmp;
return(FALSE);
}
-#if !defined(MSWIN32) && !defined(MSWINCE)
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
/*
# define LOG_RT_SIZE 6
# define RT_SIZE (1 << LOG_RT_SIZE) -- Power of 2, may be != MAX_ROOT_SETS
GC_root_index[h] = p;
}
-# else /* MSWIN32 || MSWINCE */
+# else /* MSWIN32 || MSWINCE || CYGWIN32 */
# define add_roots_to_index(p)
{
struct roots * old;
-# if defined(MSWIN32) || defined(MSWINCE)
+# if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
/* Spend the time to ensure that there are no overlapping */
/* or adjacent intervals. */
/* This could be done faster with e.g. a */
GC_static_roots[n_root_sets].r_start = (ptr_t)b;
GC_static_roots[n_root_sets].r_end = (ptr_t)e;
GC_static_roots[n_root_sets].r_tmp = tmp;
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
GC_static_roots[n_root_sets].r_next = 0;
# endif
add_roots_to_index(GC_static_roots + n_root_sets);
n_root_sets++;
}
-static roots_were_cleared = FALSE;
+static GC_bool roots_were_cleared = FALSE;
void GC_clear_roots GC_PROTO((void))
{
roots_were_cleared = TRUE;
n_root_sets = 0;
GC_root_size = 0;
-# if !defined(MSWIN32) && !defined(MSWINCE)
+# if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
{
register int i;
ENABLE_SIGNALS();
}
+/* Internal use only; lock held. */
+static void GC_remove_root_at_pos(i)
+int i;
+{
+ GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
+ GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
+ GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
+ GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
+ n_root_sets--;
+}
+
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+static void GC_rebuild_root_index()
+{
+ register int i;
+
+ for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
+ for (i = 0; i < n_root_sets; i++)
+ add_roots_to_index(GC_static_roots + i);
+}
+#endif
+
/* Internal use only; lock held. */
void GC_remove_tmp_roots()
{
for (i = 0; i < n_root_sets; ) {
if (GC_static_roots[i].r_tmp) {
- GC_root_size -=
- (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
- GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
- GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
- GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
- n_root_sets--;
+ GC_remove_root_at_pos(i);
} else {
i++;
- }
}
-# if !defined(MSWIN32) && !defined(MSWINCE)
- {
- register int i;
-
- for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
- for (i = 0; i < n_root_sets; i++)
- add_roots_to_index(GC_static_roots + i);
}
-# endif
+ #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+ GC_rebuild_root_index();
+ #endif
+}
+
+#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32)
+void GC_remove_roots(b, e)
+char * b; char * e;
+{
+ DCL_LOCK_STATE;
+ DISABLE_SIGNALS();
+ LOCK();
+ GC_remove_roots_inner(b, e);
+ UNLOCK();
+ ENABLE_SIGNALS();
+}
+
+/* Should only be called when the lock is held */
+void GC_remove_roots_inner(b,e)
+char * b; char * e;
+{
+ int i;
+ for (i = 0; i < n_root_sets; ) {
+ if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
+ GC_remove_root_at_pos(i);
+ } else {
+ i++;
+ }
+ }
+ GC_rebuild_root_index();
}
+#endif /* !defined(MSWIN32) && !defined(MSWINCE) && !defined(CYGWIN32) */
-#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
+#if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION) || defined(CYGWIN32)
/* Workaround for the OS mapping and unmapping behind our back: */
/* Is the address p in one of the temporary static root sections? */
GC_bool GC_is_tmp_root(p)
}
return(FALSE);
}
-#endif /* MSWIN32 || _WIN32_WCE_EMULATION */
+#endif /* MSWIN32 || _WIN32_WCE_EMULATION || defined(CYGWIN32) */
ptr_t GC_approx_sp()
{
- word dummy;
+ VOLATILE word dummy;
+ dummy = 42; /* Force stack to grow if necessary. Otherwise the */
+ /* later accesses might cause the kernel to think we're */
+ /* doing something wrong. */
# ifdef _MSC_VER
# pragma warning(disable:4172)
# endif
- return((ptr_t)(&dummy));
+#ifdef __GNUC__
+ /* Eliminate a warning from GCC about taking the address of a
+ local variable. */
+ return __builtin_frame_address (0);
+#else
+ return ((ptr_t)(&dummy));
+#endif /* __GNUC__ */
# ifdef _MSC_VER
# pragma warning(default:4172)
# endif
void GC_mark_thread_local_free_lists();
#endif
+void GC_cond_register_dynamic_libraries()
+{
+# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
+ || defined(CYGWIN32) || defined(PCR)) && !defined(SRC_M3)
+ GC_remove_tmp_roots();
+ if (!GC_no_dls) GC_register_dynamic_libraries();
+# else
+ GC_no_dls = TRUE;
+# endif
+}
+
/*
* Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
* on groups of pointers) on every top level accessible pointer.
GC_bool all;
ptr_t cold_gc_frame;
{
- register int i;
+ int i;
+ int kind;
- /*
- * push registers - i.e., call GC_push_one(r) for each
- * register contents r.
- */
-# ifdef USE_GENERIC_PUSH_REGS
- GC_generic_push_regs(cold_gc_frame);
-# else
- GC_push_regs(); /* usually defined in machine_dep.c */
-# endif
-
/*
* Next push static data. This must happen early on, since it's
* not robust against mark stack overflow.
*/
- /* Reregister dynamic libraries, in case one got added. */
-# if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
- || defined(PCR)) && !defined(SRC_M3)
- GC_remove_tmp_roots();
- if (!GC_no_dls) GC_register_dynamic_libraries();
-# else
- GC_no_dls = TRUE;
+ /* Reregister dynamic libraries, in case one got added. */
+ /* There is some argument for doing this as late as possible, */
+ /* especially on win32, where it can change asynchronously. */
+ /* In those cases, we do it here. But on other platforms, it's */
+ /* not safe with the world stopped, so we do it earlier. */
+# if !defined(REGISTER_LIBRARIES_EARLY)
+ GC_cond_register_dynamic_libraries();
# endif
/* Mark everything in static data areas */
GC_static_roots[i].r_end, all);
}
+ /* Mark all free list header blocks, if those were allocated from */
+ /* the garbage collected heap. This makes sure they don't */
+ /* disappear if we are not marking from static data. It also */
+ /* saves us the trouble of scanning them, and possibly that of */
+ /* marking the freelists. */
+ for (kind = 0; kind < GC_n_kinds; kind++) {
+ GC_PTR base = GC_base(GC_obj_kinds[kind].ok_freelist);
+ if (0 != base) {
+ GC_set_mark_bit(base);
+ }
+ }
+
/* Mark from GC internal roots if those might otherwise have */
/* been excluded. */
if (GC_no_dls || roots_were_cleared) {
/* Mark thread local free lists, even if their mark */
/* descriptor excludes the link field. */
+ /* If the world is not stopped, this is unsafe. It is */
+ /* also unnecessary, since we will do this again with the */
+ /* world stopped. */
# ifdef THREAD_LOCAL_ALLOC
- GC_mark_thread_local_free_lists();
+ if (GC_world_stopped) GC_mark_thread_local_free_lists();
# endif
/*
- * Now traverse stacks.
+ * Now traverse stacks, and mark from register contents.
+ * These must be done last, since they can legitimately overflow
+ * the mark stack.
*/
-# if !defined(USE_GENERIC_PUSH_REGS)
+# ifdef USE_GENERIC_PUSH_REGS
+ GC_generic_push_regs(cold_gc_frame);
+ /* Also pushes stack, so that we catch callee-save registers */
+ /* saved inside the GC_push_regs frame. */
+# else
+ /*
+ * push registers - i.e., call GC_push_one(r) for each
+ * register contents r.
+ */
+ GC_push_regs(); /* usually defined in machine_dep.c */
GC_push_current_stack(cold_gc_frame);
/* In the threads case, this only pushes collector frames. */
- /* In the USE_GENERIC_PUSH_REGS case, this is done inside */
- /* GC_push_regs, so that we catch callee-save registers saved */
- /* inside the GC_push_regs frame. */
/* In the case of linux threads on IA64, the hot section of */
/* the main stack is marked here, but the register stack */
/* backing store is handled in the threads-specific code. */
# endif
if (GC_push_other_roots != 0) (*GC_push_other_roots)();
/* In the threads case, this also pushes thread stacks. */
+ /* Note that without interior pointer recognition lots */
+ /* of stuff may have been pushed already, and this */
+ /* should be careful about mark stack overflows. */
}