Skip to content

Commit d7ae95d

Browse files
Find potential deadlocks using tryLock in profiler shutdown
1 parent 3a493be commit d7ae95d

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

src/mutex.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ Mutex::Mutex() {
1313
pthread_mutex_init(&_mutex, &attr);
1414
}
1515

16+
bool Mutex::tryLock() {
17+
return pthread_mutex_trylock(&_mutex) == 0;
18+
}
19+
1620
void Mutex::lock() {
1721
pthread_mutex_lock(&_mutex);
1822
}

src/mutex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class Mutex {
1717
public:
1818
Mutex();
1919

20+
bool tryLock();
2021
void lock();
2122
void unlock();
2223
};

src/profiler.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static Instrument instrument;
6868

6969
static ProfilingWindow profiling_window;
7070

71+
static volatile bool _in_jfrsync = false;
7172

7273
struct MethodSample {
7374
u64 samples;
@@ -1211,7 +1212,9 @@ Error Profiler::start(Arguments& args, bool reset) {
12111212
switchLibraryTrap(true);
12121213

12131214
if (args._output == OUTPUT_JFR) {
1215+
_in_jfrsync = args._jfr_sync != NULL;
12141216
error = _jfr.start(args, reset);
1217+
_in_jfrsync = false;
12151218
if (error) {
12161219
uninstallTraps();
12171220
switchLibraryTrap(false);
@@ -2024,6 +2027,27 @@ Error Profiler::restart(Arguments& args) {
20242027
}
20252028

20262029
void Profiler::shutdown(Arguments& args) {
2030+
// Potential deadlock may happen between current thread & profiling thread due to usage of jfrsync
2031+
// To avoid that we use `tryLock` rather than `lock`
2032+
if (!_state_lock.tryLock()) {
2033+
volatile bool sleep = true;
2034+
2035+
// peek lock until acquired or _in_jfrsync is set
2036+
while (!_state_lock.tryLock() && !_in_jfrsync) {
2037+
OS::uninterruptibleSleep(10000000, &sleep); // 10ms
2038+
}
2039+
2040+
// retry to confirm if real deadlock
2041+
for (int i = 0; i < 10 && !_state_lock.tryLock() && _in_jfrsync; i++) {
2042+
OS::uninterruptibleSleep(10000000, &sleep);
2043+
}
2044+
}
2045+
2046+
// deadlock detected, skip stopping the profiler.
2047+
if (!_state_lock.tryLock() && _in_jfrsync) {
2048+
Log::warn("%s", "async-profiler deadlock detected during process shutdown, skipping the shutdown hooks");
2049+
return;
2050+
}
20272051
MutexLocker ml(_state_lock);
20282052

20292053
// The last chance to dump profile before VM terminates

0 commit comments

Comments
 (0)