зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1569458 - Use mMutex.AssertCurrentThreadOwns() in BlocksRingBuffer - r=gregtatum
This of course checks that the mutex is locked as expected in non-public APIs. It also checks that user callbacks will not keep readers/writers longer than they should. Differential Revision: https://phabricator.services.mozilla.com/D39625 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
d5ac2c3154
Коммит
6abdf8f681
|
@ -172,7 +172,13 @@ class BlocksRingBuffer {
|
||||||
|
|
||||||
// Destructor explictly destroys all remaining entries, this may invoke the
|
// Destructor explictly destroys all remaining entries, this may invoke the
|
||||||
// caller-provided entry destructor.
|
// caller-provided entry destructor.
|
||||||
~BlocksRingBuffer() { DestroyAllEntries(); }
|
~BlocksRingBuffer() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
// Needed because of lock DEBUG-check in `DestroyAllEntries()`.
|
||||||
|
baseprofiler::detail::BPAutoLock lock(mMutex);
|
||||||
|
#endif // DEBUG
|
||||||
|
DestroyAllEntries();
|
||||||
|
}
|
||||||
|
|
||||||
// Buffer length, constant. No need for locking.
|
// Buffer length, constant. No need for locking.
|
||||||
PowerOfTwo<Length> BufferLength() const { return mBuffer.BufferLength(); }
|
PowerOfTwo<Length> BufferLength() const { return mBuffer.BufferLength(); }
|
||||||
|
@ -190,11 +196,15 @@ class BlocksRingBuffer {
|
||||||
// within a lock guard lifetime.
|
// within a lock guard lifetime.
|
||||||
class EntryReader : public BufferReader {
|
class EntryReader : public BufferReader {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DEBUG
|
||||||
~EntryReader() {
|
~EntryReader() {
|
||||||
// Expect reader to stay within the entry.
|
// Expect reader to stay within the entry.
|
||||||
MOZ_ASSERT(CurrentIndex() >= mEntryStart);
|
MOZ_ASSERT(CurrentIndex() >= mEntryStart);
|
||||||
MOZ_ASSERT(CurrentIndex() <= mEntryStart + mEntryBytes);
|
MOZ_ASSERT(CurrentIndex() <= mEntryStart + mEntryBytes);
|
||||||
|
// No EntryReader should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
}
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
// All BufferReader (aka ModuloBuffer<uint32_t, Index>::Reader) APIs are
|
// All BufferReader (aka ModuloBuffer<uint32_t, Index>::Reader) APIs are
|
||||||
// available to read data from this entry.
|
// available to read data from this entry.
|
||||||
|
@ -262,7 +272,10 @@ class BlocksRingBuffer {
|
||||||
: BufferReader(aRing.mBuffer.ReaderAt(Index(aBlockIndex))),
|
: BufferReader(aRing.mBuffer.ReaderAt(Index(aBlockIndex))),
|
||||||
mRing(WrapNotNull(&aRing)),
|
mRing(WrapNotNull(&aRing)),
|
||||||
mEntryBytes(BufferReader::ReadULEB128<Length>()),
|
mEntryBytes(BufferReader::ReadULEB128<Length>()),
|
||||||
mEntryStart(CurrentIndex()) {}
|
mEntryStart(CurrentIndex()) {
|
||||||
|
// No EntryReader should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
|
||||||
// Using a non-null pointer instead of a reference, to allow copying.
|
// Using a non-null pointer instead of a reference, to allow copying.
|
||||||
// This EntryReader should only live inside one of the thread-safe
|
// This EntryReader should only live inside one of the thread-safe
|
||||||
|
@ -278,6 +291,13 @@ class BlocksRingBuffer {
|
||||||
// Created through `Reader`, lives within a lock guard lifetime.
|
// Created through `Reader`, lives within a lock guard lifetime.
|
||||||
class BlockIterator {
|
class BlockIterator {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DEBUG
|
||||||
|
~BlockIterator() {
|
||||||
|
// No BlockIterator should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
// Comparison with other iterator, mostly used in range-for loops.
|
// Comparison with other iterator, mostly used in range-for loops.
|
||||||
bool operator==(const BlockIterator aRhs) const {
|
bool operator==(const BlockIterator aRhs) const {
|
||||||
MOZ_ASSERT(mRing == aRhs.mRing);
|
MOZ_ASSERT(mRing == aRhs.mRing);
|
||||||
|
@ -327,7 +347,10 @@ class BlocksRingBuffer {
|
||||||
friend class Reader;
|
friend class Reader;
|
||||||
|
|
||||||
BlockIterator(const BlocksRingBuffer& aRing, BlockIndex aBlockIndex)
|
BlockIterator(const BlocksRingBuffer& aRing, BlockIndex aBlockIndex)
|
||||||
: mRing(WrapNotNull(&aRing)), mBlockIndex(aBlockIndex) {}
|
: mRing(WrapNotNull(&aRing)), mBlockIndex(aBlockIndex) {
|
||||||
|
// No BlockIterator should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
|
||||||
// Using a non-null pointer instead of a reference, to allow copying.
|
// Using a non-null pointer instead of a reference, to allow copying.
|
||||||
// This BlockIterator should only live inside one of the thread-safe
|
// This BlockIterator should only live inside one of the thread-safe
|
||||||
|
@ -340,6 +363,13 @@ class BlocksRingBuffer {
|
||||||
// iterate through entries; lives within a lock guard lifetime.
|
// iterate through entries; lives within a lock guard lifetime.
|
||||||
class Reader {
|
class Reader {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DEBUG
|
||||||
|
~Reader() {
|
||||||
|
// No Reader should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
// Index of the first block in the whole buffer.
|
// Index of the first block in the whole buffer.
|
||||||
BlockIndex BufferRangeStart() const { return mRing->mFirstReadIndex; }
|
BlockIndex BufferRangeStart() const { return mRing->mFirstReadIndex; }
|
||||||
|
|
||||||
|
@ -369,7 +399,10 @@ class BlocksRingBuffer {
|
||||||
friend class BlocksRingBuffer;
|
friend class BlocksRingBuffer;
|
||||||
|
|
||||||
explicit Reader(const BlocksRingBuffer& aRing)
|
explicit Reader(const BlocksRingBuffer& aRing)
|
||||||
: mRing(WrapNotNull(&aRing)) {}
|
: mRing(WrapNotNull(&aRing)) {
|
||||||
|
// No Reader should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
|
||||||
// Using a non-null pointer instead of a reference, to allow copying.
|
// Using a non-null pointer instead of a reference, to allow copying.
|
||||||
// This Reader should only live inside one of the thread-safe
|
// This Reader should only live inside one of the thread-safe
|
||||||
|
@ -419,6 +452,14 @@ class BlocksRingBuffer {
|
||||||
// Created through `EntryReserver`, lives within a lock guard lifetime.
|
// Created through `EntryReserver`, lives within a lock guard lifetime.
|
||||||
class EntryWriter : public BufferWriter {
|
class EntryWriter : public BufferWriter {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DEBUG
|
||||||
|
~EntryWriter() {
|
||||||
|
MOZ_ASSERT(RemainingBytes() == 0);
|
||||||
|
// No EntryWriter should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
// All BufferWriter (aka ModuloBuffer<uint32_t, Index>::Writer) APIs are
|
// All BufferWriter (aka ModuloBuffer<uint32_t, Index>::Writer) APIs are
|
||||||
// available to read/write data from/to this entry.
|
// available to read/write data from/to this entry.
|
||||||
// Note that there are no bound checks! So this should not be used with
|
// Note that there are no bound checks! So this should not be used with
|
||||||
|
@ -489,9 +530,10 @@ class BlocksRingBuffer {
|
||||||
BufferWriter::WriteULEB128(aEntryBytes);
|
BufferWriter::WriteULEB128(aEntryBytes);
|
||||||
// ... BufferWriter now at start of entry section.
|
// ... BufferWriter now at start of entry section.
|
||||||
return CurrentIndex();
|
return CurrentIndex();
|
||||||
}()) {}
|
}()) {
|
||||||
|
// No EntryWriter should live outside of a mutexed call.
|
||||||
~EntryWriter() { MOZ_ASSERT(RemainingBytes() == 0); }
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
|
||||||
// Using a non-null pointer instead of a reference, to allow copying.
|
// Using a non-null pointer instead of a reference, to allow copying.
|
||||||
// This EntryWriter should only live inside one of the thread-safe
|
// This EntryWriter should only live inside one of the thread-safe
|
||||||
|
@ -505,6 +547,13 @@ class BlocksRingBuffer {
|
||||||
// for them; lives within a lock guard lifetime.
|
// for them; lives within a lock guard lifetime.
|
||||||
class EntryReserver {
|
class EntryReserver {
|
||||||
public:
|
public:
|
||||||
|
#ifdef DEBUG
|
||||||
|
~EntryReserver() {
|
||||||
|
// No EntryReserver should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
// Reserve `aBytes`, call `aCallback` with a temporary EntryWriter, and
|
// Reserve `aBytes`, call `aCallback` with a temporary EntryWriter, and
|
||||||
// return whatever `aCallback` returns.
|
// return whatever `aCallback` returns.
|
||||||
// Callback should not store `EntryWriter`, as it may become invalid after
|
// Callback should not store `EntryWriter`, as it may become invalid after
|
||||||
|
@ -583,7 +632,10 @@ class BlocksRingBuffer {
|
||||||
friend class BlocksRingBuffer;
|
friend class BlocksRingBuffer;
|
||||||
|
|
||||||
explicit EntryReserver(BlocksRingBuffer& aRing)
|
explicit EntryReserver(BlocksRingBuffer& aRing)
|
||||||
: mRing(WrapNotNull(&aRing)) {}
|
: mRing(WrapNotNull(&aRing)) {
|
||||||
|
// No EntryReserver should live outside of a mutexed call.
|
||||||
|
mRing->mMutex.AssertCurrentThreadOwns();
|
||||||
|
}
|
||||||
|
|
||||||
// Using a non-null pointer instead of a reference, to allow copying.
|
// Using a non-null pointer instead of a reference, to allow copying.
|
||||||
// This EntryReserver should only live inside one of the thread-safe
|
// This EntryReserver should only live inside one of the thread-safe
|
||||||
|
@ -703,6 +755,7 @@ class BlocksRingBuffer {
|
||||||
// Slow, so avoid it for internal checks; this is more to check what callers
|
// Slow, so avoid it for internal checks; this is more to check what callers
|
||||||
// provide us.
|
// provide us.
|
||||||
void AssertBlockIndexIsValid(BlockIndex aBlockIndex) const {
|
void AssertBlockIndexIsValid(BlockIndex aBlockIndex) const {
|
||||||
|
mMutex.AssertCurrentThreadOwns();
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
MOZ_ASSERT(aBlockIndex >= mFirstReadIndex);
|
MOZ_ASSERT(aBlockIndex >= mFirstReadIndex);
|
||||||
MOZ_ASSERT(aBlockIndex < mNextWriteIndex);
|
MOZ_ASSERT(aBlockIndex < mNextWriteIndex);
|
||||||
|
@ -735,6 +788,7 @@ class BlocksRingBuffer {
|
||||||
|
|
||||||
// Create a reader for the block starting at aBlockIndex.
|
// Create a reader for the block starting at aBlockIndex.
|
||||||
EntryReader ReaderInBlockAt(BlockIndex aBlockIndex) const {
|
EntryReader ReaderInBlockAt(BlockIndex aBlockIndex) const {
|
||||||
|
mMutex.AssertCurrentThreadOwns();
|
||||||
MOZ_ASSERT(aBlockIndex >= mFirstReadIndex);
|
MOZ_ASSERT(aBlockIndex >= mFirstReadIndex);
|
||||||
MOZ_ASSERT(aBlockIndex < mNextWriteIndex);
|
MOZ_ASSERT(aBlockIndex < mNextWriteIndex);
|
||||||
return EntryReader(*this, aBlockIndex);
|
return EntryReader(*this, aBlockIndex);
|
||||||
|
@ -744,6 +798,7 @@ class BlocksRingBuffer {
|
||||||
// Note: The read index is not moved; this should only be called from the
|
// Note: The read index is not moved; this should only be called from the
|
||||||
// destructor or ClearAllEntries.
|
// destructor or ClearAllEntries.
|
||||||
void DestroyAllEntries() {
|
void DestroyAllEntries() {
|
||||||
|
mMutex.AssertCurrentThreadOwns();
|
||||||
if (mEntryDestructor) {
|
if (mEntryDestructor) {
|
||||||
// We have an entry destructor, destroy all the things!
|
// We have an entry destructor, destroy all the things!
|
||||||
Reader(*this).ForEach(
|
Reader(*this).ForEach(
|
||||||
|
@ -755,6 +810,7 @@ class BlocksRingBuffer {
|
||||||
// Clear all entries, calling entry destructor (if any), and move read index
|
// Clear all entries, calling entry destructor (if any), and move read index
|
||||||
// to the end so that these entries cannot be read anymore.
|
// to the end so that these entries cannot be read anymore.
|
||||||
void ClearAllEntries() {
|
void ClearAllEntries() {
|
||||||
|
mMutex.AssertCurrentThreadOwns();
|
||||||
DestroyAllEntries();
|
DestroyAllEntries();
|
||||||
// Move read index to write index, so there's effectively no more entries
|
// Move read index to write index, so there's effectively no more entries
|
||||||
// that can be read. (Not setting both to 0, in case user is keeping
|
// that can be read. (Not setting both to 0, in case user is keeping
|
||||||
|
|
Загрузка…
Ссылка в новой задаче