mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1027921 - Part 2: Switch to nsClassHashtable. r=froydnj
This commit is contained in:
parent
1d48eb0a57
commit
2c069186a9
@ -10,9 +10,9 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "plhash.h"
|
||||
#include "prlock.h"
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
#ifdef NS_TRACE_MALLOC
|
||||
@ -177,7 +177,8 @@ public:
|
||||
typedef nsTArray<ResourceAcquisition> ResourceAcquisitionArray;
|
||||
|
||||
private:
|
||||
typedef nsTArray<PLHashEntry*> HashEntryArray;
|
||||
struct OrderingEntry;
|
||||
typedef nsTArray<OrderingEntry*> HashEntryArray;
|
||||
typedef typename HashEntryArray::index_type index_type;
|
||||
typedef typename HashEntryArray::size_type size_type;
|
||||
static const index_type NoIndex = HashEntryArray::NoIndex;
|
||||
@ -206,43 +207,11 @@ private:
|
||||
const T* mResource;
|
||||
};
|
||||
|
||||
static void* TableAlloc(void* /*aPool*/, size_t aSize)
|
||||
{
|
||||
return operator new(aSize);
|
||||
}
|
||||
static void TableFree(void* /*aPool*/, void* aItem)
|
||||
{
|
||||
operator delete(aItem);
|
||||
}
|
||||
static PLHashEntry* EntryAlloc(void* /*aPool*/, const void* aKey)
|
||||
{
|
||||
return new PLHashEntry;
|
||||
}
|
||||
static void EntryFree(void* /*aPool*/, PLHashEntry* aEntry, unsigned aFlag)
|
||||
{
|
||||
delete static_cast<T*>(const_cast<void*>(aEntry->key));
|
||||
delete static_cast<OrderingEntry*>(aEntry->value);
|
||||
aEntry->value = 0;
|
||||
if (aFlag == HT_FREE_ENTRY) {
|
||||
delete aEntry;
|
||||
}
|
||||
}
|
||||
static PLHashNumber HashKey(const void* aKey)
|
||||
{
|
||||
return static_cast<PLHashNumber>(NS_PTR_TO_INT32(aKey) >> 2);
|
||||
}
|
||||
static const PLHashAllocOps kAllocOps;
|
||||
|
||||
// Hash table "interface" the rest of the code should use
|
||||
|
||||
PLHashEntry** GetEntry(const T* aKey)
|
||||
{
|
||||
return PL_HashTableRawLookup(mOrdering, HashKey(aKey), aKey);
|
||||
}
|
||||
|
||||
void PutEntry(T* aKey)
|
||||
{
|
||||
PL_HashTableAdd(mOrdering, aKey, new OrderingEntry(aKey));
|
||||
mOrdering.Put(aKey, new OrderingEntry(aKey));
|
||||
}
|
||||
|
||||
// XXX need these helper methods because OrderingEntry doesn't have
|
||||
@ -257,9 +226,9 @@ private:
|
||||
* the "worst" bad case, adding it anyway will cause
|
||||
* |InTransitiveClosure()| to diverge.
|
||||
*/
|
||||
void AddOrder(PLHashEntry* aLT, PLHashEntry* aGT)
|
||||
void AddOrder(OrderingEntry* aLT, OrderingEntry* aGT)
|
||||
{
|
||||
static_cast<OrderingEntry*>(aLT->value)->mOrderedLT
|
||||
aLT->mOrderedLT
|
||||
.InsertElementSorted(aGT);
|
||||
}
|
||||
|
||||
@ -269,12 +238,10 @@ private:
|
||||
*
|
||||
* Does not consider transitivity.
|
||||
*/
|
||||
bool IsOrdered(const PLHashEntry* aFirst, const PLHashEntry* aSecond)
|
||||
bool IsOrdered(const OrderingEntry* aFirst, const OrderingEntry* aSecond)
|
||||
const
|
||||
{
|
||||
const OrderingEntry* entry =
|
||||
static_cast<const OrderingEntry*>(aFirst->value);
|
||||
return entry->mOrderedLT.BinaryIndexOf(aSecond) != NoIndex;
|
||||
return aFirst->mOrderedLT.BinaryIndexOf(aSecond) != NoIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,10 +250,10 @@ private:
|
||||
*
|
||||
* NOTE: this does *not* consider transitive orderings.
|
||||
*/
|
||||
PLHashEntry* const* GetOrders(const PLHashEntry* aEntry) const
|
||||
OrderingEntry* const* GetOrders(const OrderingEntry* aEntry) const
|
||||
{
|
||||
return
|
||||
static_cast<const OrderingEntry*>(aEntry->value)->mOrderedLT.Elements();
|
||||
aEntry->mOrderedLT.Elements();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,18 +262,18 @@ private:
|
||||
*
|
||||
* NOTE: this does *not* consider transitive orderings.
|
||||
*/
|
||||
size_type NumOrders(const PLHashEntry* aEntry) const
|
||||
size_type NumOrders(const OrderingEntry* aEntry) const
|
||||
{
|
||||
return
|
||||
static_cast<const OrderingEntry*>(aEntry->value)->mOrderedLT.Length();
|
||||
aEntry->mOrderedLT.Length();
|
||||
}
|
||||
|
||||
/** Make a ResourceAcquisition out of |aEntry|. */
|
||||
ResourceAcquisition MakeResourceAcquisition(const PLHashEntry* aEntry) const
|
||||
ResourceAcquisition MakeResourceAcquisition(const OrderingEntry* aEntry) const
|
||||
{
|
||||
return ResourceAcquisition(
|
||||
static_cast<const T*>(aEntry->key),
|
||||
static_cast<const OrderingEntry*>(aEntry->value)->mFirstSeen);
|
||||
aEntry->mResource,
|
||||
aEntry->mFirstSeen);
|
||||
}
|
||||
|
||||
// Throwaway RAII lock to make the following code safer.
|
||||
@ -328,15 +295,8 @@ public:
|
||||
* that will be checked.
|
||||
*/
|
||||
explicit DeadlockDetector(uint32_t aNumResourcesGuess = kDefaultNumBuckets)
|
||||
: mOrdering(aNumResourcesGuess)
|
||||
{
|
||||
mOrdering = PL_NewHashTable(aNumResourcesGuess,
|
||||
HashKey,
|
||||
PL_CompareValues, PL_CompareValues,
|
||||
&kAllocOps, 0);
|
||||
if (!mOrdering) {
|
||||
NS_RUNTIMEABORT("couldn't initialize resource ordering table");
|
||||
}
|
||||
|
||||
mLock = PR_NewLock();
|
||||
if (!mLock) {
|
||||
NS_RUNTIMEABORT("couldn't allocate deadlock detector lock");
|
||||
@ -350,7 +310,6 @@ public:
|
||||
*/
|
||||
~DeadlockDetector()
|
||||
{
|
||||
PL_HashTableDestroy(mOrdering);
|
||||
PR_DestroyLock(mLock);
|
||||
}
|
||||
|
||||
@ -406,10 +365,11 @@ public:
|
||||
NS_ASSERTION(aProposed, "null resource");
|
||||
PRAutoLock _(mLock);
|
||||
|
||||
PLHashEntry* second = *GetEntry(aProposed);
|
||||
OrderingEntry* e = static_cast<OrderingEntry*>(second->value);
|
||||
if (CallStack::kNone == e->mFirstSeen) {
|
||||
e->mFirstSeen = aCallContext;
|
||||
OrderingEntry* proposed = mOrdering.Get(aProposed);
|
||||
NS_ASSERTION(proposed, "missing ordering entry");
|
||||
|
||||
if (CallStack::kNone == proposed->mFirstSeen) {
|
||||
proposed->mFirstSeen = aCallContext;
|
||||
}
|
||||
|
||||
if (!aLast) {
|
||||
@ -417,33 +377,34 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
PLHashEntry* first = *GetEntry(aLast);
|
||||
OrderingEntry* current = mOrdering.Get(aLast);
|
||||
NS_ASSERTION(current, "missing ordering entry");
|
||||
|
||||
// this is the crux of the deadlock detector algorithm
|
||||
|
||||
if (first == second) {
|
||||
if (current == proposed) {
|
||||
// reflexive deadlock. fastpath b/c InTransitiveClosure is
|
||||
// not applicable here.
|
||||
ResourceAcquisitionArray* cycle = new ResourceAcquisitionArray();
|
||||
if (!cycle) {
|
||||
NS_RUNTIMEABORT("can't allocate dep. cycle array");
|
||||
}
|
||||
cycle->AppendElement(MakeResourceAcquisition(first));
|
||||
cycle->AppendElement(MakeResourceAcquisition(current));
|
||||
cycle->AppendElement(ResourceAcquisition(aProposed,
|
||||
aCallContext));
|
||||
return cycle;
|
||||
}
|
||||
if (InTransitiveClosure(first, second)) {
|
||||
if (InTransitiveClosure(current, proposed)) {
|
||||
// we've already established |aLast < aProposed|. all is well.
|
||||
return 0;
|
||||
}
|
||||
if (InTransitiveClosure(second, first)) {
|
||||
if (InTransitiveClosure(proposed, current)) {
|
||||
// the order |aProposed < aLast| has been deduced, perhaps
|
||||
// transitively. we're attempting to violate that
|
||||
// constraint by acquiring resources in the order
|
||||
// |aLast < aProposed|, and thus we may deadlock under the
|
||||
// right conditions.
|
||||
ResourceAcquisitionArray* cycle = GetDeductionChain(second, first);
|
||||
ResourceAcquisitionArray* cycle = GetDeductionChain(proposed, current);
|
||||
// show how acquiring |aProposed| would complete the cycle
|
||||
cycle->AppendElement(ResourceAcquisition(aProposed,
|
||||
aCallContext));
|
||||
@ -452,7 +413,7 @@ public:
|
||||
// |aLast|, |aProposed| are unordered according to our
|
||||
// poset. this is fine, but we now need to add this
|
||||
// ordering constraint.
|
||||
AddOrder(first, second);
|
||||
AddOrder(current, proposed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -462,8 +423,8 @@ public:
|
||||
*
|
||||
* @precondition |aStart != aTarget|
|
||||
*/
|
||||
bool InTransitiveClosure(const PLHashEntry* aStart,
|
||||
const PLHashEntry* aTarget) const
|
||||
bool InTransitiveClosure(const OrderingEntry* aStart,
|
||||
const OrderingEntry* aTarget) const
|
||||
{
|
||||
if (IsOrdered(aStart, aTarget)) {
|
||||
return true;
|
||||
@ -471,7 +432,7 @@ public:
|
||||
|
||||
index_type i = 0;
|
||||
size_type len = NumOrders(aStart);
|
||||
for (const PLHashEntry* const* it = GetOrders(aStart); i < len; ++i, ++it) {
|
||||
for (const OrderingEntry* const* it = GetOrders(aStart); i < len; ++i, ++it) {
|
||||
if (InTransitiveClosure(*it, aTarget)) {
|
||||
return true;
|
||||
}
|
||||
@ -495,8 +456,8 @@ public:
|
||||
*
|
||||
* @precondition |aStart != aTarget|
|
||||
*/
|
||||
ResourceAcquisitionArray* GetDeductionChain(const PLHashEntry* aStart,
|
||||
const PLHashEntry* aTarget)
|
||||
ResourceAcquisitionArray* GetDeductionChain(const OrderingEntry* aStart,
|
||||
const OrderingEntry* aTarget)
|
||||
{
|
||||
ResourceAcquisitionArray* chain = new ResourceAcquisitionArray();
|
||||
if (!chain) {
|
||||
@ -511,8 +472,8 @@ public:
|
||||
|
||||
// precondition: |aStart != aTarget|
|
||||
// invariant: |aStart| is the last element in |aChain|
|
||||
bool GetDeductionChain_Helper(const PLHashEntry* aStart,
|
||||
const PLHashEntry* aTarget,
|
||||
bool GetDeductionChain_Helper(const OrderingEntry* aStart,
|
||||
const OrderingEntry* aTarget,
|
||||
ResourceAcquisitionArray* aChain)
|
||||
{
|
||||
if (IsOrdered(aStart, aTarget)) {
|
||||
@ -522,7 +483,7 @@ public:
|
||||
|
||||
index_type i = 0;
|
||||
size_type len = NumOrders(aStart);
|
||||
for (const PLHashEntry* const* it = GetOrders(aStart); i < len; ++i, ++it) {
|
||||
for (const OrderingEntry* const* it = GetOrders(aStart); i < len; ++i, ++it) {
|
||||
aChain->AppendElement(MakeResourceAcquisition(*it));
|
||||
if (GetDeductionChain_Helper(*it, aTarget, aChain)) {
|
||||
return true;
|
||||
@ -536,7 +497,8 @@ public:
|
||||
* The partial order on resource acquisitions used by the deadlock
|
||||
* detector.
|
||||
*/
|
||||
PLHashTable* mOrdering; // T* -> PLHashEntry<OrderingEntry>
|
||||
nsClassHashtable<nsPtrHashKey<const T>, OrderingEntry> mOrdering;
|
||||
|
||||
|
||||
/**
|
||||
* Protects contentious methods.
|
||||
@ -551,13 +513,6 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
const PLHashAllocOps DeadlockDetector<T>::kAllocOps = {
|
||||
DeadlockDetector<T>::TableAlloc, DeadlockDetector<T>::TableFree,
|
||||
DeadlockDetector<T>::EntryAlloc, DeadlockDetector<T>::EntryFree
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
// FIXME bug 456272: tune based on average workload
|
||||
const uint32_t DeadlockDetector<T>::kDefaultNumBuckets = 64;
|
||||
|
Loading…
Reference in New Issue
Block a user