Skip to content

Commit

Permalink
Make safepoint thread local.
Browse files Browse the repository at this point in the history
Preparing for using the safepoint to deliver SIGINT, which requires distinguish
between master and worker threads.
  • Loading branch information
yuyichao committed May 5, 2016
1 parent 1a721b3 commit 035be96
Show file tree
Hide file tree
Showing 11 changed files with 51 additions and 45 deletions.
9 changes: 8 additions & 1 deletion src/cgutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ static bool deserves_sret(jl_value_t *dt, Type *T)
static Value *emit_nthptr_addr(Value *v, ssize_t n)
{
return builder.CreateGEP(builder.CreateBitCast(v, T_ppjlvalue),
ConstantInt::get(T_size, (ssize_t)n));
ConstantInt::get(T_size, n));
}

static Value *emit_nthptr_addr(Value *v, Value *idx)
Expand All @@ -477,6 +477,13 @@ static Value *emit_nthptr_recast(Value *v, Value *idx, MDNode *tbaa, Type *ptype
return tbaa_decorate(tbaa,builder.CreateLoad(builder.CreateBitCast(vptr,ptype), false));
}

static Value *emit_nthptr_recast(Value *v, ssize_t n, MDNode *tbaa, Type *ptype)
{
// p = (jl_value_t**)v; *(ptype)&p[n]
Value *vptr = emit_nthptr_addr(v, n);
return tbaa_decorate(tbaa,builder.CreateLoad(builder.CreateBitCast(vptr,ptype), false));
}

