summaryrefslogtreecommitdiff
path: root/win32_threads.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-02-24 14:34:34 +0400
committerIvan Maidanski <ivmai@mail.ru>2012-02-24 14:34:34 +0400
commit11e95a1dfdd8ac1ed729d822a2968cb389e253d1 (patch)
treee768dc34472cb975e55940b4eb61c06693e18cd3 /win32_threads.c
parentee0301906ae01bdd6d3a0fb4105c8a45d6bfae82 (diff)
downloadbdwgc-11e95a1dfdd8ac1ed729d822a2968cb389e253d1.tar.gz
Fix Cygwin support to handle fork() properly
* include/private/gcconfig.h (HANDLE_FORK): Define also for Cygwin (but not for win32-pthreads and not if Win32 memory allocation used). * win32_threads.c: Include unistd.h if HANDLE_FORK (for pthread_atfork). * win32_threads.c (GC_wait_for_gc_completion): Add wait_for_all argument. * win32_threads.c (GC_unregister_my_thread, GC_thread_exit_proc): Pass FALSE ("wait_for_all" argument) to GC_wait_for_gc_completion. * win32_threads.c (GC_remove_all_threads_but_me, GC_fork_prepare_proc, GC_fork_parent_proc, GC_fork_child_proc): New functions (similar to that in pthread_support.c) if HANDLE_FORK. * win32_threads.c (GC_thr_init): Invoke pthread_atfork if HANDLE_FORK.
Diffstat (limited to 'win32_threads.c')
-rw-r--r--win32_threads.c99
1 files changed, 93 insertions, 6 deletions
diff --git a/win32_threads.c b/win32_threads.c
index 09bfbd41..1682b2cc 100644
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -55,6 +55,9 @@
STATIC void GC_thread_exit_proc(void *arg);
# include <pthread.h>
+# ifdef HANDLE_FORK
+# include <unistd.h>
+# endif
#else
@@ -759,8 +762,8 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
}
}
-/* Similar to that in pthread_support.c (wait_for_all is always FALSE). */
-STATIC void GC_wait_for_gc_completion(void)
+/* Similar to that in pthread_support.c. */
+STATIC void GC_wait_for_gc_completion(GC_bool wait_for_all)
{
GC_ASSERT(I_HOLD_LOCK());
if (GC_incremental && GC_collection_in_progress()) {
@@ -779,7 +782,7 @@ STATIC void GC_wait_for_gc_completion(void)
Sleep(0); /* yield */
LOCK();
} while (GC_incremental && GC_collection_in_progress()
- && old_gc_no == GC_gc_no);
+ && (wait_for_all || old_gc_no == GC_gc_no));
}
}
@@ -809,7 +812,7 @@ GC_API int GC_CALL GC_unregister_my_thread(void)
DWORD thread_id = GetCurrentThreadId();
LOCK();
- GC_wait_for_gc_completion();
+ GC_wait_for_gc_completion(FALSE);
# if defined(THREAD_LOCAL_ALLOC) || defined(GC_PTHREADS)
me = GC_lookup_thread_inner(thread_id);
CHECK_LOOKUP_MY_THREAD(me);
@@ -982,6 +985,83 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
}
}
+# ifdef HANDLE_FORK
+ /* Similar to that in pthread_support.c. */
+ STATIC void GC_remove_all_threads_but_me(void)
+ {
+ pthread_t id = pthread_self();
+ int hv;
+ GC_thread p, next, me;
+
+ for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
+ me = 0;
+ for (p = GC_threads[hv]; 0 != p; p = next) {
+ next = p -> tm.next;
+ if (THREAD_EQUAL(p -> pthread_id, id)) {
+ me = p;
+ p -> tm.next = 0;
+ /* Update Win32 thread Id and handle. */
+ me -> id = GetCurrentThreadId();
+# ifndef MSWINCE
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(),
+ (HANDLE *)&me->handle, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ ABORT("DuplicateHandle failed");
+# endif
+ } else {
+# ifdef THREAD_LOCAL_ALLOC
+ if ((p -> flags & FINISHED) == 0) {
+ GC_destroy_thread_local(&p->tlfs);
+ }
+# endif
+ if (&first_thread != p)
+ GC_INTERNAL_FREE(p);
+ }
+ }
+ GC_threads[hv] = me;
+ }
+ }
+
+ STATIC void GC_fork_prepare_proc(void)
+ {
+ LOCK();
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_wait_for_reclaim();
+# endif
+ GC_wait_for_gc_completion(TRUE);
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_acquire_mark_lock();
+# endif
+ }
+
+ STATIC void GC_fork_parent_proc(void)
+ {
+# ifdef PARALLEL_MARK
+ if (GC_parallel)
+ GC_release_mark_lock();
+# endif
+ UNLOCK();
+ }
+
+ STATIC void GC_fork_child_proc(void)
+ {
+# ifdef PARALLEL_MARK
+ if (GC_parallel) {
+ GC_release_mark_lock();
+ GC_parallel = FALSE; /* or GC_markers_m1 = 0 */
+ /* Turn off parallel marking in the child, since we are */
+ /* probably just going to exec, and we would have to */
+ /* restart mark threads. */
+ }
+# endif
+ GC_remove_all_threads_but_me();
+ UNLOCK();
+ }
+# endif /* HANDLE_FORK */
+
#endif /* GC_PTHREADS */
void GC_push_thread_structures(void)
@@ -1593,7 +1673,7 @@ GC_INNER void GC_get_next_stack(char *start, char *limit,
# endif
/* start_mark_threads() is the same as in pthread_support.c except for: */
- /* - GC_markers_m1 value is adjusted already; */
+ /* - GC_markers_m1 value is adjusted already; */
/* - thread stack is assumed to be large enough; and */
/* - statistics about the number of marker threads is printed outside. */
static void start_mark_threads(void)
@@ -2280,6 +2360,13 @@ GC_INNER void GC_thr_init(void)
GC_main_thread = GetCurrentThreadId();
GC_thr_initialized = TRUE;
+# if defined(GC_PTHREADS) && defined(HANDLE_FORK)
+ /* Prepare for a possible fork. */
+ if (pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
+ GC_fork_child_proc) != 0)
+ ABORT("pthread_atfork failed");
+# endif
+
/* Add the initial thread, so we can stop it. */
# ifdef GC_ASSERTIONS
sb_result =
@@ -2544,7 +2631,7 @@ GC_INNER void GC_thr_init(void)
# endif
LOCK();
- GC_wait_for_gc_completion();
+ GC_wait_for_gc_completion(FALSE);
# if defined(THREAD_LOCAL_ALLOC)
GC_destroy_thread_local(&(me->tlfs));
# endif