Skip to content

Commit 1f0437e

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm, profiler] Don't tear down sample buffers while there are pending signal handlers.
TEST=dartfuzz Bug: #42401 Bug: #52052 Bug: #60809 Change-Id: Ic61968fd312de6f84f2a064be18cbed8f2c68e5d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/456820 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Alexander Aprelev <[email protected]>
1 parent 8999635 commit 1f0437e

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

runtime/vm/thread_interrupter_android.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,60 @@ namespace dart {
2929

3030
DECLARE_FLAG(bool, trace_thread_interrupter);
3131

32+
class SignalState : public AllStatic {
33+
public:
34+
static bool Start() {
35+
uword expected = state_.load(std::memory_order_relaxed);
36+
uword desired;
37+
do {
38+
if (!Enabled::decode(expected)) return false;
39+
desired = Pending::update(Pending::decode(expected) + 1, expected);
40+
} while (!state_.compare_exchange_weak(expected, desired,
41+
std::memory_order_relaxed));
42+
return true;
43+
}
44+
45+
static void End() {
46+
uword expected = state_.load(std::memory_order_relaxed);
47+
uword desired;
48+
do {
49+
intptr_t pending = Pending::decode(expected);
50+
ASSERT(pending > 0);
51+
desired = Pending::update(pending - 1, expected);
52+
} while (!state_.compare_exchange_weak(expected, desired,
53+
std::memory_order_relaxed));
54+
}
55+
56+
static void Enable() {
57+
uword expected = state_.load(std::memory_order_relaxed);
58+
ASSERT(expected == (Enabled::encode(false) | Pending::encode(0)));
59+
uword desired = Enabled::encode(true) | Pending::encode(0);
60+
bool success = state_.compare_exchange_strong(expected, desired,
61+
std::memory_order_relaxed);
62+
ASSERT(success);
63+
}
64+
65+
static void Disable() {
66+
ASSERT(Enabled::decode(state_.load(std::memory_order_relaxed)));
67+
uword expected;
68+
uword desired = Enabled::encode(false) | Pending::encode(0);
69+
do {
70+
// Failed CAS updates [expected], recompute.
71+
expected = Enabled::encode(true) | Pending::encode(0);
72+
} while (!state_.compare_exchange_weak(expected, desired,
73+
std::memory_order_relaxed));
74+
}
75+
76+
private:
77+
using Enabled = BitField<uword, bool, 0, 1>;
78+
using Pending =
79+
BitField<uword, intptr_t, Enabled::kNextBit, kBitsPerWord - 1>;
80+
static std::atomic<uword> state_;
81+
};
82+
83+
std::atomic<uword> SignalState::state_ = {Enabled::encode(false) |
84+
Pending::encode(0)};
85+
3286
namespace {
3387
#if defined(USE_SIGNAL_HANDLER_TRAMPOLINE)
3488
extern "C" {
@@ -41,6 +95,9 @@ void ThreadInterruptSignalHandler(int signal, siginfo_t* info, void* context_) {
4195
if (thread == nullptr) {
4296
return;
4397
}
98+
if (!SignalState::Start()) {
99+
return;
100+
}
44101
ThreadInterruptScope signal_handler_scope;
45102
// Extract thread state.
46103
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
@@ -52,6 +109,7 @@ void ThreadInterruptSignalHandler(int signal, siginfo_t* info, void* context_) {
52109
its.dsp = SignalHandler::GetDartStackPointer(mcontext);
53110
its.lr = SignalHandler::GetLinkRegister(mcontext);
54111
Profiler::SampleThread(thread, its);
112+
SignalState::End();
55113
}
56114
#if defined(USE_SIGNAL_HANDLER_TRAMPOLINE)
57115
} // extern "C"
@@ -81,9 +139,11 @@ void ThreadInterrupter::InstallSignalHandler() {
81139
#else
82140
SignalHandler::Install(&ThreadInterruptSignalHandler);
83141
#endif
142+
SignalState::Enable();
84143
}
85144

86145
void ThreadInterrupter::RemoveSignalHandler() {
146+
SignalState::Disable();
87147
SignalHandler::Remove();
88148
}
89149

runtime/vm/thread_interrupter_linux.cc

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,60 @@ namespace dart {
1919

2020
DECLARE_FLAG(bool, trace_thread_interrupter);
2121

22+
class SignalState : public AllStatic {
23+
public:
24+
static bool Start() {
25+
uword expected = state_.load(std::memory_order_relaxed);
26+
uword desired;
27+
do {
28+
if (!Enabled::decode(expected)) return false;
29+
desired = Pending::update(Pending::decode(expected) + 1, expected);
30+
} while (!state_.compare_exchange_weak(expected, desired,
31+
std::memory_order_relaxed));
32+
return true;
33+
}
34+
35+
static void End() {
36+
uword expected = state_.load(std::memory_order_relaxed);
37+
uword desired;
38+
do {
39+
intptr_t pending = Pending::decode(expected);
40+
ASSERT(pending > 0);
41+
desired = Pending::update(pending - 1, expected);
42+
} while (!state_.compare_exchange_weak(expected, desired,
43+
std::memory_order_relaxed));
44+
}
45+
46+
static void Enable() {
47+
uword expected = state_.load(std::memory_order_relaxed);
48+
ASSERT(expected == (Enabled::encode(false) | Pending::encode(0)));
49+
uword desired = Enabled::encode(true) | Pending::encode(0);
50+
bool success = state_.compare_exchange_strong(expected, desired,
51+
std::memory_order_relaxed);
52+
ASSERT(success);
53+
}
54+
55+
static void Disable() {
56+
ASSERT(Enabled::decode(state_.load(std::memory_order_relaxed)));
57+
uword expected;
58+
uword desired = Enabled::encode(false) | Pending::encode(0);
59+
do {
60+
// Failed CAS updates [expected], recompute.
61+
expected = Enabled::encode(true) | Pending::encode(0);
62+
} while (!state_.compare_exchange_weak(expected, desired,
63+
std::memory_order_relaxed));
64+
}
65+
66+
private:
67+
using Enabled = BitField<uword, bool, 0, 1>;
68+
using Pending =
69+
BitField<uword, intptr_t, Enabled::kNextBit, kBitsPerWord - 1>;
70+
static std::atomic<uword> state_;
71+
};
72+
73+
std::atomic<uword> SignalState::state_ = {Enabled::encode(false) |
74+
Pending::encode(0)};
75+
2276
class ThreadInterrupterLinux : public AllStatic {
2377
public:
2478
static void ThreadInterruptSignalHandler(int signal,
@@ -31,6 +85,9 @@ class ThreadInterrupterLinux : public AllStatic {
3185
if (thread == nullptr) {
3286
return;
3387
}
88+
if (!SignalState::Start()) {
89+
return;
90+
}
3491
ThreadInterruptScope signal_handler_scope;
3592
// Extract thread state.
3693
ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
@@ -42,6 +99,7 @@ class ThreadInterrupterLinux : public AllStatic {
4299
its.dsp = SignalHandler::GetDartStackPointer(mcontext);
43100
its.lr = SignalHandler::GetLinkRegister(mcontext);
44101
Profiler::SampleThread(thread, its);
102+
SignalState::End();
45103
}
46104
};
47105

@@ -56,9 +114,11 @@ void ThreadInterrupter::InterruptThread(OSThread* thread) {
56114

57115
void ThreadInterrupter::InstallSignalHandler() {
58116
SignalHandler::Install(&ThreadInterrupterLinux::ThreadInterruptSignalHandler);
117+
SignalState::Enable();
59118
}
60119

61120
void ThreadInterrupter::RemoveSignalHandler() {
121+
SignalState::Disable();
62122
SignalHandler::Remove();
63123
}
64124

0 commit comments

Comments
 (0)