static Value *emit_typeptr_addr(Value *p)
{
ssize_t offset = (sizeof(jl_taggedvalue_t) -
Expand Down
20 changes: 3 additions & 17 deletions src/codegen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,9 +343,6 @@ static GlobalVariable *jltls_states_var;
static GlobalVariable *jltls_states_func_ptr = NULL;
static size_t jltls_states_func_idx = 0;
#endif
// Imaging mode only (non-imaging mode use pointer directly)
static GlobalVariable *jl_safepoint_page_ptr = NULL;
static size_t jl_safepoint_page_idx = 0;

// important functions
static Function *jlnew_func;
Expand Down Expand Up @@ -3430,14 +3427,9 @@ static void allocate_gc_frame(BasicBlock *b0, jl_codectx_t *ctx)
{
// allocate a placeholder gc instruction
ctx->ptlsStates = builder.CreateCall(prepare_call(jltls_states_func));
if (imaging_mode) {
ctx->signalPage =
tbaa_decorate(tbaa_const, builder.CreateLoad(prepare_global(jl_safepoint_page_ptr)));
}
else {
ctx->signalPage = builder.CreateIntToPtr(
ConstantInt::get(T_size, (uintptr_t)jl_safepoint_page), T_pint8);
}
int nthfield = offsetof(jl_tls_states_t, safepoint) / sizeof(void*);
ctx->signalPage = emit_nthptr_recast(ctx->ptlsStates, nthfield, tbaa_const,
PointerType::get(T_psize, 0));
}

void jl_codegen_finalize_temp_arg(CallInst *ptlsStates, Type *T_pjlvalue,
Expand Down Expand Up @@ -5170,12 +5162,6 @@ static void init_julia_llvm_env(Module *m)
jltls_states_func_idx);
}
#endif
if (imaging_mode) {
jl_safepoint_page_ptr =
jl_emit_sysimg_slot(m, T_pint8, "jl_safepoint_page.ptr",
(uintptr_t)jl_safepoint_page,
jl_safepoint_page_idx);
}

std::vector<Type*> args1(0);
args1.push_back(T_pint8);
Expand Down
3 changes: 0 additions & 3 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,6 @@ static int jl_load_sysimg_so(void)
*sysimg_gvars[tls_getter_idx - 1] =
(jl_value_t*)jl_get_ptls_states_getter();
#endif
size_t safepoint_idx = *(size_t*)jl_dlsym(jl_sysimg_handle,
"jl_safepoint_page_idx");
*sysimg_gvars[safepoint_idx - 1] = (jl_value_t*)jl_safepoint_page;
const char *cpu_target = (const char*)jl_dlsym(jl_sysimg_handle, "jl_sysimg_cpu_target");
if (strcmp(cpu_target,jl_options.cpu_target) != 0)
jl_error("Julia and the system image were compiled for different architectures.\n"
Expand Down
10 changes: 3 additions & 7 deletions src/jitlayers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -812,10 +812,11 @@ static void* jl_emit_and_add_to_shadow(GlobalVariable *gv, void *gvarinit = NULL
#endif
}

#ifdef JULIA_ENABLE_THREADING
// Emit a slot in the system image to be filled at sysimg init time.
// Returns the global var. Fill `idx` with 1-base index in the sysimg gv.
// Use as an optimization for runtime constant addresses to have one less
// load.
// load. (Used only by threading).
static GlobalVariable *jl_emit_sysimg_slot(Module *m, Type *typ, const char *name,
uintptr_t init, size_t &idx)
{
Expand All @@ -839,6 +840,7 @@ static GlobalVariable *jl_emit_sysimg_slot(Module *m, Type *typ, const char *nam
idx = jl_sysimg_gvars.size();
return gv;
}
#endif

static void* jl_get_global(GlobalVariable *gv)
{
Expand Down Expand Up @@ -914,12 +916,6 @@ static void jl_gen_llvm_globaldata(llvm::Module *mod, ValueToValueMapTy &VMap,
ConstantInt::get(T_size, jltls_states_func_idx),
"jl_ptls_states_getter_idx"));
#endif
addComdat(new GlobalVariable(*mod,
T_size,
true,
GlobalVariable::ExternalLinkage,
ConstantInt::get(T_size, jl_safepoint_page_idx),
"jl_safepoint_page_idx"));

Constant *feature_string = ConstantDataArray::getString(jl_LLVMContext, jl_options.cpu_target);
addComdat(new GlobalVariable(*mod,
Expand Down
6 changes: 6 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ void jl_start_threads(void);
void jl_shutdown_threading(void);

// Whether the GC is running
extern char *jl_safepoint_pages;
STATIC_INLINE int jl_addr_is_safepoint(uintptr_t addr)
{
uintptr_t safepoint_addr = (uintptr_t)jl_safepoint_pages;
return addr >= safepoint_addr && addr < safepoint_addr + jl_page_size * 3;
}
extern volatile uint32_t jl_gc_running;
// All the functions are safe to be called from within a signal handler
// provided that the thread will not be interrupted by another asynchronous
Expand Down
12 changes: 6 additions & 6 deletions src/julia_threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
typedef struct _jl_tls_states_t {
struct _jl_gcframe_t *pgcstack;
struct _jl_value_t *exception_in_transit;
volatile size_t *safepoint;
// Whether it is safe to execute GC at the same time.
#define JL_GC_STATE_WAITING 1
// gc_state = 1 means the thread is doing GC or is waiting for the GC to
Expand Down Expand Up @@ -285,15 +286,14 @@ JL_DLLEXPORT void (jl_cpu_wake)(void);

// Accessing the tls variables, gc safepoint and gc states
JL_DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void);
JL_DLLEXPORT extern volatile size_t *jl_safepoint_page;
// This triggers a SegFault when we are in GC
// Assign it to a variable to make sure the compiler emit the load
// and to avoid Clang warning for -Wunused-volatile-lvalue
#define jl_gc_safepoint() do { \
jl_signal_fence(); \
size_t safepoint_load = *jl_safepoint_page; \
jl_signal_fence(); \
(void)safepoint_load; \
#define jl_gc_safepoint() do { \
jl_signal_fence(); \
size_t safepoint_load = *jl_get_ptls_states()->safepoint; \
jl_signal_fence(); \
(void)safepoint_load; \
} while (0)
#ifndef JULIA_ENABLE_THREADING
extern JL_DLLEXPORT jl_tls_states_t jl_tls_states;
Expand Down
20 changes: 13 additions & 7 deletions src/safepoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ extern "C" {

/* static uint32_t jl_signal_pending = 0; */
volatile uint32_t jl_gc_running = 0;
JL_DLLEXPORT volatile size_t *jl_safepoint_page = NULL;
// The number of safepoints enabled on the two pages.
// The first page, the one before `jl_safepoint_page` is the SIGINT page.
// The second page, the one pointed to by `jl_safepoint_page` is the GC page.
char *jl_safepoint_pages = NULL;
// The number of safepoints enabled on the three pages.
// The first page, is the SIGINT page, only used by the master thread.
// The second page, is the GC page for the master thread, this is where
// the `safepoint` tls pointer points to for the master thread.
// The third page is the GC page for the other threads. The thread's
// `safepoint` tls pointer points the beginning of this page + `sizeof(size_t)`
// so that both safepoint load and pending signal load falls in this page.
// The initialization of the `safepoint` pointer is done `ti_initthread`
// in `threading.c`.
uint8_t jl_safepoint_enable_cnt[3] = {0, 0, 0};

// This lock should be acquired before enabling/disabling the safepoint
Expand Down Expand Up @@ -48,7 +54,7 @@ static void jl_safepoint_enable(int idx)
return;
}
// Now that we are requested to mprotect the page and it wasn't already.
char *pageaddr = (char*)jl_safepoint_page + jl_page_size * (idx - 1);
char *pageaddr = jl_safepoint_pages + jl_page_size * idx;
#ifdef _OS_WINDOWS_
DWORD old_prot;
VirtualProtect(pageaddr, jl_page_size, PAGE_NOACCESS, &old_prot);
Expand All @@ -67,7 +73,7 @@ static void jl_safepoint_disable(int idx)
}
// Now that we are requested to un-mprotect the page and no one else
// want it to be kept protected.
char *pageaddr = (char*)jl_safepoint_page + jl_page_size * (idx - 1);
char *pageaddr = jl_safepoint_pages + jl_page_size * idx;
#ifdef _OS_WINDOWS_
DWORD old_prot;
VirtualProtect(pageaddr, jl_page_size, PAGE_READONLY, &old_prot);
Expand Down Expand Up @@ -95,7 +101,7 @@ void jl_safepoint_init(void)
}
// The signal page is for the gc safepoint.
// The page before it is the sigint pending flag.
jl_safepoint_page = (size_t*)(addr + pgsz);
jl_safepoint_pages = addr;
}

int jl_safepoint_start_gc(void)
Expand Down
2 changes: 1 addition & 1 deletion src/signals-mach.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ kern_return_t catch_exception_raise(mach_port_t exception_port,
HANDLE_MACH_ERROR("thread_get_state", ret);
uint64_t fault_addr = exc_state.__faultvaddr;
#ifdef JULIA_ENABLE_THREADING
if (fault_addr == (uintptr_t)jl_safepoint_page) {
if (jl_addr_is_safepoint(fault_addr)) {
jl_mutex_lock_nogc(&safepoint_lock);
if (!jl_gc_running) {
// GC is done before we get the message, do nothing and return
Expand Down
2 changes: 1 addition & 1 deletion src/signals-unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static void segv_handler(int sig, siginfo_t *info, void *context)
assert(sig == SIGSEGV || sig == SIGBUS);

#ifdef JULIA_ENABLE_THREADING
if (info->si_addr == jl_safepoint_page) {
if (jl_addr_is_safepoint((uintptr_t)info->si_addr)) {
jl_unblock_signal(sig);
jl_set_gc_and_wait();
return;
Expand Down
3 changes: 1 addition & 2 deletions src/signals-win.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,7 @@ static LONG WINAPI _exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo,
return EXCEPTION_CONTINUE_EXECUTION;
case EXCEPTION_ACCESS_VIOLATION:
#ifdef JULIA_ENABLE_THREADING
if (ExceptionInfo->ExceptionRecord->ExceptionInformation[1] ==
(intptr_t)jl_safepoint_page) {
if (jl_addr_is_safepoint(ExceptionInfo->ExceptionRecord->ExceptionInformation[1])) {
jl_set_gc_and_wait();
return EXCEPTION_CONTINUE_EXECUTION;
}
Expand Down
9 changes: 9 additions & 0 deletions src/threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ static void ti_initthread(int16_t tid)
ptls->tid = tid;
ptls->pgcstack = NULL;
ptls->gc_state = 0; // GC unsafe
// Conditionally initialize the safepoint address. See comment in
// `safepoint.c`
if (tid == 0) {
ptls->safepoint = (size_t*)(jl_safepoint_pages + jl_page_size);
}
else {
ptls->safepoint = (size_t*)(jl_safepoint_pages + jl_page_size * 2 +
sizeof(size_t));
}
ptls->current_module = NULL;
void *bt_data = malloc(sizeof(uintptr_t) * (JL_MAX_BT_SIZE + 1));
if (bt_data == NULL) {
Expand Down

0 comments on commit 035be96

Please sign in to comment.