Skip to content

Commit f4d13cf

Browse files
authored
manage stackwalk/profile lock correctly (#45549)
Previously we had the wrong number of them (it was not global) and it was in the wrong shared library (it was part of codegen instead of profiling). The profile_round_robin_thread_order buffer was not allocated on the thread that exclusively used it, so it sometimes could end up somewhat awkwardly (in incorrectly) shared between 2 threads.
1 parent e9783c7 commit f4d13cf

11 files changed

Lines changed: 155 additions & 131 deletions

src/codegen-stubs.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,6 @@ JL_DLLEXPORT size_t jl_jit_total_bytes_fallback(void)
6666
return 0;
6767
}
6868

69-
JL_DLLEXPORT void jl_lock_profile_fallback(void)
70-
{
71-
}
72-
73-
JL_DLLEXPORT void jl_unlock_profile_fallback(void)
74-
{
75-
}
76-
7769
JL_DLLEXPORT void *jl_create_native_fallback(jl_array_t *methods, LLVMOrcThreadSafeModuleRef llvmctxt, const jl_cgparams_t *cgparams, int _policy) UNAVAILABLE
7870

7971
JL_DLLEXPORT void jl_dump_compiles_fallback(void *s)

src/debug-registry.h

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ typedef struct {
1515
int64_t slide;
1616
} objfileentry_t;
1717

18-
1918
// Central registry for resolving function addresses to `jl_method_instance_t`s and
2019
// originating `ObjectFile`s (for the DWARF debug info).
2120
//
@@ -81,32 +80,6 @@ class JITDebugInfoRegistry
8180
~Locked() JL_NOTSAFEPOINT = default;
8281
};
8382

84-
template<typename datatype>
85-
struct jl_pthread_key_t {
86-
static_assert(std::is_trivially_default_constructible<datatype>::value, "Invalid datatype for pthread key!");
87-
static_assert(std::is_trivially_destructible<datatype>::value, "Expected datatype to be trivially destructible!");
88-
static_assert(sizeof(datatype) == sizeof(void*), "Expected datatype to be like a void*!");
89-
pthread_key_t key;
90-
91-
void init() JL_NOTSAFEPOINT {
92-
if (pthread_key_create(&key, NULL))
93-
jl_error("fatal: pthread_key_create failed");
94-
}
95-
96-
operator datatype() JL_NOTSAFEPOINT {
97-
return reinterpret_cast<datatype>(pthread_getspecific(key));
98-
}
99-
100-
jl_pthread_key_t &operator=(datatype val) JL_NOTSAFEPOINT {
101-
pthread_setspecific(key, reinterpret_cast<void*>(val));
102-
return *this;
103-
}
104-
105-
void destroy() JL_NOTSAFEPOINT {
106-
pthread_key_delete(key);
107-
}
108-
};
109-
11083
struct sysimg_info_t {
11184
uint64_t jl_sysimage_base;
11285
jl_sysimg_fptrs_t sysimg_fptrs;
@@ -159,16 +132,6 @@ class JITDebugInfoRegistry
159132
JITDebugInfoRegistry() JL_NOTSAFEPOINT;
160133
~JITDebugInfoRegistry() JL_NOTSAFEPOINT = default;
161134

162-
// Any function that acquires this lock must be either a unmanaged thread
163-
// or in the GC safe region and must NOT allocate anything through the GC
164-
// while holding this lock.
165-
// Certain functions in this file might be called from an unmanaged thread
166-
// and cannot have any interaction with the julia runtime
167-
// They also may be re-entrant, and operating while threads are paused, so we
168-
// separately manage the re-entrant count behavior for safety across platforms
169-
// Note that we cannot safely upgrade read->write
170-
uv_rwlock_t debuginfo_asyncsafe{};
171-
jl_pthread_key_t<uintptr_t> debuginfo_asyncsafe_held{};
172135
libc_frames_t libc_frames{};
173136

174137
void add_code_in_flight(llvm::StringRef name, jl_code_instance_t *codeinst, const llvm::DataLayout &DL) JL_NOTSAFEPOINT;

src/debuginfo.cpp

Lines changed: 18 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,6 @@ struct debug_link_info {
5252
uint32_t crc32;
5353
};
5454

55-
extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT;
56-
extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT;
57-
58-
template <typename T>
59-
static void jl_profile_atomic(T f);
60-
6155
#if (defined(_OS_LINUX_) || defined(_OS_FREEBSD_) || (defined(_OS_DARWIN_) && defined(LLVM_SHLIB)))
6256
extern "C" void __register_frame(void*);
6357
extern "C" void __deregister_frame(void*);
@@ -101,16 +95,16 @@ void JITDebugInfoRegistry::add_code_in_flight(StringRef name, jl_code_instance_t
10195

10296
jl_method_instance_t *JITDebugInfoRegistry::lookupLinfo(size_t pointer) JL_NOTSAFEPOINT
10397
{
104-
jl_lock_profile_impl();
98+
jl_lock_profile();
10599
auto region = linfomap.lower_bound(pointer);
106100
jl_method_instance_t *linfo = NULL;
107101
if (region != linfomap.end() && pointer < region->first + region->second.first)
108102
linfo = region->second.second;
109-
jl_unlock_profile_impl();
103+
jl_unlock_profile();
110104
return linfo;
111105
}
112106

113-
//Protected by debuginfo_asyncsafe
107+
//Protected by debuginfo_asyncsafe (profile) lock
114108
JITDebugInfoRegistry::objectmap_t &
115109
JITDebugInfoRegistry::getObjectMap() JL_NOTSAFEPOINT
116110
{
@@ -131,41 +125,21 @@ JITDebugInfoRegistry::get_objfile_map() JL_NOTSAFEPOINT {
131125
return *this->objfilemap;
132126
}
133127

134-
JITDebugInfoRegistry::JITDebugInfoRegistry() JL_NOTSAFEPOINT {
135-
uv_rwlock_init(&debuginfo_asyncsafe);
136-
debuginfo_asyncsafe_held.init();
137-
}
128+
JITDebugInfoRegistry::JITDebugInfoRegistry() JL_NOTSAFEPOINT { }
138129

139130
struct unw_table_entry
140131
{
141132
int32_t start_ip_offset;
142133
int32_t fde_offset;
143134
};
144135

145-
extern "C" JL_DLLEXPORT void jl_lock_profile_impl(void) JL_NOTSAFEPOINT
146-
{
147-
uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held;
148-
if (held++ == 0)
149-
uv_rwlock_rdlock(&getJITDebugRegistry().debuginfo_asyncsafe);
150-
getJITDebugRegistry().debuginfo_asyncsafe_held = held;
151-
}
152-
153-
extern "C" JL_DLLEXPORT void jl_unlock_profile_impl(void) JL_NOTSAFEPOINT
154-
{
155-
uintptr_t held = getJITDebugRegistry().debuginfo_asyncsafe_held;
156-
assert(held);
157-
if (--held == 0)
158-
uv_rwlock_rdunlock(&getJITDebugRegistry().debuginfo_asyncsafe);
159-
getJITDebugRegistry().debuginfo_asyncsafe_held = held;
160-
}
161-
162136
// some actions aren't signal (especially profiler) safe so we acquire a lock
163137
// around them to establish a mutual exclusion with unwinding from a signal
164138
template <typename T>
165139
static void jl_profile_atomic(T f)
166140
{
167-
assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held);
168-
uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe);
141+
assert(0 == jl_lock_profile_rd_held());
142+
jl_lock_profile_wr();
169143
#ifndef _OS_WINDOWS_
170144
sigset_t sset;
171145
sigset_t oset;
@@ -176,7 +150,7 @@ static void jl_profile_atomic(T f)
176150
#ifndef _OS_WINDOWS_
177151
pthread_sigmask(SIG_SETMASK, &oset, NULL);
178152
#endif
179-
uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe);
153+
jl_unlock_profile_wr();
180154
}
181155

