diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2012-02-24 14:34:34 +0400 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2012-02-24 14:34:34 +0400 |
commit | 11e95a1dfdd8ac1ed729d822a2968cb389e253d1 (patch) | |
tree | e768dc34472cb975e55940b4eb61c06693e18cd3 /win32_threads.c | |
parent | ee0301906ae01bdd6d3a0fb4105c8a45d6bfae82 (diff) | |
download | bdwgc-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.c | 99 |
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 |