зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1722261 - Remove data from RegisteredThread, only keep pass-through methods to the ThreadRegistrationData - r=canaltinova
Now {,Racy}RegisteredThread don't contain any data, but provide the same API that goes through ThreadRegistration. Until they are removed, {,Racy}RegisteredThread are given private access to ThreadRegistration{,Data} for easier access. This means that we can now change uses of RegisteredThread to use ThreadRegistration directly instead, and the data will be the same through either APIs. Also, RacyRegisteredThread::ThreadId() was unused so it can be removed. Differential Revision: https://phabricator.services.mozilla.com/D121847
This commit is contained in:
Родитель
ec135fdda7
Коммит
a544395950
|
@ -11,104 +11,23 @@
|
|||
#include "js/ProfilingStack.h"
|
||||
#include "js/TraceLoggerAPI.h"
|
||||
|
||||
// This is a simplified version of profiler_add_marker that can be easily passed
|
||||
// into the JS engine.
|
||||
static void profiler_add_js_marker(const char* aMarkerName,
|
||||
const char* aMarkerText) {
|
||||
PROFILER_MARKER_TEXT(
|
||||
mozilla::ProfilerString8View::WrapNullTerminatedString(aMarkerName), JS,
|
||||
{}, mozilla::ProfilerString8View::WrapNullTerminatedString(aMarkerText));
|
||||
}
|
||||
|
||||
static void profiler_add_js_allocation_marker(JS::RecordAllocationInfo&& info) {
|
||||
if (!profiler_can_accept_markers()) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct JsAllocationMarker {
|
||||
static constexpr mozilla::Span<const char> MarkerTypeName() {
|
||||
return mozilla::MakeStringSpan("JS allocation");
|
||||
}
|
||||
static void StreamJSONMarkerData(
|
||||
mozilla::baseprofiler::SpliceableJSONWriter& aWriter,
|
||||
const mozilla::ProfilerString16View& aTypeName,
|
||||
const mozilla::ProfilerString8View& aClassName,
|
||||
const mozilla::ProfilerString16View& aDescriptiveTypeName,
|
||||
const mozilla::ProfilerString8View& aCoarseType, uint64_t aSize,
|
||||
bool aInNursery) {
|
||||
if (aClassName.Length() != 0) {
|
||||
aWriter.StringProperty("className", aClassName);
|
||||
}
|
||||
if (aTypeName.Length() != 0) {
|
||||
aWriter.StringProperty(
|
||||
"typeName",
|
||||
NS_ConvertUTF16toUTF8(aTypeName.Data(), aTypeName.Length()));
|
||||
}
|
||||
if (aDescriptiveTypeName.Length() != 0) {
|
||||
aWriter.StringProperty(
|
||||
"descriptiveTypeName",
|
||||
NS_ConvertUTF16toUTF8(aDescriptiveTypeName.Data(),
|
||||
aDescriptiveTypeName.Length()));
|
||||
}
|
||||
aWriter.StringProperty("coarseType", aCoarseType);
|
||||
aWriter.IntProperty("size", aSize);
|
||||
aWriter.BoolProperty("inNursery", aInNursery);
|
||||
}
|
||||
static mozilla::MarkerSchema MarkerTypeDisplay() {
|
||||
return mozilla::MarkerSchema::SpecialFrontendLocation{};
|
||||
}
|
||||
};
|
||||
|
||||
profiler_add_marker(
|
||||
"JS allocation", geckoprofiler::category::JS,
|
||||
mozilla::MarkerStack::Capture(), JsAllocationMarker{},
|
||||
mozilla::ProfilerString16View::WrapNullTerminatedString(info.typeName),
|
||||
mozilla::ProfilerString8View::WrapNullTerminatedString(info.className),
|
||||
mozilla::ProfilerString16View::WrapNullTerminatedString(
|
||||
info.descriptiveTypeName),
|
||||
mozilla::ProfilerString8View::WrapNullTerminatedString(info.coarseType),
|
||||
info.size, info.inNursery);
|
||||
}
|
||||
|
||||
RacyRegisteredThread::RacyRegisteredThread(ProfilerThreadId aThreadId)
|
||||
: mProfilingStack([]() -> class ProfilingStack& {
|
||||
using namespace mozilla::profiler;
|
||||
class ProfilingStack* profilingStack =
|
||||
ThreadRegistration::WithOnThreadRefOr(
|
||||
[](ThreadRegistration::OnThreadRef aThread) {
|
||||
return &aThread.UnlockedConstReaderAndAtomicRWRef()
|
||||
.ProfilingStackRef();
|
||||
},
|
||||
nullptr);
|
||||
MOZ_RELEASE_ASSERT(profilingStack);
|
||||
return *profilingStack;
|
||||
}()),
|
||||
mThreadId(aThreadId),
|
||||
mSleep(AWAKE),
|
||||
mIsBeingProfiled(false) {
|
||||
RacyRegisteredThread::RacyRegisteredThread(
|
||||
mozilla::profiler::ThreadRegistration& aThreadRegistration,
|
||||
ProfilerThreadId aThreadId)
|
||||
: mThreadRegistration(aThreadRegistration) {
|
||||
MOZ_COUNT_CTOR(RacyRegisteredThread);
|
||||
}
|
||||
|
||||
RegisteredThread::RegisteredThread(ThreadInfo* aInfo, nsIThread* aThread,
|
||||
void* aStackTop)
|
||||
: mRacyRegisteredThread(aInfo->ThreadId()),
|
||||
RegisteredThread::RegisteredThread(
|
||||
mozilla::profiler::ThreadRegistration& aThreadRegistration,
|
||||
ThreadInfo* aInfo, nsIThread* aThread, void* aStackTop)
|
||||
: mRacyRegisteredThread(aThreadRegistration, aInfo->ThreadId()),
|
||||
mPlatformData(AllocPlatformData(aInfo->ThreadId())),
|
||||
mStackTop(aStackTop),
|
||||
mThreadInfo(aInfo),
|
||||
mThread(aThread),
|
||||
mContext(nullptr),
|
||||
mJSSampling(INACTIVE),
|
||||
mJSFlags(0) {
|
||||
mThreadInfo(aInfo) {
|
||||
MOZ_COUNT_CTOR(RegisteredThread);
|
||||
|
||||
// NOTE: aThread can be null for the first thread, before the ThreadManager
|
||||
// is initialized.
|
||||
|
||||
// We don't have to guess on mac
|
||||
#if defined(GP_OS_darwin)
|
||||
pthread_t self = pthread_self();
|
||||
mStackTop = pthread_get_stackaddr_np(self);
|
||||
#endif
|
||||
}
|
||||
|
||||
RegisteredThread::~RegisteredThread() { MOZ_COUNT_DTOR(RegisteredThread); }
|
||||
|
@ -130,70 +49,14 @@ size_t RegisteredThread::SizeOfIncludingThis(
|
|||
void RegisteredThread::GetRunningEventDelay(const mozilla::TimeStamp& aNow,
|
||||
mozilla::TimeDuration& aDelay,
|
||||
mozilla::TimeDuration& aRunning) {
|
||||
if (mThread) { // can be null right at the start of a process
|
||||
mozilla::TimeStamp start;
|
||||
mThread->GetRunningEventDelay(&aDelay, &start);
|
||||
if (!start.IsNull()) {
|
||||
// Note: the timestamp used here will be from when we started to
|
||||
// suspend and sample the thread; which is also the timestamp
|
||||
// associated with the sample.
|
||||
aRunning = aNow - start;
|
||||
return;
|
||||
}
|
||||
}
|
||||
aDelay = mozilla::TimeDuration();
|
||||
aRunning = mozilla::TimeDuration();
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.GetRunningEventDelay(
|
||||
aNow, aDelay, aRunning);
|
||||
}
|
||||
|
||||
void RegisteredThread::SetJSContext(JSContext* aContext) {
|
||||
// This function runs on-thread.
|
||||
|
||||
MOZ_ASSERT(aContext && !mContext);
|
||||
|
||||
mContext = aContext;
|
||||
|
||||
// We give the JS engine a non-owning reference to the ProfilingStack. It's
|
||||
// important that the JS engine doesn't touch this once the thread dies.
|
||||
js::SetContextProfilingStack(aContext,
|
||||
&RacyRegisteredThread().ProfilingStack());
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.SetJSContext(aContext);
|
||||
}
|
||||
|
||||
void RegisteredThread::PollJSSampling() {
|
||||
// This function runs on-thread.
|
||||
|
||||
// We can't start/stop profiling until we have the thread's JSContext.
|
||||
if (mContext) {
|
||||
// It is possible for mJSSampling to go through the following sequences.
|
||||
//
|
||||
// - INACTIVE, ACTIVE_REQUESTED, INACTIVE_REQUESTED, INACTIVE
|
||||
//
|
||||
// - ACTIVE, INACTIVE_REQUESTED, ACTIVE_REQUESTED, ACTIVE
|
||||
//
|
||||
// Therefore, the if and else branches here aren't always interleaved.
|
||||
// This is ok because the JS engine can handle that.
|
||||
//
|
||||
if (mJSSampling == ACTIVE_REQUESTED) {
|
||||
mJSSampling = ACTIVE;
|
||||
js::EnableContextProfilingStack(mContext, true);
|
||||
if (JSTracerEnabled()) {
|
||||
JS::StartTraceLogger(mContext);
|
||||
}
|
||||
if (JSAllocationsEnabled()) {
|
||||
// TODO - This probability should not be hardcoded. See Bug 1547284.
|
||||
JS::EnableRecordingAllocations(mContext,
|
||||
profiler_add_js_allocation_marker, 0.01);
|
||||
}
|
||||
js::RegisterContextProfilingEventMarker(mContext, profiler_add_js_marker);
|
||||
|
||||
} else if (mJSSampling == INACTIVE_REQUESTED) {
|
||||
mJSSampling = INACTIVE;
|
||||
js::EnableContextProfilingStack(mContext, false);
|
||||
if (JSTracerEnabled()) {
|
||||
JS::StopTraceLogger(mContext);
|
||||
}
|
||||
if (JSAllocationsEnabled()) {
|
||||
JS::DisableRecordingAllocations(mContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.PollJSSampling();
|
||||
}
|
||||
|
|
|
@ -25,109 +25,49 @@ class ProfilingStack;
|
|||
//
|
||||
class RacyRegisteredThread final {
|
||||
public:
|
||||
explicit RacyRegisteredThread(ProfilerThreadId aThreadId);
|
||||
explicit RacyRegisteredThread(
|
||||
mozilla::profiler::ThreadRegistration& aThreadRegistration,
|
||||
ProfilerThreadId aThreadId);
|
||||
|
||||
MOZ_COUNTED_DTOR(RacyRegisteredThread)
|
||||
|
||||
void SetIsBeingProfiled(bool aIsBeingProfiled) {
|
||||
mIsBeingProfiled = aIsBeingProfiled;
|
||||
mThreadRegistration.mData.mIsBeingProfiled = aIsBeingProfiled;
|
||||
}
|
||||
|
||||
bool IsBeingProfiled() const { return mIsBeingProfiled; }
|
||||
bool IsBeingProfiled() const {
|
||||
return mThreadRegistration.mData.mIsBeingProfiled;
|
||||
}
|
||||
|
||||
// This is called on every profiler restart. Put things that should happen at
|
||||
// that time here.
|
||||
void ReinitializeOnResume() {
|
||||
// This is needed to cause an initial sample to be taken from sleeping
|
||||
// threads that had been observed prior to the profiler stopping and
|
||||
// restarting. Otherwise sleeping threads would not have any samples to
|
||||
// copy forward while sleeping.
|
||||
(void)mSleep.compareExchange(SLEEPING_OBSERVED, SLEEPING_NOT_OBSERVED);
|
||||
mThreadRegistration.mData.ReinitializeOnResume();
|
||||
}
|
||||
|
||||
// This returns true for the second and subsequent calls in each sleep cycle.
|
||||
bool CanDuplicateLastSampleDueToSleep() {
|
||||
if (mSleep == AWAKE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSleep.compareExchange(SLEEPING_NOT_OBSERVED, SLEEPING_OBSERVED)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return mThreadRegistration.mData.CanDuplicateLastSampleDueToSleep();
|
||||
}
|
||||
|
||||
// Call this whenever the current thread sleeps. Calling it twice in a row
|
||||
// without an intervening setAwake() call is an error.
|
||||
void SetSleeping() {
|
||||
MOZ_ASSERT(mSleep == AWAKE);
|
||||
mSleep = SLEEPING_NOT_OBSERVED;
|
||||
}
|
||||
void SetSleeping() { mThreadRegistration.mData.SetSleeping(); }
|
||||
|
||||
// Call this whenever the current thread wakes. Calling it twice in a row
|
||||
// without an intervening setSleeping() call is an error.
|
||||
void SetAwake() {
|
||||
MOZ_ASSERT(mSleep != AWAKE);
|
||||
mSleep = AWAKE;
|
||||
}
|
||||
void SetAwake() { mThreadRegistration.mData.SetAwake(); }
|
||||
|
||||
bool IsSleeping() { return mSleep != AWAKE; }
|
||||
|
||||
ProfilerThreadId ThreadId() const { return mThreadId; }
|
||||
bool IsSleeping() { return mThreadRegistration.mData.IsSleeping(); }
|
||||
|
||||
class ProfilingStack& ProfilingStack() {
|
||||
return mProfilingStack;
|
||||
return mThreadRegistration.mData.ProfilingStackRef();
|
||||
}
|
||||
const class ProfilingStack& ProfilingStack() const {
|
||||
return mThreadRegistration.mData.ProfilingStackCRef();
|
||||
}
|
||||
const class ProfilingStack& ProfilingStack() const { return mProfilingStack; }
|
||||
|
||||
private:
|
||||
class ProfilingStack& mProfilingStack;
|
||||
|
||||
// mThreadId contains the thread ID of the current thread. It is safe to read
|
||||
// this from multiple threads concurrently, as it will never be mutated.
|
||||
const ProfilerThreadId mThreadId;
|
||||
|
||||
// mSleep tracks whether the thread is sleeping, and if so, whether it has
|
||||
// been previously observed. This is used for an optimization: in some cases,
|
||||
// when a thread is asleep, we duplicate the previous sample, which is
|
||||
// cheaper than taking a new sample.
|
||||
//
|
||||
// mSleep is atomic because it is accessed from multiple threads.
|
||||
//
|
||||
// - It is written only by this thread, via setSleeping() and setAwake().
|
||||
//
|
||||
// - It is read by SamplerThread::Run().
|
||||
//
|
||||
// There are two cases where racing between threads can cause an issue.
|
||||
//
|
||||
// - If CanDuplicateLastSampleDueToSleep() returns false but that result is
|
||||
// invalidated before being acted upon, we will take a full sample
|
||||
// unnecessarily. This is additional work but won't cause any correctness
|
||||
// issues. (In actual fact, this case is impossible. In order to go from
|
||||
// CanDuplicateLastSampleDueToSleep() returning false to it returning true
|
||||
// requires an intermediate call to it in order for mSleep to go from
|
||||
// SLEEPING_NOT_OBSERVED to SLEEPING_OBSERVED.)
|
||||
//
|
||||
// - If CanDuplicateLastSampleDueToSleep() returns true but that result is
|
||||
// invalidated before being acted upon -- i.e. the thread wakes up before
|
||||
// DuplicateLastSample() is called -- we will duplicate the previous
|
||||
// sample. This is inaccurate, but only slightly... we will effectively
|
||||
// treat the thread as having slept a tiny bit longer than it really did.
|
||||
//
|
||||
// This latter inaccuracy could be avoided by moving the
|
||||
// CanDuplicateLastSampleDueToSleep() check within the thread-freezing code,
|
||||
// e.g. the section where Tick() is called. But that would reduce the
|
||||
// effectiveness of the optimization because more code would have to be run
|
||||
// before we can tell that duplication is allowed.
|
||||
//
|
||||
static const int AWAKE = 0;
|
||||
static const int SLEEPING_NOT_OBSERVED = 1;
|
||||
static const int SLEEPING_OBSERVED = 2;
|
||||
mozilla::Atomic<int> mSleep;
|
||||
|
||||
// Is this thread being profiled? (e.g., should markers be recorded?)
|
||||
mozilla::Atomic<bool, mozilla::MemoryOrdering::Relaxed> mIsBeingProfiled;
|
||||
mozilla::profiler::ThreadRegistration& mThreadRegistration;
|
||||
};
|
||||
|
||||
// This class contains information that's relevant to a single thread only
|
||||
|
@ -136,7 +76,8 @@ class RacyRegisteredThread final {
|
|||
// protected by the profiler state lock.
|
||||
class RegisteredThread final {
|
||||
public:
|
||||
RegisteredThread(ThreadInfo* aInfo, nsIThread* aThread, void* aStackTop);
|
||||
RegisteredThread(mozilla::profiler::ThreadRegistration& aThreadRegistration,
|
||||
ThreadInfo* aInfo, nsIThread* aThread, void* aStackTop);
|
||||
~RegisteredThread();
|
||||
|
||||
class RacyRegisteredThread& RacyRegisteredThread() {
|
||||
|
@ -147,7 +88,9 @@ class RegisteredThread final {
|
|||
}
|
||||
|
||||
PlatformData* GetPlatformData() const { return mPlatformData.get(); }
|
||||
const void* StackTop() const { return mStackTop; }
|
||||
const void* StackTop() const {
|
||||
return mRacyRegisteredThread.mThreadRegistration.mData.mStackTop;
|
||||
}
|
||||
|
||||
// aDelay is the time the event that is currently running on the thread
|
||||
// was queued before starting to run (if a PrioritizedEventQueue
|
||||
|
@ -168,35 +111,32 @@ class RegisteredThread final {
|
|||
|
||||
void ClearJSContext() {
|
||||
// This function runs on-thread.
|
||||
mContext = nullptr;
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.mJSContext = nullptr;
|
||||
}
|
||||
|
||||
JSContext* GetJSContext() const { return mContext; }
|
||||
JSContext* GetJSContext() const {
|
||||
return mRacyRegisteredThread.mThreadRegistration.mData.mJSContext;
|
||||
}
|
||||
|
||||
const RefPtr<ThreadInfo> Info() const { return mThreadInfo; }
|
||||
const nsCOMPtr<nsIEventTarget> GetEventTarget() const { return mThread; }
|
||||
void ResetMainThread(nsIThread* aThread) { mThread = aThread; }
|
||||
nsCOMPtr<nsIEventTarget> GetEventTarget() const {
|
||||
return mRacyRegisteredThread.mThreadRegistration.mData.mThread;
|
||||
}
|
||||
void ResetMainThread(nsIThread* aThread) {
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.mThread = aThread;
|
||||
}
|
||||
|
||||
// Request that this thread start JS sampling. JS sampling won't actually
|
||||
// start until a subsequent PollJSSampling() call occurs *and* mContext has
|
||||
// been set.
|
||||
void StartJSSampling(uint32_t aJSFlags) {
|
||||
// This function runs on-thread or off-thread.
|
||||
|
||||
MOZ_RELEASE_ASSERT(mJSSampling == INACTIVE ||
|
||||
mJSSampling == INACTIVE_REQUESTED);
|
||||
mJSSampling = ACTIVE_REQUESTED;
|
||||
mJSFlags = aJSFlags;
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.StartJSSampling(aJSFlags);
|
||||
}
|
||||
|
||||
// Request that this thread stop JS sampling. JS sampling won't actually stop
|
||||
// until a subsequent PollJSSampling() call occurs.
|
||||
void StopJSSampling() {
|
||||
// This function runs on-thread or off-thread.
|
||||
|
||||
MOZ_RELEASE_ASSERT(mJSSampling == ACTIVE ||
|
||||
mJSSampling == ACTIVE_REQUESTED);
|
||||
mJSSampling = INACTIVE_REQUESTED;
|
||||
mRacyRegisteredThread.mThreadRegistration.mData.StopJSSampling();
|
||||
}
|
||||
|
||||
// Poll to see if JS sampling should be started/stopped.
|
||||
|
@ -206,71 +146,8 @@ class RegisteredThread final {
|
|||
class RacyRegisteredThread mRacyRegisteredThread;
|
||||
|
||||
const UniquePlatformData mPlatformData;
|
||||
const void* mStackTop;
|
||||
|
||||
const RefPtr<ThreadInfo> mThreadInfo;
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
|
||||
// If this is a JS thread, this is its JSContext, which is required for any
|
||||
// JS sampling.
|
||||
JSContext* mContext;
|
||||
|
||||
// The profiler needs to start and stop JS sampling of JS threads at various
|
||||
// times. However, the JS engine can only do the required actions on the
|
||||
// JS thread itself ("on-thread"), not from another thread ("off-thread").
|
||||
// Therefore, we have the following two-step process.
|
||||
//
|
||||
// - The profiler requests (on-thread or off-thread) that the JS sampling be
|
||||
// started/stopped, by changing mJSSampling to the appropriate REQUESTED
|
||||
// state.
|
||||
//
|
||||
// - The relevant JS thread polls (on-thread) for changes to mJSSampling.
|
||||
// When it sees a REQUESTED state, it performs the appropriate actions to
|
||||
// actually start/stop JS sampling, and changes mJSSampling out of the
|
||||
// REQUESTED state.
|
||||
//
|
||||
// The state machine is as follows.
|
||||
//
|
||||
// INACTIVE --> ACTIVE_REQUESTED
|
||||
// ^ ^ |
|
||||
// | _/ |
|
||||
// | _/ |
|
||||
// | / |
|
||||
// | v v
|
||||
// INACTIVE_REQUESTED <-- ACTIVE
|
||||
//
|
||||
// The polling is done in the following two ways.
|
||||
//
|
||||
// - Via the interrupt callback mechanism; the JS thread must call
|
||||
// profiler_js_interrupt_callback() from its own interrupt callback.
|
||||
// This is how sampling must be started/stopped for threads where the
|
||||
// request was made off-thread.
|
||||
//
|
||||
// - When {Start,Stop}JSSampling() is called on-thread, we can immediately
|
||||
// follow it with a PollJSSampling() call to avoid the delay between the
|
||||
// two steps. Likewise, setJSContext() calls PollJSSampling().
|
||||
//
|
||||
// One non-obvious thing about all this: these JS sampling requests are made
|
||||
// on all threads, even non-JS threads. mContext needs to also be set (via
|
||||
// setJSContext(), which can only happen for JS threads) for any JS sampling
|
||||
// to actually happen.
|
||||
//
|
||||
enum {
|
||||
INACTIVE = 0,
|
||||
ACTIVE_REQUESTED = 1,
|
||||
ACTIVE = 2,
|
||||
INACTIVE_REQUESTED = 3,
|
||||
} mJSSampling;
|
||||
|
||||
uint32_t mJSFlags;
|
||||
|
||||
bool JSTracerEnabled() {
|
||||
return mJSFlags & uint32_t(JSInstrumentationFlags::TraceLogging);
|
||||
}
|
||||
|
||||
bool JSAllocationsEnabled() {
|
||||
return mJSFlags & uint32_t(JSInstrumentationFlags::Allocations);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // RegisteredThread_h
|
||||
|
|
|
@ -4113,8 +4113,12 @@ static ProfilingStack* locked_register_thread(
|
|||
aOffThreadRef.UnlockedConstReaderCRef().Info().Name(),
|
||||
aOffThreadRef.UnlockedConstReaderCRef().Info().ThreadId(),
|
||||
aOffThreadRef.UnlockedConstReaderCRef().Info().IsMainThread());
|
||||
// Temporary hack: Ugly-copy ThreadRegistration* from inside aOffThreadRef!
|
||||
ThreadRegistration* tr;
|
||||
static_assert(sizeof(tr) == sizeof(aOffThreadRef));
|
||||
memcpy(&tr, &aOffThreadRef, sizeof(tr));
|
||||
UniquePtr<RegisteredThread> registeredThread = MakeUnique<RegisteredThread>(
|
||||
info, NS_GetCurrentThreadNoCreate(),
|
||||
*tr, info, NS_GetCurrentThreadNoCreate(),
|
||||
(void*)aOffThreadRef.UnlockedConstReaderCRef().StackTop());
|
||||
|
||||
TLSRegisteredThread::SetRegisteredThread(aLock, registeredThread.get());
|
||||
|
|
|
@ -312,6 +312,11 @@ class ThreadRegistration {
|
|||
private:
|
||||
friend class ThreadRegistry;
|
||||
|
||||
// Trust these to access mData.
|
||||
// TODO: Remove when {,Racy}RegisteredThread are removed in a later patch.
|
||||
friend class ::RacyRegisteredThread;
|
||||
friend class ::RegisteredThread;
|
||||
|
||||
// This is what is embedded inside ThreadRegistration.
|
||||
// References to sub-classes will be provided, to limit access as appropriate.
|
||||
class EmbeddedData final : public LockedRWOnThread {
|
||||
|
|
|
@ -47,6 +47,10 @@
|
|||
class PSAutoLock;
|
||||
struct JSContext;
|
||||
|
||||
// TODO: Remove when {,Racy}RegisteredThread are removed in a later patch.
|
||||
class RacyRegisteredThread;
|
||||
class RegisteredThread;
|
||||
|
||||
namespace mozilla::profiler {
|
||||
|
||||
// All data members related to thread profiling are stored here.
|
||||
|
@ -62,6 +66,11 @@ class ThreadRegistrationData {
|
|||
protected:
|
||||
ThreadRegistrationData(const char* aName, const void* aStackTop);
|
||||
|
||||
// Trust these to access mData.
|
||||
// TODO: Remove when {,Racy}RegisteredThread are removed in a later patch.
|
||||
friend class ::RacyRegisteredThread;
|
||||
friend class ::RegisteredThread;
|
||||
|
||||
// Permanent thread information.
|
||||
// Set at construction, read from anywhere, moved-from at destruction.
|
||||
ThreadRegistrationInfo mInfo;
|
||||
|
|
Загрузка…
Ссылка в новой задаче