diff options
author | Brian J. Cardiff <bcardiff@gmail.com> | 2019-05-06 12:06:12 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2019-05-06 12:06:12 +0300 |
commit | 5668de71107022a316ee967162bc16c10754b9ce (patch) | |
tree | 7867c8c9a20e1a5f42c931fec5f431886e8318a8 /pthread_support.c | |
parent | 757fcad526d4d1520142c4ab60f86902a36d0caf (diff) | |
download | bdwgc-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.c | 56 |
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 */ |