summaryrefslogtreecommitdiff
path: root/pthread_support.c
diff options
context:
space:
mode:
authorIvan Maidanski <ivmai@mail.ru>2023-04-06 08:25:33 +0300
committerIvan Maidanski <ivmai@mail.ru>2023-04-06 13:17:41 +0300
commit3e35cb1fa09e80d601929bdb2f4b4ed51b50aa7a (patch)
tree8d12fa5cced5164c296fdd4c2b6ef8192f1e5fbd /pthread_support.c
parent68d419a51fa73765ac66beb348a6c577ca1963ac (diff)
downloadbdwgc-3e35cb1fa09e80d601929bdb2f4b4ed51b50aa7a.tar.gz
Revert "Remove first_thread/crtn static variables"
Issue #536 (bdwgc). This reverts commit 92dce071fa2db2b615981818b1db1024558d09ca. Reason: there should be no objects allocation in GC_init (because static data root are registered later in GC_init on Darwin, and because the client might call GC_enable_incremental after GC_init and in case of GWW_VDB any object allocation should be generally avoided before GC_enable_incremental is called). Thus, we need the first entry in GC_threads table to be allocated statically.
Diffstat (limited to 'pthread_support.c')
-rw-r--r--pthread_support.c142
1 files changed, 79 insertions, 63 deletions
diff --git a/pthread_support.c b/pthread_support.c
index 30addcbe..1753fa89 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -604,6 +604,12 @@
/* Not used if GC_win32_dll_threads is set. */
GC_INNER GC_thread GC_threads[THREAD_TABLE_SZ] = {0};
+/* It may not be safe to allocate when we register the first thread. */
+/* Note that next and status fields are unused, but there might be some */
+/* other fields (crtn and backing_store_end) to be pushed. */
+static struct GC_StackContext_Rep first_crtn;
+static struct GC_Thread_Rep first_thread;
+
/* A place to retain a pointer to an allocated object while a thread */
/* registration is ongoing. Protected by the GC lock. */
static GC_stack_context_t saved_crtn = NULL;
@@ -626,6 +632,14 @@ void GC_push_thread_structures(void)
# endif
/* else */ {
GC_PUSH_ALL_SYM(GC_threads);
+# ifdef E2K
+ GC_PUSH_ALL_SYM(first_crtn.backing_store_end);
+# endif
+ GC_ASSERT(NULL == first_thread.tm.next);
+# ifdef GC_PTHREADS
+ GC_ASSERT(NULL == first_thread.status);
+# endif
+ GC_PUSH_ALL_SYM(first_thread.crtn);
GC_PUSH_ALL_SYM(saved_crtn);
}
# if defined(THREAD_LOCAL_ALLOC) && defined(USE_CUSTOM_SPECIFIC)
@@ -639,10 +653,14 @@ void GC_push_thread_structures(void)
if (!GC_win32_dll_threads && GC_auto_incremental) {
GC_stack_context_t crtn = t -> crtn;
- GC_ASSERT(SMALL_OBJ(GC_size(crtn)));
- GC_remove_protection(HBLKPTR(crtn), 1, FALSE);
- GC_ASSERT(SMALL_OBJ(GC_size(t)));
- GC_remove_protection(HBLKPTR(t), 1, FALSE);
+ if (crtn != &first_crtn) {
+ GC_ASSERT(SMALL_OBJ(GC_size(crtn)));
+ GC_remove_protection(HBLKPTR(crtn), 1, FALSE);
+ }
+ if (t != &first_thread) {
+ GC_ASSERT(SMALL_OBJ(GC_size(t)));
+ GC_remove_protection(HBLKPTR(t), 1, FALSE);
+ }
}
}
#endif /* MPROTECT_VDB && GC_WIN32_THREADS */
@@ -675,7 +693,6 @@ GC_INNER_WIN32THREAD GC_thread GC_new_thread(thread_id_t self_id)
{
int hv = THREAD_TABLE_INDEX(self_id);
GC_thread result;
- GC_stack_context_t crtn;
GC_ASSERT(I_HOLD_LOCK());
# ifdef DEBUG_THREADS
@@ -687,26 +704,42 @@ GC_INNER_WIN32THREAD GC_thread GC_new_thread(thread_id_t self_id)
break;
}
# endif
- GC_ASSERT(!GC_win32_dll_threads);
- GC_ASSERT(!GC_in_thread_creation);
- GC_in_thread_creation = TRUE; /* OK to collect from unknown thread */
- crtn = (GC_stack_context_t)GC_INTERNAL_MALLOC(
- sizeof(struct GC_StackContext_Rep), NORMAL);
+ if (EXPECT(NULL == first_thread.crtn, FALSE)) {
+ result = &first_thread;
+ first_thread.crtn = &first_crtn;
+ GC_ASSERT(NULL == GC_threads[hv]);
+# ifdef CPPCHECK
+ GC_noop1((unsigned char)first_thread.flags_pad[0]);
+# if defined(THREAD_SANITIZER) && defined(SIGNAL_BASED_STOP_WORLD)
+ GC_noop1((unsigned char)first_crtn.dummy[0]);
+# endif
+# ifndef GC_NO_FINALIZATION
+ GC_noop1((unsigned char)first_crtn.fnlz_pad[0]);
+# endif
+# endif
+ } else {
+ GC_stack_context_t crtn;
- /* The current stack is not scanned until the thread is */
- /* registered, thus crtn pointer is to be retained in the */
- /* global data roots for a while (and pushed explicitly if */
- /* a collection occurs here). */
- GC_ASSERT(NULL == saved_crtn);
- saved_crtn = crtn;
- result = (GC_thread)GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep),
- NORMAL);
- saved_crtn = NULL; /* no more collections till thread is registered */
- GC_in_thread_creation = FALSE;
- if (NULL == crtn || NULL == result)
- ABORT("Failed to allocate memory for thread registering");
- result -> crtn = crtn;
+ GC_ASSERT(!GC_win32_dll_threads);
+ GC_ASSERT(!GC_in_thread_creation);
+ GC_in_thread_creation = TRUE; /* OK to collect from unknown thread */
+ crtn = (GC_stack_context_t)GC_INTERNAL_MALLOC(
+ sizeof(struct GC_StackContext_Rep), NORMAL);
+ /* The current stack is not scanned until the thread is */
+ /* registered, thus crtn pointer is to be retained in the */
+ /* global data roots for a while (and pushed explicitly if */
+ /* a collection occurs here). */
+ GC_ASSERT(NULL == saved_crtn);
+ saved_crtn = crtn;
+ result = (GC_thread)GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep),
+ NORMAL);
+ saved_crtn = NULL; /* no more collections till thread is registered */
+ GC_in_thread_creation = FALSE;
+ if (NULL == crtn || NULL == result)
+ ABORT("Failed to allocate memory for thread registering");
+ result -> crtn = crtn;
+ }
/* The id field is not set here. */
# ifdef USE_TKILL_ON_ANDROID
result -> kernel_id = gettid();
@@ -717,7 +750,8 @@ GC_INNER_WIN32THREAD GC_thread GC_new_thread(thread_id_t self_id)
GC_nacl_initialize_gc_thread(result);
# endif
GC_ASSERT(0 == result -> flags);
- GC_dirty(result);
+ if (EXPECT(result != &first_thread, TRUE))
+ GC_dirty(result);
return result;
}
@@ -768,14 +802,18 @@ GC_INNER_WIN32THREAD void GC_delete_thread(GC_thread t)
if (NULL == prev) {
GC_threads[hv] = p -> tm.next;
} else {
+ GC_ASSERT(prev != &first_thread);
prev -> tm.next = p -> tm.next;
GC_dirty(prev);
}
-# ifdef GC_DARWIN_THREADS
- mach_port_deallocate(mach_task_self(), p -> mach_thread);
-# endif
- GC_INTERNAL_FREE(p -> crtn);
- GC_INTERNAL_FREE(p);
+ if (EXPECT(p != &first_thread, TRUE)) {
+# ifdef GC_DARWIN_THREADS
+ mach_port_deallocate(mach_task_self(), p -> mach_thread);
+# endif
+ GC_ASSERT(p -> crtn != &first_crtn);
+ GC_INTERNAL_FREE(p -> crtn);
+ GC_INTERNAL_FREE(p);
+ }
}
}
@@ -862,11 +900,6 @@ GC_API int GC_CALL GC_thread_is_registered(void)
return me != NULL && !KNOWN_FINISHED(me);
}
-#ifndef GC_WIN32_THREADS
- static void *main_normstack, *main_altstack;
- static word main_normstack_size, main_altstack_size;
-#endif
-
GC_API void GC_CALL GC_register_altstack(void *normstack,
GC_word normstack_size, void *altstack, GC_word altstack_size)
{
@@ -878,23 +911,19 @@ GC_API void GC_CALL GC_register_altstack(void *normstack,
UNUSED_ARG(altstack_size);
#else
GC_thread me;
+ GC_stack_context_t crtn;
LOCK();
me = GC_self_thread_inner();
- if (EXPECT(me != NULL, TRUE)) {
- GC_stack_context_t crtn = me -> crtn;
-
- crtn -> normstack = (ptr_t)normstack;
- crtn -> normstack_size = normstack_size;
- crtn -> altstack = (ptr_t)altstack;
- crtn -> altstack_size = altstack_size;
- } else {
+ if (EXPECT(NULL == me, FALSE)) {
/* We are called before GC_thr_init. */
- main_normstack = normstack;
- main_normstack_size = normstack_size;
- main_altstack = altstack;
- main_altstack_size = altstack_size;
+ me = &first_thread;
}
+ crtn = me -> crtn;
+ crtn -> normstack = (ptr_t)normstack;
+ crtn -> normstack_size = normstack_size;
+ crtn -> altstack = (ptr_t)altstack;
+ crtn -> altstack_size = altstack_size;
UNLOCK();
#endif
}
@@ -1241,9 +1270,12 @@ GC_INNER void GC_wait_for_gc_completion(GC_bool wait_for_all)
/* TODO: To avoid TSan hang (when updating GC_bytes_freed), */
/* we just skip explicit freeing of GC_threads entries. */
# if !defined(THREAD_SANITIZER) || !defined(CAN_CALL_ATFORK)
+ if (p != &first_thread) {
/* TODO: Should call mach_port_deallocate? */
+ GC_ASSERT(p -> crtn != &first_crtn);
GC_INTERNAL_FREE(p -> crtn);
GC_INTERNAL_FREE(p);
+ }
# endif
}
}
@@ -1657,7 +1689,6 @@ GC_INNER void GC_thr_init(void)
{
struct GC_stack_base sb;
GC_thread me;
- GC_stack_context_t crtn;
thread_id_t self_id = thread_id_self();
sb.mem_base = GC_stackbottom;
@@ -1673,22 +1704,6 @@ GC_INNER void GC_thr_init(void)
GC_main_thread_id = self_id;
# endif
me -> flags = DETACHED;
- /* Copy the alt-stack information if set. */
- crtn = me -> crtn;
- crtn -> normstack = (ptr_t)main_normstack;
- crtn -> normstack_size = main_normstack_size;
- crtn -> altstack = (ptr_t)main_altstack;
- crtn -> altstack_size = main_altstack_size;
-
-# ifdef CPPCHECK
- GC_noop1((unsigned char)(me -> flags_pad[0]));
-# if defined(THREAD_SANITIZER) && defined(SIGNAL_BASED_STOP_WORLD)
- GC_noop1((unsigned char)(crtn -> dummy[0]));
-# endif
-# ifndef GC_NO_FINALIZATION
- GC_noop1((unsigned char)(crtn -> fnlz_pad[0]));
-# endif
-# endif
}
}
@@ -2355,6 +2370,7 @@ GC_API int GC_CALL GC_register_my_thread(const struct GC_stack_base *sb)
/* We register the thread here instead of in the parent, so that */
/* we don't need to hold the allocation lock during pthread_create. */
me = GC_register_my_thread_inner(sb, self_id);
+ GC_ASSERT(me != &first_thread);
me -> flags = psi -> flags;
# ifdef GC_WIN32_THREADS
GC_win32_cache_self_pthread(self_id);