From 11e526f5daaca19238fa2f8bd94e36bd1f5be0c3 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sat, 21 Nov 2015 10:40:19 -0500 Subject: [PATCH 1/6] Threading without LLVM patch --- Make.inc | 6 ------ src/cgutils.cpp | 21 ++++++++++++++++++-- src/codegen.cpp | 46 ++++++++++++++++++++++++++------------------ src/gc.c | 2 +- src/julia.h | 45 +++++++++++++++++++++++++------------------ src/julia_internal.h | 2 +- src/task.c | 11 +++-------- src/threading.c | 19 +++++++++++++++++- src/threading.h | 3 +-- 9 files changed, 96 insertions(+), 59 deletions(-) diff --git a/Make.inc b/Make.inc index d0fd4bcbe2d90..4ba534a52ff44 100644 --- a/Make.inc +++ b/Make.inc @@ -275,12 +275,6 @@ else DISABLE_ASSERTIONS := -DNDEBUG endif -# Threads -ifeq ($(JULIA_THREADS), 1) -LLVM_VER := svn -LLVM_GIT_URL_LLVM := https://github.com/JuliaLang/llvm.git -b jn/tls37 -endif - # Compiler specific stuff ifeq ($(USEMSVC), 1) diff --git a/src/cgutils.cpp b/src/cgutils.cpp index b83a130acb156..7a5e10d87a062 100644 --- a/src/cgutils.cpp +++ b/src/cgutils.cpp @@ -2124,12 +2124,29 @@ static jl_cgval_t emit_new_struct(jl_value_t *ty, size_t nargs, jl_value_t **arg } } +static Value *emit_ptls_states() +{ +#ifndef JULIA_ENABLE_THREADING + return prepare_global(jltls_states_var); +#else + return builder.CreateCall(prepare_call(jltls_states_func)); +#endif +} + static Value *emit_pgcstack() { - return prepare_global(jlpgcstack_var); + Value * addr = emit_nthptr_addr( + emit_ptls_states(), + (ssize_t)(offsetof(jl_tls_states_t, pgcstack) / sizeof(void*))); + return builder.CreateBitCast(addr, PointerType::get(T_ppjlvalue, 0), + "jl_pgcstack"); } static Value *emit_exc_in_transit() { - return prepare_global(jlexc_var); + Value * addr = emit_nthptr_addr( + emit_ptls_states(), + (ssize_t)(offsetof(jl_tls_states_t, + exception_in_transit) / sizeof(void*))); + return builder.CreateBitCast(addr, T_ppjlvalue, "jl_exception_in_transit"); } diff --git a/src/codegen.cpp b/src/codegen.cpp index 8844b8273a4d2..945ce9fa3c8e1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -447,8 +447,6 @@ static GlobalVariable *jlemptytuple_var; #ifdef JL_NEED_FLOATTEMP_VAR static GlobalVariable *jlfloattemp_var; #endif -static GlobalVariable *jlpgcstack_var; -static GlobalVariable *jlexc_var; static GlobalVariable *jldiverr_var; static GlobalVariable *jlundeferr_var; static GlobalVariable *jldomerr_var; @@ -467,6 +465,12 @@ extern JITMemoryManager* createJITMemoryManagerWin(); extern RTDyldMemoryManager* createRTDyldMemoryManagerOSX(); #endif +#ifndef JULIA_ENABLE_THREADING +static GlobalVariable *jltls_states_var; +#else +static Function *jltls_states_func; +#endif + // important functions static Function *jlnew_func; static Function *jlthrow_func; @@ -5574,23 +5578,6 @@ static void init_julia_llvm_env(Module *m) "jl_array_t"); jl_parray_llvmt = PointerType::get(jl_array_llvmt,0); -#ifdef JULIA_ENABLE_THREADING -#define JL_THREAD_MODEL ,GlobalValue::GeneralDynamicTLSModel -#else -#define JL_THREAD_MODEL -#endif - jlpgcstack_var = - new GlobalVariable(*m, T_ppjlvalue, - false, GlobalVariable::ExternalLinkage, - NULL, "jl_pgcstack", NULL JL_THREAD_MODEL); - add_named_global(jlpgcstack_var, jl_dlsym(jl_dl_handle, "jl_pgcstack")); - - jlexc_var = - new GlobalVariable(*m, T_pjlvalue, - false, GlobalVariable::ExternalLinkage, - NULL, "jl_exception_in_transit", NULL JL_THREAD_MODEL); - add_named_global(jlexc_var, jl_dlsym(jl_dl_handle, "jl_exception_in_transit")); - global_to_llvm("__stack_chk_guard", (void*)&__stack_chk_guard, m); Function *jl__stack_chk_fail = Function::Create(FunctionType::get(T_void, false), @@ -5640,6 +5627,27 @@ static void init_julia_llvm_env(Module *m) "jl_float_temp")); #endif +#ifndef JULIA_ENABLE_THREADING + size_t tls_states_size = LLT_ALIGN(sizeof(jl_tls_states_t), + sizeof(void*)) / sizeof(void*); + jltls_states_var = + new GlobalVariable(*m, ArrayType::get(T_pint8, tls_states_size), + false, GlobalVariable::ExternalLinkage, + NULL, "jl_tls_states"); + add_named_global(jltls_states_var, (void*)&jl_tls_states); +#else + jltls_states_func = Function::Create(FunctionType::get(T_ppint8, false), + Function::ExternalLinkage, + "jl_get_ptls_states", m); + jltls_states_func->setAttributes( + jltls_states_func->getAttributes() + .addAttribute(jltls_states_func->getContext(), + AttributeSet::FunctionIndex, Attribute::ReadNone) + .addAttribute(jltls_states_func->getContext(), + AttributeSet::FunctionIndex, Attribute::NoUnwind)); + add_named_global(jltls_states_func, (void*)&jl_get_ptls_states); +#endif + std::vector args1(0); args1.push_back(T_pint8); jlerror_func = diff --git a/src/gc.c b/src/gc.c index 7ad24c86481c2..806cf1a050b52 100644 --- a/src/gc.c +++ b/src/gc.c @@ -251,7 +251,7 @@ typedef struct { // In the single-threaded version, they are essentially noops, but nonetheless // serve to check that the thread context macros are being used. #ifdef JULIA_ENABLE_THREADING -static JL_THREAD jl_thread_heap_t *jl_thread_heap; +#define jl_thread_heap (jl_get_ptls_states()->heap) #define FOR_EACH_HEAP() \ for (jl_each_heap_index_t __current_heap_idx = {jl_n_threads, NULL}; \ --current_heap_index >= 0 && \ diff --git a/src/julia.h b/src/julia.h index 921e2aacc8c74..57cffaf61812a 100644 --- a/src/julia.h +++ b/src/julia.h @@ -57,24 +57,13 @@ extern "C" { // threading ------------------------------------------------------------------ -// WARNING: Threading support is incomplete and experimental (and only works with llvm-svn) -// Nonetheless, we define JL_THREAD and use it to give advanced notice to maintainers -// of what eventual threading support will change. +// WARNING: Threading support is incomplete and experimental +// Nonetheless, we define JL_THREAD and use it to give advanced notice to +// maintainers of what eventual threading support will change. // JULIA_ENABLE_THREADING is switched on in Make.inc if JULIA_THREADS is // set (in Make.user) -#ifndef JULIA_ENABLE_THREADING -// Definition for compiling non-thread-safe Julia. -# define JL_THREAD -#elif !defined(_OS_WINDOWS_) -// Definition for compiling Julia on platforms with GCC __thread. -# define JL_THREAD __thread -#else -// Definition for compiling Julia on Windows -# define JL_THREAD __declspec(thread) -#endif - DLLEXPORT int16_t jl_threadid(void); DLLEXPORT void *jl_threadgroup(void); DLLEXPORT void jl_cpu_pause(void); @@ -585,7 +574,7 @@ typedef struct _jl_gcframe_t { // jl_value_t *x=NULL, *y=NULL; JL_GC_PUSH2(&x, &y); // x = f(); y = g(); foo(x, y) -extern DLLEXPORT JL_THREAD jl_gcframe_t *jl_pgcstack; +#define jl_pgcstack (jl_get_ptls_states()->pgcstack) #define JL_GC_PUSH1(arg1) \ void *__gc_stkf[] = {(void*)3, jl_pgcstack, arg1}; \ @@ -1485,10 +1474,10 @@ typedef struct { jl_value_t * volatile *ptask_arg_in_transit; } jl_thread_task_state_t; -extern DLLEXPORT JL_THREAD jl_task_t * volatile jl_current_task; -extern DLLEXPORT JL_THREAD jl_task_t *jl_root_task; -extern DLLEXPORT JL_THREAD jl_value_t *jl_exception_in_transit; -extern DLLEXPORT JL_THREAD jl_value_t * volatile jl_task_arg_in_transit; +#define jl_current_task (jl_get_ptls_states()->current_task) +#define jl_root_task (jl_get_ptls_states()->root_task) +#define jl_exception_in_transit (jl_get_ptls_states()->exception_in_transit) +#define jl_task_arg_in_transit (jl_get_ptls_states()->task_arg_in_transit) DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, size_t ssize); DLLEXPORT jl_value_t *jl_switchto(jl_task_t *t, jl_value_t *arg); @@ -1496,6 +1485,24 @@ DLLEXPORT void NORETURN jl_throw(jl_value_t *e); DLLEXPORT void NORETURN jl_rethrow(void); DLLEXPORT void NORETURN jl_rethrow_other(jl_value_t *e); +typedef struct _jl_tls_states_t { + jl_gcframe_t *pgcstack; + jl_value_t *exception_in_transit; + struct _jl_thread_heap_t *heap; + jl_task_t *volatile current_task; + jl_task_t *root_task; + jl_value_t *volatile task_arg_in_transit; + void *stackbase; + jl_jmp_buf *volatile jmp_target; + jl_jmp_buf base_ctx; // base context of stack + int16_t tid; +} jl_tls_states_t; +DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void); +#ifndef JULIA_ENABLE_THREADING +extern DLLEXPORT jl_tls_states_t jl_tls_states; +#define jl_get_ptls_states() (&jl_tls_states) +#endif + STATIC_INLINE void jl_eh_restore_state(jl_handler_t *eh) { JL_SIGATOMIC_BEGIN(); diff --git a/src/julia_internal.h b/src/julia_internal.h index 0a6a6af69c171..08d5df42ad51d 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -146,7 +146,7 @@ void jl_init_serializer(void); void _julia_init(JL_IMAGE_SEARCH rel); #ifdef COPY_STACKS -extern JL_THREAD void *jl_stackbase; +#define jl_stackbase (jl_get_ptls_states()->stackbase) #endif void jl_set_stackbase(char *__stk); diff --git a/src/task.c b/src/task.c index fbad9ec93b416..035816a4f0dac 100644 --- a/src/task.c +++ b/src/task.c @@ -138,21 +138,17 @@ static jl_sym_t *runnable_sym; extern size_t jl_page_size; jl_datatype_t *jl_task_type; -DLLEXPORT JL_THREAD jl_task_t * volatile jl_current_task; -JL_THREAD jl_task_t *jl_root_task; -DLLEXPORT JL_THREAD jl_value_t *jl_exception_in_transit; -DLLEXPORT JL_THREAD jl_gcframe_t *jl_pgcstack = NULL; +#define jl_root_task (jl_get_ptls_states()->root_task) #ifdef COPY_STACKS -static JL_THREAD jl_jmp_buf * volatile jl_jmp_target; +#define jl_jmp_target (jl_get_ptls_states()->jmp_target) #if (defined(_CPU_X86_64_) || defined(_CPU_X86_)) && !defined(_COMPILER_MICROSOFT_) #define ASM_COPY_STACKS #endif -JL_THREAD void *jl_stackbase; #ifndef ASM_COPY_STACKS -static JL_THREAD jl_jmp_buf jl_base_ctx; // base context of stack +#define jl_base_ctx (jl_get_ptls_states()->base_ctx) #endif static void NOINLINE save_stack(jl_task_t *t) @@ -359,7 +355,6 @@ static void ctx_switch(jl_task_t *t, jl_jmp_buf *where) //JL_SIGATOMIC_END(); } -JL_THREAD jl_value_t * volatile jl_task_arg_in_transit; extern int jl_in_gc; DLLEXPORT jl_value_t *jl_switchto(jl_task_t *t, jl_value_t *arg) { diff --git a/src/threading.c b/src/threading.c index e70c352e84b4f..2c778a6b8a470 100644 --- a/src/threading.c +++ b/src/threading.c @@ -34,8 +34,25 @@ extern "C" { #include "threadgroup.h" #include "threading.h" +#ifdef JULIA_ENABLE_THREADING +# if !defined(_COMPILER_MICROSOFT_) +// Definition for compiling Julia on platforms with GCC __thread. +# define JL_THREAD __thread +# else +// Definition for compiling Julia on Windows +# define JL_THREAD __declspec(thread) +# endif +JL_THREAD jl_tls_states_t jl_tls_states; +#else +DLLEXPORT jl_tls_states_t jl_tls_states; +#endif + +DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void) +{ + return &jl_tls_states; +} + // thread ID -JL_THREAD int16_t ti_tid = 0; DLLEXPORT int jl_n_threads; // # threads we're actually using DLLEXPORT int jl_max_threads; // # threads possible jl_thread_task_state_t *jl_all_task_states; diff --git a/src/threading.h b/src/threading.h index 8b1b803bab636..b5c3938c55251 100644 --- a/src/threading.h +++ b/src/threading.h @@ -14,7 +14,7 @@ extern "C" { #define PROFILE_JL_THREADING 1 // thread ID -extern JL_THREAD int16_t ti_tid; +#define ti_tid (jl_get_ptls_states()->tid) extern jl_thread_task_state_t *jl_all_task_states; extern DLLEXPORT int jl_n_threads; // # threads we're actually using @@ -69,4 +69,3 @@ jl_value_t *ti_runthread(jl_function_t *f, jl_svec_t *args, size_t nargs); #endif #endif /* THREADING_H */ - From d4ee513621833f4182a8ca797354bcbb7813ab8b Mon Sep 17 00:00:00 2001 From: Tony Kelman Date: Sat, 21 Nov 2015 14:17:58 -0800 Subject: [PATCH 2/6] Fix JL_ATOMIC_COMPARE_AND_SWAP under MSVC fixes d:/code/msys64/home/Tony/julia/src/jltypes.c(1910) : error C2664: 'LONG64 _Inter lockedCompareExchange64(volatile LONG64 *,LONG64,LONG64)' : cannot convert argum ent 1 from 'volatile uint64_t *' to 'volatile LONG64 *' Types pointed to are unrelated; conversion requires reinterpret_cast, C- style cast or function-style cast d:/code/msys64/home/Tony/julia/src/jltypes.c(1913) : error C2664: 'LONG64 _Inter lockedCompareExchange64(volatile LONG64 *,LONG64,LONG64)' : cannot convert argum ent 1 from 'volatile uint64_t *' to 'volatile LONG64 *' Types pointed to are unrelated; conversion requires reinterpret_cast, C- style cast or function-style cast d:/code/msys64/home/Tony/julia/src/jltypes.c(1993) : error C2664: 'LONG64 _Inter lockedCompareExchange64(volatile LONG64 *,LONG64,LONG64)' : cannot convert argum ent 1 from 'volatile uint64_t *' to 'volatile LONG64 *' Types pointed to are unrelated; conversion requires reinterpret_cast, C- style cast or function-style cast d:/code/msys64/home/Tony/julia/src/jltypes.c(2000) : error C2664: 'LONG64 _Inter lockedCompareExchange64(volatile LONG64 *,LONG64,LONG64)' : cannot convert argum ent 1 from 'volatile uint64_t *' to 'volatile LONG64 *' Types pointed to are unrelated; conversion requires reinterpret_cast, C- style cast or function-style cast also define sleep for MSVC Kernel32 Sleep takes milliseconds, ref https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298(v=vs.85).aspx fixes d:/code/msys64/home/Tony/julia/src/threading.c(212) : error C3861: 'sleep': iden tifier not found d:/code/msys64/home/Tony/julia/src/threading.c(290) : error C3861: 'sleep': iden tifier not found --- src/julia.h | 4 ++-- src/threading.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/julia.h b/src/julia.h index 57cffaf61812a..11f16603fec01 100644 --- a/src/julia.h +++ b/src/julia.h @@ -69,7 +69,7 @@ DLLEXPORT void *jl_threadgroup(void); DLLEXPORT void jl_cpu_pause(void); DLLEXPORT void jl_threading_profile(void); -#if __GNUC__ +#if defined(__GNUC__) # define JL_ATOMIC_FETCH_AND_ADD(a,b) \ __sync_fetch_and_add(&(a), (b)) # define JL_ATOMIC_COMPARE_AND_SWAP(a,b,c) \ @@ -82,7 +82,7 @@ DLLEXPORT void jl_threading_profile(void); # define JL_ATOMIC_FETCH_AND_ADD(a,b) \ _InterlockedExchangeAdd((volatile LONG *)&(a), (b)) # define JL_ATOMIC_COMPARE_AND_SWAP(a,b,c) \ - _InterlockedCompareExchange64(&(a), (c), (b)) + _InterlockedCompareExchange64((volatile LONG64 *)&(a), (c), (b)) # define JL_ATOMIC_TEST_AND_SET(a) \ _InterlockedExchange64(&(a), 1) # define JL_ATOMIC_RELEASE(a) \ diff --git a/src/threading.c b/src/threading.c index 2c778a6b8a470..8865041e76a03 100644 --- a/src/threading.c +++ b/src/threading.c @@ -21,6 +21,8 @@ #ifndef _MSC_VER #include #include +#else +#define sleep(x) Sleep(1000*x) #endif #include "julia.h" From 103cd89ef12791eb5c27ecf4379202f9ad83d978 Mon Sep 17 00:00:00 2001 From: Tony Kelman Date: Sat, 21 Nov 2015 14:50:07 -0800 Subject: [PATCH 3/6] Move JL_DEFINE_MUTEX_EXT(codegen) to julia_internal.h so that they are always `extern "C"`'d so codegen_mutex and codegen_lock_count do not get c++ mangled --- src/builtins.c | 2 -- src/codegen.cpp | 2 -- src/gf.c | 1 - src/julia_internal.h | 2 ++ 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/builtins.c b/src/builtins.c index f51095e2fd981..212863c430803 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -955,8 +955,6 @@ extern int jl_in_inference; extern int jl_boot_file_loaded; int jl_eval_with_compiler_p(jl_expr_t *ast, jl_expr_t *expr, int compileloops, jl_module_t *m); -JL_DEFINE_MUTEX_EXT(codegen) - static int jl_eval_inner_with_compiler(jl_expr_t *e, jl_module_t *m) { int i; diff --git a/src/codegen.cpp b/src/codegen.cpp index 945ce9fa3c8e1..ab8c8e05b80fa 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -921,8 +921,6 @@ static void maybe_alloc_arrayvar(jl_sym_t *s, jl_codectx_t *ctx) } } -JL_DEFINE_MUTEX_EXT(codegen) - // Snooping on which functions are being compiled, and how long it takes JL_STREAM *dump_compiles_stream = NULL; uint64_t last_time = 0; diff --git a/src/gf.c b/src/gf.c index 87c60bb7fb5d9..4acae1b6bb1db 100644 --- a/src/gf.c +++ b/src/gf.c @@ -420,7 +420,6 @@ jl_function_t *jl_method_cache_insert(jl_methtable_t *mt, jl_tupletype_t *type, can be equal to "li" if not applicable. */ int jl_in_inference = 0; -JL_DEFINE_MUTEX_EXT(codegen) void jl_type_infer(jl_lambda_info_t *li, jl_tupletype_t *argtypes, jl_lambda_info_t *def) { JL_LOCK(codegen); diff --git a/src/julia_internal.h b/src/julia_internal.h index 08d5df42ad51d..a8458e2e1506e 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -335,6 +335,8 @@ DLLEXPORT jl_value_t *jl_flipsign_int(jl_value_t *a, jl_value_t *b); DLLEXPORT jl_value_t *jl_select_value(jl_value_t *isfalse, jl_value_t *a, jl_value_t *b); DLLEXPORT jl_value_t *jl_arraylen(jl_value_t *a); +JL_DEFINE_MUTEX_EXT(codegen) + #ifdef __cplusplus } #endif From 5ceb218ba01f20beab1bccbad4897f6697915bcc Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sat, 21 Nov 2015 23:47:41 -0500 Subject: [PATCH 4/6] Allow the tls state to be overrided (to a faster one) --- src/julia.h | 3 +++ src/threading.c | 27 ++++++++++++++++++++------- ui/repl.c | 15 +++++++++++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/julia.h b/src/julia.h index 11f16603fec01..0009c00864e63 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1501,6 +1501,9 @@ DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void); #ifndef JULIA_ENABLE_THREADING extern DLLEXPORT jl_tls_states_t jl_tls_states; #define jl_get_ptls_states() (&jl_tls_states) +#else +typedef jl_tls_states_t *(*jl_get_ptls_states_func)(void); +DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f); #endif STATIC_INLINE void jl_eh_restore_state(jl_handler_t *eh) diff --git a/src/threading.c b/src/threading.c index 8865041e76a03..d436b6a14ad75 100644 --- a/src/threading.c +++ b/src/threading.c @@ -37,22 +37,35 @@ extern "C" { #include "threading.h" #ifdef JULIA_ENABLE_THREADING +// fallback provided for embedding +static JL_CONST_FUNC jl_tls_states_t *jl_get_ptls_states_fallback(void) +{ # if !defined(_COMPILER_MICROSOFT_) -// Definition for compiling Julia on platforms with GCC __thread. -# define JL_THREAD __thread + static __thread jl_tls_states_t tls_states; # else -// Definition for compiling Julia on Windows -# define JL_THREAD __declspec(thread) + static __declspec(thread) jl_tls_states_t tls_states; # endif -JL_THREAD jl_tls_states_t jl_tls_states; + return &tls_states; +} +static jl_get_ptls_states_func jl_tls_states_cb = jl_get_ptls_states_fallback; +DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void) +{ + return (*jl_tls_states_cb)(); +} +DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f) +{ + // only allow setting this once + if (f && jl_tls_states_cb == jl_get_ptls_states_fallback) { + jl_tls_states_cb = f; + } +} #else DLLEXPORT jl_tls_states_t jl_tls_states; -#endif - DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void) { return &jl_tls_states; } +#endif // thread ID DLLEXPORT int jl_n_threads; // # threads we're actually using diff --git a/ui/repl.c b/ui/repl.c index 30cd1dfab149f..b65acf52c7c16 100644 --- a/ui/repl.c +++ b/ui/repl.c @@ -34,6 +34,18 @@ extern "C" { #endif +#ifdef JULIA_ENABLE_THREADING +static JL_CONST_FUNC jl_tls_states_t *jl_get_ptls_states_static(void) +{ +# if !defined(_COMPILER_MICROSOFT_) + static __thread jl_tls_states_t tls_states; +# else + static __declspec(thread) jl_tls_states_t tls_states; +# endif + return &tls_states; +} +#endif + static int lisp_prompt = 0; static int codecov = JL_LOG_NONE; static int malloclog= JL_LOG_NONE; @@ -595,6 +607,9 @@ int wmain(int argc, wchar_t *argv[], wchar_t *envp[]) if (!WideCharToMultiByte(CP_UTF8, 0, warg, -1, arg, len, NULL, NULL)) return 1; argv[i] = (wchar_t*)arg; } +#endif +#ifdef JULIA_ENABLE_THREADING + jl_set_ptls_states_getter(jl_get_ptls_states_static); #endif libsupport_init(); parse_opts(&argc, (char***)&argv); From 06a255b0876ad2447c86c272e1aedf05c4e1cb09 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sun, 22 Nov 2015 00:21:45 -0500 Subject: [PATCH 5/6] Use the tls states cb function directly for non-imaging code --- src/codegen.cpp | 2 +- src/julia_internal.h | 3 +++ src/threading.c | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/codegen.cpp b/src/codegen.cpp index ab8c8e05b80fa..b85641d47c0ae 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5643,7 +5643,7 @@ static void init_julia_llvm_env(Module *m) AttributeSet::FunctionIndex, Attribute::ReadNone) .addAttribute(jltls_states_func->getContext(), AttributeSet::FunctionIndex, Attribute::NoUnwind)); - add_named_global(jltls_states_func, (void*)&jl_get_ptls_states); + add_named_global(jltls_states_func, (void*)jl_get_ptls_states_getter()); #endif std::vector args1(0); diff --git a/src/julia_internal.h b/src/julia_internal.h index a8458e2e1506e..abdccbad11c57 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -155,6 +155,9 @@ void jl_set_base_ctx(char *__stk); void jl_init_threading(void); void jl_start_threads(void); void jl_shutdown_threading(void); +#ifdef JULIA_ENABLE_THREADING +jl_get_ptls_states_func jl_get_ptls_states_getter(void); +#endif void jl_dump_bitcode(char *fname, const char *sysimg_data, size_t sysimg_len); void jl_dump_objfile(char *fname, int jit_model, const char *sysimg_data, size_t sysimg_len); diff --git a/src/threading.c b/src/threading.c index d436b6a14ad75..e4b8e62e750bb 100644 --- a/src/threading.c +++ b/src/threading.c @@ -59,6 +59,11 @@ DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f) jl_tls_states_cb = f; } } +jl_get_ptls_states_func jl_get_ptls_states_getter(void) +{ + // for codegen + return jl_tls_states_cb; +} #else DLLEXPORT jl_tls_states_t jl_tls_states; DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void) From 2986358b040d861d9925d434e2ee32040ee46269 Mon Sep 17 00:00:00 2001 From: Yichao Yu Date: Sun, 22 Nov 2015 07:57:53 -0500 Subject: [PATCH 6/6] Make sure the tls callback is always initialized before threads starts. --- src/init.c | 4 ++++ src/threading.c | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/init.c b/src/init.c index 2831eff7d33ff..1ff7a501e5dae 100644 --- a/src/init.c +++ b/src/init.c @@ -463,6 +463,10 @@ static void jl_resolve_sysimg_location(JL_IMAGE_SEARCH rel) void _julia_init(JL_IMAGE_SEARCH rel) { +#ifdef JULIA_ENABLE_THREADING + // Make sure we finalize the tls callback before starting any threads. + jl_get_ptls_states_getter(); +#endif libsupport_init(); jl_io_loop = uv_default_loop(); // this loop will internal events (spawning process etc.), // best to call this first, since it also initializes libuv diff --git a/src/threading.c b/src/threading.c index e4b8e62e750bb..54ad15f0a2660 100644 --- a/src/threading.c +++ b/src/threading.c @@ -47,7 +47,16 @@ static JL_CONST_FUNC jl_tls_states_t *jl_get_ptls_states_fallback(void) # endif return &tls_states; } -static jl_get_ptls_states_func jl_tls_states_cb = jl_get_ptls_states_fallback; +static jl_tls_states_t *jl_get_ptls_states_init(void); +static jl_get_ptls_states_func jl_tls_states_cb = jl_get_ptls_states_init; +static jl_tls_states_t *jl_get_ptls_states_init(void) +{ + // This is clearly not thread safe but should be fine since we + // make sure the tls states callback is finalized before adding + // multiple threads + jl_tls_states_cb = jl_get_ptls_states_fallback; + return jl_get_ptls_states_fallback(); +} DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void) { return (*jl_tls_states_cb)(); @@ -55,12 +64,15 @@ DLLEXPORT JL_CONST_FUNC jl_tls_states_t *(jl_get_ptls_states)(void) DLLEXPORT void jl_set_ptls_states_getter(jl_get_ptls_states_func f) { // only allow setting this once - if (f && jl_tls_states_cb == jl_get_ptls_states_fallback) { + if (f && f != jl_get_ptls_states_init && + jl_tls_states_cb == jl_get_ptls_states_init) { jl_tls_states_cb = f; } } jl_get_ptls_states_func jl_get_ptls_states_getter(void) { + if (jl_tls_states_cb == jl_get_ptls_states_init) + jl_get_ptls_states_init(); // for codegen return jl_tls_states_cb; }