Skip to content

Commit 6cc48dc

Browse files
committed
Merge pull request #14190 from JuliaLang/yyc/gc/safepoint
GC safepoint and transition support
2 parents 15cae86 + eed7fea commit 6cc48dc

22 files changed

+528
-90
lines changed

base/locks.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ function lock!(l::TatasLock)
2323
end
2424
end
2525
ccall(:jl_cpu_pause, Void, ())
26+
# Temporary solution before we have gc transition support in codegen.
27+
# This could mess up gc state when we add codegen support.
28+
# Use these as a safe point
29+
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
30+
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
2631
end
2732
end
2833

@@ -61,6 +66,11 @@ function lock!(l::RecursiveTatasLock)
6166
end
6267
end
6368
ccall(:jl_cpu_pause, Void, ())
69+
# Temporary solution before we have gc transition support in codegen.
70+
# This could mess up gc state when we add codegen support.
71+
# Use these as a safe point
72+
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
73+
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
6474
end
6575
end
6676

@@ -116,7 +126,11 @@ function lock!(m::Mutex)
116126
if m.ownertid == threadid()
117127
return 0
118128
end
129+
# Temporary solution before we have gc transition support in codegen.
130+
# This could mess up gc state when we add codegen support.
131+
gc_state = ccall(:jl_gc_safe_enter, Int8, ())
119132
ccall(:uv_mutex_lock, Void, (Ptr{Void},), m.handle)
133+
ccall(:jl_gc_safe_leave, Void, (Int8,), gc_state)
120134
m.ownertid = threadid()
121135
return 0
122136
end

