mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-28 23:31:56 +00:00
Bug 1488808 Part 10 - Notify the record/replay system when a message pump thread blocks after diverging from the recording, r=froydnj.
--HG-- extra : rebase_source : c82088f0903b618caee3b0366a8c681ff6f445a1
This commit is contained in:
parent
fc6a34c667
commit
3c4231fd5b
@ -60,6 +60,19 @@ void MessagePumpDefault::Run(Delegate* delegate) {
|
||||
AUTO_PROFILER_LABEL("MessagePumpDefault::Run:Wait", IDLE);
|
||||
{
|
||||
AUTO_PROFILER_THREAD_SLEEP;
|
||||
// Some threads operating a message pump (i.e. the compositor thread)
|
||||
// can diverge from Web Replay recordings, after which the thread needs
|
||||
// to be explicitly notified in order to coordinate with the
|
||||
// record/replay checkpoint system.
|
||||
if (mozilla::recordreplay::IsRecordingOrReplaying()) {
|
||||
// Workaround static analysis. Message pumps for which the lambda
|
||||
// below might be called will not be destroyed.
|
||||
void* thiz = this;
|
||||
|
||||
mozilla::recordreplay::MaybeWaitForCheckpointSave();
|
||||
mozilla::recordreplay::NotifyUnrecordedWait([=]() { ((MessagePumpDefault*)thiz)->ScheduleWork(); },
|
||||
/* aOnlyWhenDiverged = */ true);
|
||||
}
|
||||
event_.Wait();
|
||||
}
|
||||
} else {
|
||||
|
@ -162,7 +162,8 @@ MaybeWaitForRecordReplayCheckpointSave(AutoLockHelperThreadState& locked)
|
||||
|
||||
// Now that we are holding the helper thread state lock again,
|
||||
// notify the record/replay system that we might block soon.
|
||||
mozilla::recordreplay::NotifyUnrecordedWait(HelperThread::WakeupAll);
|
||||
mozilla::recordreplay::NotifyUnrecordedWait(HelperThread::WakeupAll,
|
||||
/* aOnlyWhenDiverged = */ false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,7 +51,8 @@ namespace recordreplay {
|
||||
Macro(InternalRecordReplayBytes, \
|
||||
(void* aData, size_t aSize), (aData, aSize)) \
|
||||
Macro(NotifyUnrecordedWait, \
|
||||
(const std::function<void()>& aCallback), (aCallback)) \
|
||||
(const std::function<void()>& aCallback, bool aOnlyWhenDiverged), \
|
||||
(aCallback, aOnlyWhenDiverged)) \
|
||||
Macro(MaybeWaitForCheckpointSave, (), ()) \
|
||||
Macro(InternalInvalidateRecording, (const char* aWhy), (aWhy)) \
|
||||
Macro(InternalDestroyPLDHashTableCallbacks, \
|
||||
|
@ -258,12 +258,16 @@ static inline bool HasDivergedFromRecording();
|
||||
// The callback passed to NotifyUnrecordedWait will be invoked at most once
|
||||
// by the main thread whenever the main thread is waiting for other threads to
|
||||
// become idle, and at most once after the call to NotifyUnrecordedWait if the
|
||||
// main thread is already waiting for other threads to become idle.
|
||||
// main thread is already waiting for other threads to become idle. If
|
||||
// aOnlyWhenDiverged is specified, the callback will only be invoked if the
|
||||
// thread has diverged from the recording (causing all resources to be treated
|
||||
// as unrecorded).
|
||||
//
|
||||
// The callback should poke the thread so that it is no longer blocked on the
|
||||
// resource. The thread must call MaybeWaitForCheckpointSave before blocking
|
||||
// again.
|
||||
MFBT_API void NotifyUnrecordedWait(const std::function<void()>& aCallback);
|
||||
MFBT_API void NotifyUnrecordedWait(const std::function<void()>& aCallback,
|
||||
bool aOnlyWhenDiverged);
|
||||
MFBT_API void MaybeWaitForCheckpointSave();
|
||||
|
||||
// API for debugging inconsistent behavior between recording and replay.
|
||||
|
@ -389,7 +389,15 @@ Thread::WaitForIdleThreads()
|
||||
Thread* thread = GetById(i);
|
||||
if (!thread->mIdle) {
|
||||
done = false;
|
||||
if (thread->mUnrecordedWaitCallback && !thread->mUnrecordedWaitNotified) {
|
||||
|
||||
// Check if there is a callback we can invoke to get this thread to
|
||||
// make progress. The mUnrecordedWaitOnlyWhenDiverged flag is used to
|
||||
// avoid perturbing the behavior of threads that may or may not be
|
||||
// waiting on an unrecorded resource, depending on whether they have
|
||||
// diverged from the recording yet.
|
||||
if (thread->mUnrecordedWaitCallback && !thread->mUnrecordedWaitNotified &&
|
||||
(!thread->mUnrecordedWaitOnlyWhenDiverged ||
|
||||
thread->WillDivergeFromRecordingSoon())) {
|
||||
// Set this flag before releasing the idle lock. Otherwise it's
|
||||
// possible the thread could call NotifyUnrecordedWait while we
|
||||
// aren't holding the lock, and we would set the flag afterwards
|
||||
@ -397,10 +405,11 @@ Thread::WaitForIdleThreads()
|
||||
thread->mUnrecordedWaitNotified = true;
|
||||
|
||||
// Release the idle lock here to avoid any risk of deadlock.
|
||||
std::function<void()> callback = thread->mUnrecordedWaitCallback;
|
||||
{
|
||||
MonitorAutoUnlock unlock(*gMonitor);
|
||||
AutoPassThroughThreadEvents pt;
|
||||
thread->mUnrecordedWaitCallback();
|
||||
callback();
|
||||
}
|
||||
|
||||
// Releasing the global lock means that we need to start over
|
||||
@ -438,7 +447,7 @@ Thread::ResumeIdleThreads()
|
||||
}
|
||||
|
||||
void
|
||||
Thread::NotifyUnrecordedWait(const std::function<void()>& aCallback)
|
||||
Thread::NotifyUnrecordedWait(const std::function<void()>& aCallback, bool aOnlyWhenDiverged)
|
||||
{
|
||||
MonitorAutoLock lock(*gMonitor);
|
||||
if (mUnrecordedWaitCallback) {
|
||||
@ -451,6 +460,7 @@ Thread::NotifyUnrecordedWait(const std::function<void()>& aCallback)
|
||||
}
|
||||
|
||||
mUnrecordedWaitCallback = aCallback;
|
||||
mUnrecordedWaitOnlyWhenDiverged = aOnlyWhenDiverged;
|
||||
|
||||
// The main thread might be able to make progress now by calling the routine
|
||||
// if it is waiting for idle replay threads.
|
||||
@ -472,9 +482,10 @@ Thread::MaybeWaitForCheckpointSave()
|
||||
extern "C" {
|
||||
|
||||
MOZ_EXPORT void
|
||||
RecordReplayInterface_NotifyUnrecordedWait(const std::function<void()>& aCallback)
|
||||
RecordReplayInterface_NotifyUnrecordedWait(const std::function<void()>& aCallback,
|
||||
bool aOnlyWhenDiverged)
|
||||
{
|
||||
Thread::Current()->NotifyUnrecordedWait(aCallback);
|
||||
Thread::Current()->NotifyUnrecordedWait(aCallback, aOnlyWhenDiverged);
|
||||
}
|
||||
|
||||
MOZ_EXPORT void
|
||||
|
@ -134,6 +134,7 @@ private:
|
||||
// and whether the callback has been invoked yet while the main thread is
|
||||
// waiting for threads to become idle. Protected by the thread monitor.
|
||||
std::function<void()> mUnrecordedWaitCallback;
|
||||
bool mUnrecordedWaitOnlyWhenDiverged;
|
||||
bool mUnrecordedWaitNotified;
|
||||
|
||||
public:
|
||||
@ -277,7 +278,8 @@ public:
|
||||
static void WaitForeverNoIdle();
|
||||
|
||||
// See RecordReplay.h.
|
||||
void NotifyUnrecordedWait(const std::function<void()>& aCallback);
|
||||
void NotifyUnrecordedWait(const std::function<void()>& aCallback,
|
||||
bool aOnlyWhenDiverged);
|
||||
static void MaybeWaitForCheckpointSave();
|
||||
|
||||
// Wait for all other threads to enter the idle state necessary for saving
|
||||
|
Loading…
Reference in New Issue
Block a user