182156

@@ -482,10 +456,10 @@ static int lookup_pointer(
482456

483457
// DWARFContext/DWARFUnit update some internal tables during these queries, so
484458
// a lock is needed.
485-
assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held);
486-
uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe);
459+
assert(0 == jl_lock_profile_rd_held());
460+
jl_lock_profile_wr();
487461
auto inlineInfo = context->getInliningInfoForAddress(makeAddress(Section, pointer + slide), infoSpec);
488-
uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe);
462+
jl_unlock_profile_wr();
489463

490464
int fromC = (*frames)[0].fromC;
491465
int n_frames = inlineInfo.getNumberOfFrames();
@@ -508,9 +482,9 @@ static int lookup_pointer(
508482
info = inlineInfo.getFrame(i);
509483
}
510484
else {
511-
uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe);
485+
jl_lock_profile_wr();
512486
info = context->getLineInfoForAddress(makeAddress(Section, pointer + slide), infoSpec);
513-
uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe);
487+
jl_unlock_profile_wr();
514488
}
515489

516490
jl_frame_t *frame = &(*frames)[i];
@@ -1197,8 +1171,9 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
11971171
object::SectionRef *Section, llvm::DIContext **context) JL_NOTSAFEPOINT
11981172
{
11991173
int found = 0;
1200-
assert(0 == getJITDebugRegistry().debuginfo_asyncsafe_held);
1201-
uv_rwlock_wrlock(&getJITDebugRegistry().debuginfo_asyncsafe);
1174+
assert(0 == jl_lock_profile_rd_held());
1175+
jl_lock_profile_wr();
1176+
12021177
if (symsize)
12031178
*symsize = 0;
12041179

@@ -1214,7 +1189,7 @@ int jl_DI_for_fptr(uint64_t fptr, uint64_t *symsize, int64_t *slide,
12141189
}
12151190
found = 1;
12161191
}
1217-
uv_rwlock_wrunlock(&getJITDebugRegistry().debuginfo_asyncsafe);
1192+
jl_unlock_profile_wr();
12181193
return found;
12191194
}
12201195

