DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Implementation

Mercurial (92d7d0e03e42)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_recordreplay_ProcessRewind_h
#define mozilla_recordreplay_ProcessRewind_h

#include "mozilla/RecordReplay.h"

#include <functional>

namespace mozilla {
namespace recordreplay {

// This file is responsible for keeping track of and managing the current point
// of execution when replaying an execution, and in allowing the process to
// rewind its state to an earlier point of execution.

///////////////////////////////////////////////////////////////////////////////
// Checkpoints Overview.
//
// Checkpoints are reached periodically by the main thread of a recording or
// replaying process. Checkpoints must be reached at consistent points between
// different executions of the recording. Currently they are taken after XPCOM
// initialization and every time compositor updates are performed. Each
// checkpoint has an ID, which monotonically increases during the execution.
// Checkpoints form a basis for identifying a particular point in execution,
// and in allowing replaying processes to rewind themselves.
//
// A subset of checkpoints are saved: the contents of each thread's stack is
// copied, along with enough information to restore the contents of heap memory
// at the checkpoint.
//
// Saved checkpoints are in part represented as diffs vs the following
// saved checkpoint. This requires some different handling for the most recent
// saved checkpoint (whose diff has not been computed) and earlier saved
// checkpoints. See MemorySnapshot.h and Thread.h for more on how saved
// checkpoints are represented.
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Controlling a Replaying Process.
//
// 1. While performing the replay, execution proceeds until the main thread
//    hits either a breakpoint or a checkpoint.
//
// 2. The main thread then calls a hook (JS::replay::hooks.hitBreakpointReplay
//    or gAfterCheckpointHook), which may decide to pause the main thread and
//    give it a callback to invoke using PauseMainThreadAndInvokeCallback.
//
// 3. Now that the main thread is paused, the replay message loop thread
//    (see ChildIPC.h) can give it additional callbacks to invoke using
//    PauseMainThreadAndInvokeCallback.
//
// 4. These callbacks can inspect the paused state, diverge from the recording
//    by calling DivergeFromRecording, and eventually can unpause the main
//    thread and allow execution to resume by calling ResumeExecution
//    (if DivergeFromRecording was not called) or RestoreCheckpointAndResume.
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Recording Divergence.
//
// Callbacks invoked while debugging (during step 3 of the above comment) might
// try to interact with the system, triggering thread events and attempting to
// replay behaviors that never occurred while recording.
//
// To allow these callbacks the freedom to operate without bringing down the
// entire replay, the DivergeFromRecording API is provided; see RecordReplay.h
// After this is called, some thread events will happen as if events were
// passed through, but other events that require interacting with the system
// will trigger an unhandled divergence from the recording via
// EnsureNotDivergedFromRecording, causing the process to rewind to the most
// recent saved checkpoint. The debugger will recognize this rewind and play
// back in a way that restores the state when DivergeFromRecording() was
// called, but without performing the later operation that triggered the
// rewind.
///////////////////////////////////////////////////////////////////////////////

// Special IDs for normal checkpoints.
static const size_t InvalidCheckpointId = 0;
static const size_t FirstCheckpointId = 1;

// Initialize state needed for rewinding.
void InitializeRewindState();

// Set whether this process should save a particular checkpoint.
void SetSaveCheckpoint(size_t aCheckpoint, bool aSave);

// Invoke a callback on the main thread, and pause it until ResumeExecution or
// RestoreCheckpointAndResume are called. When the main thread is not paused,
// this must be called on the main thread itself. When the main thread is
// already paused, this may be called from any thread.
void PauseMainThreadAndInvokeCallback(const std::function<void()>& aCallback);

// Return whether the main thread should be paused. This does not necessarily
// mean it is paused, but it will pause at the earliest opportunity.
bool MainThreadShouldPause();

// Pause the current main thread and service any callbacks until the thread no
// longer needs to pause.
void PauseMainThreadAndServiceCallbacks();

// Return whether any checkpoints have been saved.
bool HasSavedAnyCheckpoint();

// Return whether a specific checkpoint has been saved.
bool HasSavedCheckpoint(size_t aCheckpoint);

// Get the ID of the most recently encountered checkpoint.
size_t GetLastCheckpoint();

// Get the ID of the most recent saved checkpoint.
size_t GetLastSavedCheckpoint();

// When paused at a breakpoint or at a checkpoint, restore a checkpoint that
// was saved earlier and resume execution.
void RestoreCheckpointAndResume(size_t aCheckpoint);

// When paused at a breakpoint or at a checkpoint, unpause and proceed with
// execution.
void ResumeExecution();

// Allow execution after this point to diverge from the recording. Execution
// will remain diverged until an earlier checkpoint is restored.
//
// If an unhandled divergence occurs (see the 'Recording Divergence' comment
// in ProcessRewind.h) then the process rewinds to the most recent saved
// checkpoint.
void DivergeFromRecording();

// After a call to DivergeFromRecording(), this may be called to prevent future
// unhandled divergence from causing earlier checkpoints to be restored
// (the process will immediately crash instead). This state lasts until a new
// call to DivergeFromRecording, or to an explicit restore of an earlier
// checkpoint.
void DisallowUnhandledDivergeFromRecording();

// Make sure that execution has not diverged from the recording after a call to
// DivergeFromRecording, by rewinding to the last saved checkpoint if so.
void EnsureNotDivergedFromRecording();

// Note a checkpoint at the current execution position. This checkpoint will be
// saved if it was instructed to do so via a manifest. This method returns true
// if the checkpoint was just saved, and false if it was just restored.
bool NewCheckpoint();

}  // namespace recordreplay
}  // namespace mozilla

#endif  // mozilla_recordreplay_ProcessRewind_h