Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GC safepoint and transition support #14190

Merged
merged 10 commits into from
Jan 5, 2016
14 changes: 14 additions & 0 deletions base/locks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ function lock!(l::TatasLock)
end
end
ccall(:jl_cpu_pause, Void, ())
# Temporary solution before we have gc transition support in codegen.
# This could mess up gc state when we add codegen support.
# Use these as a safe point
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
end
end

Expand Down Expand Up @@ -61,6 +66,11 @@ function lock!(l::RecursiveTatasLock)
end
end
ccall(:jl_cpu_pause, Void, ())
# Temporary solution before we have gc transition support in codegen.
# This could mess up gc state when we add codegen support.
# Use these as a safe point
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
end
end

Expand Down Expand Up @@ -116,7 +126,11 @@ function lock!(m::Mutex)
if m.ownertid == threadid()
return 0
end
# Temporary solution before we have gc transition support in codegen.
# This could mess up gc state when we add codegen support.
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
ccall(:uv_mutex_lock, Void, (Ptr{Void},), m.handle)
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
m.ownertid = threadid()
return 0
end
Expand Down
27 changes: 24 additions & 3 deletions doc/devdocs/debuggingtips.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Similarly, if you're debugging some of julia's internals (e.g.,

This is a good way to circumvent problems that arise from the order in which julia's output streams are initialized.

Julia's flisp interpreter uses ``value_t*`` objects; these can be displayed
Julia's flisp interpreter uses ``value_t`` objects; these can be displayed
with ``call fl_print(ios_stdout, obj)``.

Useful Julia variables for Inspecting
Expand Down Expand Up @@ -74,7 +74,7 @@ Another useful frame is ``to_function(jl_lambda_info_t *li, bool cstyle)``. The

#2 0x00007ffff7928bf7 in to_function (li=0x2812060, cstyle=false) at codegen.cpp:584
584 abort();
(gdb) p jl_(jl_uncompress_ast(li, li.ast))
(gdb) p jl_(jl_uncompress_ast(li, li->ast))

Inserting breakpoints upon certain conditions
---------------------------------------------
Expand All @@ -91,10 +91,31 @@ Calling a particular method

::

(gdb) break jl_apply_generic if strcmp(F->name->name, "method_to_break")==0
(gdb) break jl_apply_generic if strcmp((char*)(jl_symbol_name)(jl_gf_mtable(F)->name), "method_to_break")==0

Since this function is used for every call, you will make everything 1000x slower if you do this.

Dealing with signals
--------------------

Julia requires a few signal to function property. The profiler uses ``SIGUSR2``
for sampling and the garbage collector uses ``SIGSEGV`` for threads
synchronization. If you are debugging some code that uses the profiler or
multiple julia threads, you may want to let the debugger ignore these signals
since they can be triggered very often during normal operations. The command to
do this in GDB is (replace ``SIGSEGV`` with ``SIGUSRS`` or other signals you
want to ignore)::

(gdb) handle SIGSEGV noprint nostop pass

The corresponding LLDB command is (after the process is started)::

(lldb) pro hand -p true -s false -n false SIGSEGV

If you are debugging a segfault with threaded code, you can set a breakpoint on
``jl_critical_error`` (``sigdie_handler`` should also work on Linux and BSD) in
order to only catch the actual segfault rather than the GC synchronization points.

Debugging during julia's build process (bootstrap)
--------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion src/ast.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_lambda_info_t *lam);

