summaryrefslogtreecommitdiff
path: root/pthread_support.c
diff options
context:
space:
mode:
authorBrian J. Cardiff <bcardiff@gmail.com>2019-05-06 12:06:12 +0300
committerIvan Maidanski <ivmai@mail.ru>2019-05-06 12:06:12 +0300
commit5668de71107022a316ee967162bc16c10754b9ce (patch)
tree7867c8c9a20e1a5f42c931fec5f431886e8318a8 /pthread_support.c
parent757fcad526d4d1520142c4ab60f86902a36d0caf (diff)
downloadbdwgc-5668de71107022a316ee967162bc16c10754b9ce.tar.gz
Add API functions to get and set the stack bottom of each thread
Issue #277 (bdwgc). This API is useful to support coroutines. * include/gc.h (GC_get_my_stackbottom, GC_set_stackbottom): New API function declaration. * misc.c [!THREADS] (GC_set_stackbottom, GC_get_my_stackbottom): New function definition. * pthread_support.c [GC_PTHREADS && !GC_WIN32_THREADS] (GC_set_stackbottom, GC_get_my_stackbottom): Likewise. * win32_threads.c [GC_WIN32_THREADS] (GC_set_stackbottom, GC_get_my_stackbottom): Likewise. * tests/test.c (struct thr_hndl_sb_s): Define. * tests/test.c (set_stackbottom): New function (which calls GC_set_stackbottom). * tests/test.c (run_one_test): Define thr_hndl_sb local variable; call GC_get_my_stackbottom() and set_stackbottom(). * win32_threads.c [GC_WIN32_THREADS && I386] (struct GC_Thread_Rep): Add initial_stack_base field. * win32_threads.c [GC_WIN32_THREADS && I386] (GC_record_stack_base, GC_call_with_gc_active): Set initial_stack_base field. * win32_threads.c [GC_WIN32_THREADS && I386] (GC_push_stack_for): Handle the case when GetThreadContext() might return stale register values, thread stack_base != initial_stack_base but the stack is not inside the TIB stack (use context.Esp but call WARN); add TODO.
Diffstat (limited to 'pthread_support.c')
-rw-r--r--pthread_support.c56
1 files changed, 56 insertions, 0 deletions
diff --git a/pthread_support.c b/pthread_support.c
index 6c138c1c..0b2af4ac 100644
--- a/pthread_support.c
+++ b/pthread_support.c
@@ -1403,6 +1403,62 @@ GC_INNER void GC_do_blocking_inner(ptr_t data, void * context GC_ATTR_UNUSED)
UNLOCK();
}
+GC_API void GC_CALL GC_set_stackbottom(void *gc_thread_handle,
+ const struct GC_stack_base *sb)
+{
+ GC_thread t = (GC_thread)gc_thread_handle;
+
+ GC_ASSERT(sb -> mem_base != NULL);
+ if (!EXPECT(GC_is_initialized, TRUE)) {
+ GC_ASSERT(NULL == t);
+ } else {
+ GC_ASSERT(I_HOLD_LOCK());
+ if (NULL == t) /* current thread? */
+ t = GC_lookup_thread(pthread_self());
+ GC_ASSERT((t -> flags & FINISHED) == 0);
+ GC_ASSERT(!(t -> thread_blocked)
+ && NULL == t -> traced_stack_sect); /* for now */
+
+ if ((t -> flags & MAIN_THREAD) == 0) {
+ t -> stack_end = (ptr_t)sb->mem_base;
+# ifdef IA64
+ t -> backing_store_end = (ptr_t)sb->reg_base;
+# endif
+ return;
+ }
+ /* Otherwise alter the stack bottom of the primordial thread. */
+ }
+
+ GC_stackbottom = (char*)sb->mem_base;
+# ifdef IA64
+ GC_register_stackbottom = (ptr_t)sb->reg_base;
+# endif
+}
+
+GC_API void * GC_CALL GC_get_my_stackbottom(struct GC_stack_base *sb)
+{
+ pthread_t self = pthread_self();
+ GC_thread me;
+ DCL_LOCK_STATE;
+
+ LOCK();
+ me = GC_lookup_thread(self);
+ /* The thread is assumed to be registered. */
+ if ((me -> flags & MAIN_THREAD) == 0) {
+ sb -> mem_base = me -> stack_end;
+# ifdef IA64
+ sb -> reg_base = me -> backing_store_end;
+# endif
+ } else {
+ sb -> mem_base = GC_stackbottom;
+# ifdef IA64
+ sb -> reg_base = GC_register_stackbottom;
+# endif
+ }
+ UNLOCK();
+ return (void *)me; /* gc_thread_handle */
+}
+
/* GC_call_with_gc_active() has the opposite to GC_do_blocking() */
/* functionality. It might be called from a user function invoked by */
/* GC_do_blocking() to temporarily back allow calling any GC function */