summaryrefslogtreecommitdiff
path: root/win32_threads.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2012-02-26 16:55:56 +0100
committerIvan Maidanski <ivmai@mail.ru>2012-02-26 18:19:01 +0100
commit4ab8444c8e477e8fb9152af3965d678f6d912cd5 (patch)
treefd54261b96c1d41ff3ad55b8e8d3646804a625fa /win32_threads.c
parent6f7c0b722b59669d5c49b7af6cbbef86044558ec (diff)
Fix fork() handling on Cygwin (update child thread Id properly and
update child thread-local storage pointer) * win32_threads.c (GC_remove_all_threads_but_me): Update comment; re-hash GC_threads map as thread Win32 Id in the child differs from that in the parent; rename "id" local variable to "pthread_id". * win32_threads.c (GC_remove_all_threads_but_me): Call GC_setspecific (if THREAD_LOCAL_ALLOC) to re-assign Win32-based thread-local pointer to 'tlfs' (identified by GC_thread_key) of the current thread.
Diffstat (limited to 'win32_threads.c')
-rw-r--r--win32_threads.c47
1 files changed, 32 insertions, 15 deletions
diff --git a/win32_threads.c b/win32_threads.c
index 6b891d3..af2ccd9 100644
--- a/win32_threads.c
+++ b/win32_threads.c
@@ -971,29 +971,23 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
}
# ifdef HANDLE_FORK
- /* Similar to that in pthread_support.c. */
+ /* Similar to that in pthread_support.c but also rehashes the table */
+ /* since hash map key (thread_id) differs from that in the parent. */
STATIC void GC_remove_all_threads_but_me(void)
{
- pthread_t id = pthread_self();
int hv;
- GC_thread p, next, me;
+ GC_thread p, next, me = NULL;
+ DWORD thread_id;
+ pthread_t pthread_id = pthread_self(); /* same as in parent */
+ GC_ASSERT(!GC_win32_dll_threads);
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)) {
+ if (THREAD_EQUAL(p -> pthread_id, pthread_id)) {
+ GC_ASSERT(me == NULL);
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) {
@@ -1004,8 +998,31 @@ GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
GC_INTERNAL_FREE(p);
}
}
- GC_threads[hv] = me;
+ GC_threads[hv] = NULL;
}
+
+ /* Put "me" back to GC_threads. */
+ GC_ASSERT(me != NULL);
+ thread_id = GetCurrentThreadId(); /* differs from that in parent */
+ GC_threads[THREAD_TABLE_INDEX(thread_id)] = me;
+
+ /* Update Win32 thread Id and handle. */
+ me -> id = thread_id;
+# ifndef MSWINCE
+ if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), (HANDLE *)&me->handle,
+ 0 /* dwDesiredAccess */, FALSE /* bInheritHandle */,
+ DUPLICATE_SAME_ACCESS))
+ ABORT("DuplicateHandle failed");
+# endif
+
+# if defined(THREAD_LOCAL_ALLOC) && !defined(USE_CUSTOM_SPECIFIC)
+ /* For Cygwin, we need to re-assign thread-local pointer to */
+ /* 'tlfs' (it is ok to call GC_destroy_thread_local and */
+ /* GC_free_internal before this action). */
+ if (GC_setspecific(GC_thread_key, &me->tlfs) != 0)
+ ABORT("GC_setspecific failed (in child)");
+# endif
}
STATIC void GC_fork_prepare_proc(void)