doc/devdocs/debuggingtips.rst

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Similarly, if you're debugging some of julia's internals (e.g.,
2424

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

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

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

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

7979
Inserting breakpoints upon certain conditions
8080
---------------------------------------------
@@ -91,10 +91,31 @@ Calling a particular method
9191

9292
::
9393

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

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

98+
Dealing with signals
99+
--------------------
100+
101+
Julia requires a few signal to function property. The profiler uses ``SIGUSR2``
102+
for sampling and the garbage collector uses ``SIGSEGV`` for threads
103+
synchronization. If you are debugging some code that uses the profiler or
104+
multiple julia threads, you may want to let the debugger ignore these signals
105+
since they can be triggered very often during normal operations. The command to
106+
do this in GDB is (replace ``SIGSEGV`` with ``SIGUSRS`` or other signals you
107+
want to ignore)::
108+
109+
(gdb) handle SIGSEGV noprint nostop pass
110+
111+
The corresponding LLDB command is (after the process is started)::
112+
113+
(lldb) pro hand -p true -s false -n false SIGSEGV
114+
115+
If you are debugging a segfault with threaded code, you can set a breakpoint on
116+
``jl_critical_error`` (``sigdie_handler`` should also work on Linux and BSD) in
117+
order to only catch the actual segfault rather than the GC synchronization points.
118+
98119
Debugging during julia's build process (bootstrap)
99120
--------------------------------------------------
100121

src/ast.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ static jl_value_t *resolve_globals(jl_value_t *expr, jl_lambda_info_t *lam);
202202

203203
static jl_value_t *scm_to_julia(value_t e, int expronly)
204204
{
205-
int en = jl_gc_enable(0);
205+
int en = jl_gc_enable(0); // Might GC
206206
jl_value_t *v;
207207
JL_TRY {
208208
v = scm_to_julia_(e, expronly);

src/builtins.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,9 @@ JL_DLLEXPORT void jl_enter_handler(jl_handler_t *eh)
194194
JL_SIGATOMIC_BEGIN();
195195
eh->prev = jl_current_task->eh;
196196
eh->gcstack = jl_pgcstack;
197+
#ifdef JULIA_ENABLE_THREADING
198+
eh->gc_state = jl_get_ptls_states()->gc_state;
199+
#endif
197200
jl_current_task->eh = eh;
198201
// TODO: this should really go after setjmp(). see comment in
199202
// ctx_switch in task.c.

src/debuginfo.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,9 @@ class JuliaJITEventListener: public JITEventListener
194194
virtual void NotifyFunctionEmitted(const Function &F, void *Code,
195195
size_t Size, const EmittedFunctionDetails &Details)
196196
{
197+
int8_t gc_state = jl_gc_safe_enter();
197198
uv_rwlock_wrlock(&threadsafe);
199+
jl_gc_safe_leave(gc_state);
198200
#if defined(_OS_WINDOWS_)
199201
create_PRUNTIME_FUNCTION((uint8_t*)Code, Size, F.getName(), (uint8_t*)Code, Size, NULL);
200202
#endif
@@ -205,7 +207,9 @@ class JuliaJITEventListener: public JITEventListener
205207

206208
std::map<size_t, FuncInfo, revcomp>& getMap()
207209
{
210+
int8_t gc_state = jl_gc_safe_enter();
208211
uv_rwlock_rdlock(&threadsafe);
212+
jl_gc_safe_leave(gc_state);
209213
return info;
210214
}
211215
#endif // ifndef USE_MCJIT
@@ -225,7 +229,9 @@ class JuliaJITEventListener: public JITEventListener
225229
virtual void NotifyObjectEmitted(const ObjectImage &obj)
226230
#endif
227231
{
232+
int8_t gc_state = jl_gc_safe_enter();
228233
uv_rwlock_wrlock(&threadsafe);
234+
jl_gc_safe_leave(gc_state);
229235
#ifdef LLVM36
230236
object::section_iterator Section = obj.section_begin();
231237
object::section_iterator EndSection = obj.section_end();
@@ -458,7 +464,9 @@ class JuliaJITEventListener: public JITEventListener
458464

459465
std::map<size_t, ObjectInfo, revcomp>& getObjectMap()
460466
{
467+
int8_t gc_state = jl_gc_safe_enter();
461468
uv_rwlock_rdlock(&threadsafe);
469+
jl_gc_safe_leave(gc_state);
462470
return objectmap;
463471
}
464472
#endif // USE_MCJIT
@@ -477,6 +485,8 @@ JL_DLLEXPORT void ORCNotifyObjectEmitted(JITEventListener *Listener,
477485
extern "C"
478486
char *jl_demangle(const char *name)
479487
{
488+
// This function is not allowed to reference any TLS variables since
489+
// it can be called from an unmanaged thread on OSX.
480490
const char *start = name + 6;
481491
const char *end = name + strlen(name);
482492
char *ret;
@@ -508,6 +518,8 @@ void lookup_pointer(DIContext *context, char **name, size_t *line,
508518
char **inlinedat_file, size_t pointer,
509519
int demangle, int *fromC)
510520
{
521+
// This function is not allowed to reference any TLS variables since
522+
// it can be called from an unmanaged thread on OSX.
511523
DILineInfo info, topinfo;
512524
DIInliningInfo inlineinfo;
513525
if (demangle && *name != NULL) {
@@ -629,6 +641,8 @@ void jl_getDylibFunctionInfo(char **name, char **filename, size_t *line,
629641
char** inlinedat_file, size_t *inlinedat_line,
630642
size_t pointer, int *fromC, int skipC, int skipInline)
631643
{
644+
// This function is not allowed to reference any TLS variables since
645+
// it can be called from an unmanaged thread on OSX.
632646
#ifdef _OS_WINDOWS_
633647
IMAGEHLP_MODULE64 ModuleInfo;
634648
BOOL isvalid;
@@ -838,6 +852,8 @@ void jl_getFunctionInfo(char **name, char **filename, size_t *line,
838852
char **inlinedat_file, size_t *inlinedat_line,
839853
size_t pointer, int *fromC, int skipC, int skipInline)
840854
{
855+
// This function is not allowed to reference any TLS variables since
856+
// it can be called from an unmanaged thread on OSX.
841857
*name = NULL;
842858
*line = -1;
843859
*filename = NULL;

src/dump.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,7 +1974,7 @@ JL_DLLEXPORT jl_value_t *jl_ast_rettype(jl_lambda_info_t *li, jl_value_t *ast)
19741974
ios_mem(&src, 0);
19751975
ios_setbuf(&src, (char*)bytes->data, jl_array_len(bytes), 0);
19761976
src.size = jl_array_len(bytes);
1977-
int en = jl_gc_enable(0);
1977+
int en = jl_gc_enable(0); // Might GC
19781978
jl_value_t *rt = jl_deserialize_value(&src, NULL);
19791979
jl_gc_enable(en);
19801980
tree_literal_values = NULL;
@@ -1994,7 +1994,7 @@ JL_DLLEXPORT jl_value_t *jl_compress_ast(jl_lambda_info_t *li, jl_value_t *ast)
19941994
ios_mem(&dest, 0);
19951995
jl_array_t *last_tlv = tree_literal_values;
19961996
jl_module_t *last_tem = tree_enclosing_module;
1997-
int en = jl_gc_enable(0);
1997+
int en = jl_gc_enable(0); // Might GC
19981998

19991999
if (li->module->constant_table == NULL) {
20002000
li->module->constant_table = jl_alloc_cell_1d(0);
@@ -2038,7 +2038,7 @@ JL_DLLEXPORT jl_value_t *jl_uncompress_ast(jl_lambda_info_t *li, jl_value_t *dat
20382038
ios_mem(&src, 0);
20392039
ios_setbuf(&src, (char*)bytes->data, jl_array_len(bytes), 0);
20402040
src.size = jl_array_len(bytes);
2041-
int en = jl_gc_enable(0);
2041+
int en = jl_gc_enable(0); // Might GC
20422042
(void)jl_deserialize_value(&src, NULL); // skip ret type
20432043
jl_value_t *v = jl_deserialize_value(&src, NULL);
20442044
jl_gc_enable(en);

0 commit comments

Comments
 (0)