/* -*- 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/. */
// The ChunkedList<T> class implements, at the high level, a non-iterable // list of instances of T. Its goal is to be somehow minimalist for the // use case of storing the debug files handles here, with the property of // not requiring a lock to look up whether it contains a specific value. // It is also chunked in blocks of chunk_size bytes so that its // initialization doesn't require a memory allocation, while keeping the // possibility to increase its size as necessary. Note that chunks are // never deallocated (except in the destructor). // All operations are essentially O(N) but N is not expected to be large // enough to matter. template <typename T, size_t chunk_size = 64> class ChunkedList { struct ListChunk { staticconst size_t kLength =
(chunk_size - sizeof(ListChunk*)) / sizeof(mozilla::Atomic<T>);
~ChunkedList() { // There can be writes happening after this destructor runs, so keep // the list contents and don't reset mLength. But if there are more // elements left than the first chunk can hold, then all hell breaks // loose for any write that would happen after that because any extra // chunk would be deallocated, so just crash in that case.
MOZ_RELEASE_ASSERT(mLength <= ListChunk::kLength);
}
// Add an element at the end of the last chunk of the list. Create a new // chunk if there is not enough room. // This is not thread-safe with another thread calling Add or Remove. void Add(T aValue) {
ListChunk* list = &mList;
size_t position = mLength; for (; position >= ListChunk::kLength; position -= ListChunk::kLength) { if (!list->mNext) {
list->mNext.reset(new ListChunk());
}
list = list->mNext.get();
} // Use an order of operations that ensures any racing Contains call // can't be hurt.
list->mElements[position] = aValue;
mLength++;
}
// Remove an element from the list by replacing it with the last element // of the list, and then shrinking the list. // This is not thread-safe with another thread calling Add or Remove. void Remove(T aValue) { if (!mLength) { return;
}
ListChunk* list = &mList;
size_t last = mLength - 1; do {
size_t position = 0; // Look for an element matching the given value. for (; position < ListChunk::kLength; position++) { if (aValue == list->mElements[position]) {
ListChunk* last_list = list; // Look for the last element in the list, starting from where we are // instead of starting over. for (; last >= ListChunk::kLength; last -= ListChunk::kLength) {
last_list = last_list->mNext.get();
} // Use an order of operations that ensures any racing Contains call // can't be hurt.
T value = last_list->mElements[last];
list->mElements[position] = value;
mLength--; return;
}
}
last -= ListChunk::kLength;
list = list->mNext.get();
} while (list);
}
// Returns whether the list contains the given value. It is meant to be safe // to use without locking, with the tradeoff of being not entirely accurate // if another thread adds or removes an element while this function runs. bool Contains(T aValue) {
ListChunk* list = &mList; // Fix the range of the lookup to whatever the list length is when the // function is called.
size_t length = mLength; do {
size_t list_length = ListChunk::kLength;
list_length = std::min(list_length, length); for (size_t position = 0; position < list_length; position++) { if (aValue == list->mElements[position]) { returntrue;
}
}
length -= ListChunk::kLength;
list = list->mNext.get();
} while (list);
returnfalse;
}
};
typedef ChunkedList<platform_handle_t> FdList;
// Return a list used to hold the IDs of the current debug files. On unix // an ID is a file descriptor. On Windows it is a file HANDLE.
FdList& getDebugFileIDs() { static FdList DebugFileIDs; return DebugFileIDs;
}
} // namespace
namespace mozilla {
// Auxiliary Method to test if a file descriptor is registered to be ignored // by the poisoning IO interposer bool IsDebugFile(platform_handle_t aFileID) { return getDebugFileIDs().Contains(aFileID);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.