Skip to content

Commit

Permalink
Add support for scanning compiler thread locals
Browse files Browse the repository at this point in the history
Rust's fast TLS implementation uses LLVM generated thread-locals where
thread local data is stored in the PT_TLS segment [1].

To allow the BDWGC to scan this, we must locate the PT_TLS block for
each thread which is suspended during GC, and then add this to the range
of values which need marking.
  • Loading branch information
jacob-hughes committed Feb 14, 2024
1 parent fa21d71 commit a6a3714
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/private/pthread_support.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@

EXTERN_C_BEGIN

typedef struct GC_ThreadLocalRoots {
ptr_t start;
ptr_t end;
} tlr;

typedef struct GC_StackContext_Rep {
# if defined(THREAD_SANITIZER) && defined(SIGNAL_BASED_STOP_WORLD)
char dummy[sizeof(oh)]; /* A dummy field to avoid TSan false */
Expand Down Expand Up @@ -113,6 +118,7 @@ typedef struct GC_StackContext_Rep {
/* stack (thread); may be NULL. */

ptr_t tls_rootset;
tlr compiler_thread_roots;
} *GC_stack_context_t;

#ifdef GC_WIN32_THREADS
Expand Down
54 changes: 54 additions & 0 deletions pthread_stop_world.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
# include <alloca.h>
#endif

# include <link.h>

GC_INLINE void GC_usleep(unsigned us)
{
# if defined(LINT2) || defined(THREAD_SANITIZER)
Expand Down Expand Up @@ -325,10 +327,53 @@ GC_INLINE void GC_store_stack_ptr(GC_stack_context_t crtn)
# endif
}

static int find_segment(struct dl_phdr_info *info, size_t size, void *data) {
UNUSED_ARG(size);
tlr * roots = (tlr *) data;

for (size_t i = 0; i < info->dlpi_phnum; i ++) {
if ( info -> dlpi_phdr[i].p_type != PT_TLS )
continue;

if ( info -> dlpi_tls_data == NULL )
/* This SO has no thread locals */
return 0;

size_t memsz = info -> dlpi_phdr[i].p_memsz;
ptr_t start = info -> dlpi_tls_data;

GC_ASSERT(memsz > 0);

roots -> start = start;
roots -> end = start + memsz;
return 1;
}
return 0;
}


/* Get the TLS roots for the current thread. */
/* */
/* This works because a Rust program (and any shared objects) use the PT_TLS */
/* segment in the binary to store every thread's local instance of each */
/* thread-local variable. For each thread, these instances are stored at a */
/* fixed offset inside the same PT_TLS segment [1]. */
/* */
/* This returns the ranges inside the `PT_TLS` segment which contains the */
/* thread-local instances for the current thread only. */
/* */
/* [1]: https://www.akkadia.org/drepper/tls.pdf */
void get_thread_local_roots(tlr * roots)
{
dl_iterate_phdr(find_segment, roots);
return;
}

STATIC void GC_suspend_handler_inner(ptr_t dummy, void *context)
{
GC_thread me;
GC_stack_context_t crtn;
struct GC_ThreadLocalRoots tlr;
# ifdef E2K
ptr_t bs_lo;
size_t stack_size;
Expand Down Expand Up @@ -371,6 +416,9 @@ STATIC void GC_suspend_handler_inner(ptr_t dummy, void *context)
crtn = me -> crtn;
GC_store_stack_ptr(crtn);
crtn -> tls_rootset = GC_tls_rootset();
get_thread_local_roots(&tlr);
crtn -> compiler_thread_roots = tlr;

# ifdef E2K
GC_ASSERT(NULL == crtn -> backing_store_end);
GET_PROCEDURE_STACK_LOCAL(&bs_lo, &stack_size);
Expand Down Expand Up @@ -801,7 +849,10 @@ GC_INNER void GC_push_all_stacks(void)
// perform null check.
GC_thread me = GC_self_thread_inner();
if (me != NULL) {
struct GC_ThreadLocalRoots tlr;
get_thread_local_roots(&tlr);
me -> crtn -> tls_rootset = GC_tls_rootset();
me -> crtn -> compiler_thread_roots = tlr;
}

GC_ASSERT(I_HOLD_LOCK());
Expand Down Expand Up @@ -887,6 +938,9 @@ GC_INNER void GC_push_all_stacks(void)
if (GC_sp_corrector != 0)
GC_sp_corrector((void **)&lo, (void *)(p -> id));
# endif
/* Scan the TLS roots */
GC_push_all_eager(crtn->compiler_thread_roots.start, crtn->compiler_thread_roots.end);

GC_push_all_stack_sections(lo, hi, traced_stack_sect);
# ifdef DEBUG_THREADS
GC_log_printf("Pushing TLS rootset from thread %p\n",
Expand Down

0 comments on commit a6a3714

Please sign in to comment.