@@ -1613,13 +1588,13 @@ extern "C" JL_DLLEXPORT
16131588
uint64_t jl_getUnwindInfo_impl(uint64_t dwAddr)
16141589
{
16151590
// Might be called from unmanaged thread
1616-
jl_lock_profile_impl();
1591+
jl_lock_profile();
16171592
auto &objmap = getJITDebugRegistry().getObjectMap();
16181593
auto it = objmap.lower_bound(dwAddr);
16191594
uint64_t ipstart = 0; // ip of the start of the section (if found)
16201595
if (it != objmap.end() && dwAddr < it->first + it->second.SectionSize) {
16211596
ipstart = (uint64_t)(uintptr_t)(*it).first;
16221597
}
1623-
jl_unlock_profile_impl();
1598+
jl_unlock_profile();
16241599
return ipstart;
16251600
}

src/init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,7 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel)
706706
}
707707

708708
jl_init_rand();
709+
jl_init_profile_lock();
709710
jl_init_runtime_ccall();
710711
jl_init_tasks();
711712
jl_init_threading();

src/jl_exported_data.inc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,10 +124,12 @@
124124
XX(jl_vecelement_typename) \
125125
XX(jl_voidpointer_type) \
126126
XX(jl_void_type) \
127-
XX(jl_weakref_type)
127+
XX(jl_weakref_type) \
128128

129129
// Data symbols that are defined inside the public libjulia
130130
#define JL_EXPORTED_DATA_SYMBOLS(XX) \
131131
XX(jl_n_threadpools, int) \
132132
XX(jl_n_threads, int) \
133-
XX(jl_options, jl_options_t)
133+
XX(jl_options, jl_options_t) \
134+
135+
// end of file

src/jl_exported_funcs.inc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -515,10 +515,10 @@
515515
XX(jl_vexceptionf) \
516516
XX(jl_vprintf) \
517517
XX(jl_wakeup_thread) \
518-
XX(jl_yield)
518+
XX(jl_yield) \
519519

520520
#define JL_RUNTIME_EXPORTED_FUNCS_WIN(XX) \
521-
XX(jl_setjmp)
521+
XX(jl_setjmp) \
522522

523523
// use YY instead of XX to avoid jl -> ijl renaming in libjulia-codegen
524524
#define JL_CODEGEN_EXPORTED_FUNCS(YY) \
@@ -542,8 +542,6 @@
542542
YY(jl_compile_extern_c) \
543543
YY(jl_teardown_codegen) \
544544
YY(jl_jit_total_bytes) \
545-
YY(jl_lock_profile) \
546-
YY(jl_unlock_profile) \
547545
YY(jl_create_native) \
548546
YY(jl_dump_compiles) \
549547
YY(jl_dump_emitted_mi_name) \
@@ -568,4 +566,6 @@
568566
YY(LLVMExtraAddRemoveNIPass) \
569567
YY(LLVMExtraAddGCInvariantVerifierPass) \
570568
YY(LLVMExtraAddDemoteFloat16Pass) \
571-
YY(LLVMExtraAddCPUFeaturesPass)
569+
YY(LLVMExtraAddCPUFeaturesPass) \
570+
571+
// end of file

src/julia_internal.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ JL_DLLEXPORT void jl_set_peek_cond(uintptr_t);
135135
JL_DLLEXPORT double jl_get_profile_peek_duration(void);
136136
JL_DLLEXPORT void jl_set_profile_peek_duration(double);
137137

138+
JL_DLLEXPORT void jl_init_profile_lock(void);
139+
JL_DLLEXPORT uintptr_t jl_lock_profile_rd_held(void) JL_NOTSAFEPOINT;
140+
JL_DLLEXPORT void jl_lock_profile(void) JL_NOTSAFEPOINT;
141+
JL_DLLEXPORT void jl_unlock_profile(void) JL_NOTSAFEPOINT;
142+
JL_DLLEXPORT void jl_lock_profile_wr(void) JL_NOTSAFEPOINT;
143+
JL_DLLEXPORT void jl_unlock_profile_wr(void) JL_NOTSAFEPOINT;
144+
138145
// number of cycles since power-on
139146
static inline uint64_t cycleclock(void) JL_NOTSAFEPOINT
140147
{
@@ -832,6 +839,10 @@ typedef jl_gcframe_t ***(*jl_pgcstack_key_t)(void) JL_NOTSAFEPOINT;
832839
#endif
833840
JL_DLLEXPORT void jl_pgcstack_getkey(jl_get_pgcstack_func **f, jl_pgcstack_key_t *k);
834841

842+
#if !defined(_OS_WINDOWS_) && !defined(__APPLE__) && !defined(JL_DISABLE_LIBUNWIND)
843+
extern pthread_mutex_t in_signal_lock;
844+
#endif
845+
835846
#if !defined(__clang_gcanalyzer__) && !defined(_OS_DARWIN_)
836847
static inline void jl_set_gc_and_wait(void)
837848
{

src/julia_threads.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,7 @@ typedef struct {
201201
} jl_gc_mark_cache_t;
202202

203203
struct _jl_bt_element_t;
204+
204205
// This includes all the thread local states we care about for a thread.
205206
// Changes to TLS field types must be reflected in codegen.
206207
#define JL_MAX_BT_SIZE 80000

0 commit comments

Comments
 (0)