static jl_value_t *scm_to_julia(value_t e, int expronly)
{
int en = jl_gc_enable(0);
int en = jl_gc_enable(0); // Might GC
jl_value_t *v;
JL_TRY {
v = scm_to_julia_(e, expronly);
Expand Down
3 changes: 3 additions & 0 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,9 @@ JL_DLLEXPORT void jl_enter_handler(jl_handler_t *eh)
JL_SIGATOMIC_BEGIN();
eh->prev = jl_current_task->eh;
eh->gcstack = jl_pgcstack;
#ifdef JULIA_ENABLE_THREADING
eh->gc_state = jl_get_ptls_states()->gc_state;
#endif
jl_current_task->eh = eh;
// TODO: this should really go after setjmp(). see comment in
// ctx_switch in task.c.
Expand Down
16 changes: 16 additions & 0 deletions src/debuginfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@ class JuliaJITEventListener: public JITEventListener
virtual void NotifyFunctionEmitted(const Function &F, void *Code,
size_t Size, const EmittedFunctionDetails &Details)
{
int8_t gc_state = jl_gc_safe_enter();
uv_rwlock_wrlock(&threadsafe);
jl_gc_safe_leave(gc_state);
#if defined(_OS_WINDOWS_)
create_PRUNTIME_FUNCTION((uint8_t*)Code, Size, F.getName(), (uint8_t*)Code, Size, NULL);
#endif
Expand All @@ -205,7 +207,9 @@ class JuliaJITEventListener: public JITEventListener

std::map<size_t, FuncInfo, revcomp>& getMap()
{
int8_t gc_state = jl_gc_safe_enter();
uv_rwlock_rdlock(&threadsafe);
jl_gc_safe_leave(gc_state);
return info;
}
#endif // ifndef USE_MCJIT
Expand All @@ -225,7 +229,9 @@ class JuliaJITEventListener: public JITEventListener
virtual void NotifyObjectEmitted(const ObjectImage &obj)
#endif
{
int8_t gc_state = jl_gc_safe_enter();
uv_rwlock_wrlock(&threadsafe);
jl_gc_safe_leave(gc_state);
#ifdef LLVM36
object::section_iterator Section = obj.section_begin();
object::section_iterator EndSection = obj.section_end();
Expand Down Expand Up @@ -458,7 +464,9 @@ class JuliaJITEventListener: public JITEventListener

std::map<size_t, ObjectInfo, revcomp>& getObjectMap()
{
int8_t gc_state = jl_gc_safe_enter();
uv_rwlock_rdlock(&threadsafe);
jl_gc_safe_leave(gc_state);
return objectmap;
}
#endif // USE_MCJIT
Expand All @@ -477,6 +485,8 @@ JL_DLLEXPORT void ORCNotifyObjectEmitted(JITEventListener *Listener,
extern "C"
char *jl_demangle(const char *name)
{
// This function is not allowed to reference any TLS variables since
// it can be called from an unmanaged thread on OSX.
const char *start = name + 6;
const char *end = name + strlen(name);
char *ret;
Expand Down Expand Up @@ -508,6 +518,8 @@ void lookup_pointer(DIContext *context, char **name, size_t *line,
char **inlinedat_file, size_t pointer,
int demangle, int *fromC)
{
// This function is not allowed to reference any TLS variables since
// it can be called from an unmanaged thread on OSX.
DILineInfo info, topinfo;
DIInliningInfo inlineinfo;
if (demangle && *name != NULL) {
Expand Down Expand Up @@ -629,6 +641,8 @@ void jl_getDylibFunctionInfo(char **name, char **filename, size_t *line,
char** inlinedat_file, size_t *inlinedat_line,
size_t pointer, int *fromC, int skipC, int skipInline)
{
// This function is not allowed to reference any TLS variables since
// it can be called from an unmanaged thread on OSX.
#ifdef _OS_WINDOWS_
IMAGEHLP_MODULE64 ModuleInfo;
BOOL isvalid;
Expand Down Expand Up @@ -838,6 +852,8 @@ void jl_getFunctionInfo(char **name, char **filename, size_t *line,
char **inlinedat_file, size_t *inlinedat_line,
size_t pointer, int *fromC, int skipC, int skipInline)
{
// This function is not allowed to reference any TLS variables since
// it can be called from an unmanaged thread on OSX.
*name = NULL;
*line = -1;
*filename = NULL;
Expand Down
6 changes: 3 additions & 3 deletions src/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ JL_DLLEXPORT jl_value_t *jl_ast_rettype(jl_lambda_info_t *li, jl_value_t *ast)
ios_mem(&src, 0);
ios_setbuf(&src, (char*)bytes->data, jl_array_len(bytes), 0);
src.size = jl_array_len(bytes);
int en = jl_gc_enable(0);
int en = jl_gc_enable(0); // Might GC
jl_value_t *rt = jl_deserialize_value(&src, NULL);
jl_gc_enable(en);
tree_literal_values = NULL;
Expand All @@ -1994,7 +1994,7 @@ JL_DLLEXPORT jl_value_t *jl_compress_ast(jl_lambda_info_t *li, jl_value_t *ast)
ios_mem(&dest, 0);
jl_array_t *last_tlv = tree_literal_values;
jl_module_t *last_tem = tree_enclosing_module;
int en = jl_gc_enable(0);
int en = jl_gc_enable(0); // Might GC

if (li->module->constant_table == NULL) {
li->module->constant_table = jl_alloc_cell_1d(0);
Expand Down Expand Up @@ -2038,7 +2038,7 @@ JL_DLLEXPORT jl_value_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_value_t *dat
ios_mem(&src, 0);
ios_setbuf(&src, (char*)bytes->data, jl_array_len(bytes), 0);
src.size = jl_array_len(bytes);
int en = jl_gc_enable(0);
int en = jl_gc_enable(0); // Might GC
(void)jl_deserialize_value(&src, NULL); // skip ret type
jl_value_t *v = jl_deserialize_value(&src, NULL);
jl_gc_enable(en);
Expand Down
Loading