Fix for bug 76661, "Recursive attempt to lock cache entry". r=dougt, sr=darin.
git-svn-id: svn://10.0.0.236/trunk@93760 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
815a874b3a
commit
a3fc07f496
78
mozilla/netwerk/cache/src/nsCacheEntry.cpp
vendored
78
mozilla/netwerk/cache/src/nsCacheEntry.cpp
vendored
@ -56,10 +56,55 @@ nsCacheEntry::nsCacheEntry(nsCString * key,
|
||||
}
|
||||
|
||||
|
||||
static void* PR_CALLBACK
|
||||
CacheElementReleaseEventHandler(PLEvent *self)
|
||||
{
|
||||
nsISupports * element = (nsISupports *)PL_GetEventOwner(self);
|
||||
NS_RELEASE(element);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void PR_CALLBACK
|
||||
CacheElementReleaseDestroyHandler(PLEvent *self)
|
||||
{
|
||||
delete self;
|
||||
}
|
||||
|
||||
|
||||
nsCacheEntry::~nsCacheEntry()
|
||||
{
|
||||
delete mKey;
|
||||
delete mMetaData;
|
||||
|
||||
if (IsStreamData()) return;
|
||||
|
||||
// proxy release of of memory cache nsISupports objects
|
||||
if (!mData) {
|
||||
NS_ASSERTION(!mEventQ, "### ~nsCacheEntry: mEventQ but no mData");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mEventQ) {
|
||||
NS_ASSERTION(!mData, "### ~nsCacheEntry: mData, but no eventQ");
|
||||
return;
|
||||
}
|
||||
|
||||
PLEvent * event = new PLEvent;
|
||||
if (!event) {
|
||||
// XXX warning
|
||||
return;
|
||||
}
|
||||
|
||||
nsISupports * data = mData;
|
||||
NS_ADDREF(data);
|
||||
|
||||
PL_InitEvent(event,
|
||||
data,
|
||||
CacheElementReleaseEventHandler,
|
||||
CacheElementReleaseDestroyHandler);
|
||||
|
||||
mEventQ->PostEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@ -88,6 +133,7 @@ nsCacheEntry::GetData(nsISupports **result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsCacheEntry::TouchData()
|
||||
{
|
||||
@ -436,7 +482,7 @@ nsCacheEntryHashTable::ops =
|
||||
MatchEntry,
|
||||
MoveEntry,
|
||||
ClearEntry,
|
||||
Finalize
|
||||
PL_DHashFinalizeStub
|
||||
};
|
||||
|
||||
|
||||
@ -449,7 +495,7 @@ nsCacheEntryHashTable::nsCacheEntryHashTable()
|
||||
nsCacheEntryHashTable::~nsCacheEntryHashTable()
|
||||
{
|
||||
if (initialized)
|
||||
PL_DHashTableFinish(&table);
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
|
||||
@ -465,6 +511,15 @@ nsCacheEntryHashTable::Init()
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsCacheEntryHashTable::Shutdown()
|
||||
{
|
||||
if (initialized) {
|
||||
PL_DHashTableFinish(&table);
|
||||
initialized = PR_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nsCacheEntry *
|
||||
nsCacheEntryHashTable::GetEntry( const nsCString * key)
|
||||
@ -585,22 +640,3 @@ nsCacheEntryHashTable::ClearEntry(PLDHashTable * /* table */,
|
||||
{
|
||||
((nsCacheEntryHashTableEntry *)hashEntry)->cacheEntry = 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsCacheEntryHashTable::Finalize(PLDHashTable * table)
|
||||
{
|
||||
(void) PL_DHashTableEnumerate(table, FreeCacheEntries, nsnull);
|
||||
}
|
||||
|
||||
|
||||
PLDHashOperator PR_CALLBACK
|
||||
nsCacheEntryHashTable::FreeCacheEntries(PLDHashTable *table,
|
||||
PLDHashEntryHdr *hdr,
|
||||
PRUint32 number,
|
||||
void *arg)
|
||||
{
|
||||
nsCacheEntryHashTableEntry *entry = (nsCacheEntryHashTableEntry *)hdr;
|
||||
delete entry->cacheEntry;
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
47
mozilla/netwerk/cache/src/nsCacheEntry.h
vendored
47
mozilla/netwerk/cache/src/nsCacheEntry.h
vendored
@ -24,16 +24,17 @@
|
||||
#ifndef _nsCacheEntry_h_
|
||||
#define _nsCacheEntry_h_
|
||||
|
||||
#include "nsICache.h"
|
||||
#include "nsICacheEntryDescriptor.h"
|
||||
#include "nsCacheMetaData.h"
|
||||
|
||||
#include "nspr.h"
|
||||
#include "pldhash.h"
|
||||
#include "nscore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsAReadableString.h"
|
||||
|
||||
#include "nsICache.h"
|
||||
#include "nsICacheEntryDescriptor.h"
|
||||
#include "nsCacheMetaData.h"
|
||||
#include "nsIEventQueue.h"
|
||||
|
||||
|
||||
class nsCacheDevice;
|
||||
@ -79,13 +80,15 @@ public:
|
||||
* Data accessors
|
||||
*/
|
||||
nsresult GetData( nsISupports ** result);
|
||||
void SetData( nsISupports * data) { mData = data; }
|
||||
void SetData( nsISupports * data) { mData = data;}
|
||||
|
||||
PRUint32 DataSize() { return mDataSize;}
|
||||
void SetDataSize( PRUint32 size) { mDataSize = size;}
|
||||
|
||||
void TouchData();
|
||||
|
||||
|
||||
nsIEventQueue * GetEventQ() { return mEventQ;}
|
||||
void SetEventQ(nsIEventQueue * eventQ) { mEventQ = dont_AddRef(eventQ);}
|
||||
|
||||
/**
|
||||
* Meta data accessors
|
||||
@ -209,21 +212,22 @@ private:
|
||||
void MarkActive() { mFlags |= eActiveMask; }
|
||||
void MarkInactive() { mFlags &= ~eActiveMask; }
|
||||
|
||||
nsCString * mKey; // 4 // XXX ask scc about const'ness
|
||||
PRUint32 mFetchCount; // 4
|
||||
PRUint32 mLastFetched; // 4
|
||||
PRUint32 mLastModified; // 4
|
||||
PRUint32 mLastValidated; // 4
|
||||
PRUint32 mExpirationTime; // 4
|
||||
PRUint32 mFlags; // 4
|
||||
PRUint32 mDataSize; // 4
|
||||
PRUint32 mMetaSize; // 4
|
||||
nsCacheDevice * mCacheDevice; // 4
|
||||
nsCOMPtr<nsISupports> mSecurityInfo; //
|
||||
nsCOMPtr<nsISupports> mData; //
|
||||
nsCacheMetaData * mMetaData; // 4
|
||||
PRCList mRequestQ; // 8
|
||||
PRCList mDescriptorQ; // 8
|
||||
nsCString * mKey; // 4 // XXX ask scc about const'ness
|
||||
PRUint32 mFetchCount; // 4
|
||||
PRUint32 mLastFetched; // 4
|
||||
PRUint32 mLastModified; // 4
|
||||
PRUint32 mLastValidated; // 4
|
||||
PRUint32 mExpirationTime; // 4
|
||||
PRUint32 mFlags; // 4
|
||||
PRUint32 mDataSize; // 4
|
||||
PRUint32 mMetaSize; // 4
|
||||
nsCacheDevice * mCacheDevice; // 4
|
||||
nsCOMPtr<nsISupports> mSecurityInfo; //
|
||||
nsCOMPtr<nsISupports> mData; //
|
||||
nsCOMPtr<nsIEventQueue> mEventQ; // event queue for mData (for mem object cache)
|
||||
nsCacheMetaData * mMetaData; // 4
|
||||
PRCList mRequestQ; // 8
|
||||
PRCList mDescriptorQ; // 8
|
||||
};
|
||||
|
||||
|
||||
@ -265,6 +269,7 @@ public:
|
||||
~nsCacheEntryHashTable();
|
||||
|
||||
nsresult Init();
|
||||
void Shutdown();
|
||||
|
||||
nsCacheEntry *GetEntry( const nsCString * key);
|
||||
nsresult AddEntry( nsCacheEntry *entry);
|
||||
|
||||
@ -236,7 +236,8 @@ nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement)
|
||||
|
||||
mCacheEntry->SetData(cacheElement);
|
||||
mCacheEntry->TouchData();
|
||||
return NS_OK;
|
||||
|
||||
return nsCacheService::GlobalInstance()->SetCacheElement(mCacheEntry, cacheElement);
|
||||
}
|
||||
|
||||
|
||||
|
||||
2
mozilla/netwerk/cache/src/nsCacheRequest.h
vendored
2
mozilla/netwerk/cache/src/nsCacheRequest.h
vendored
@ -133,7 +133,7 @@ private:
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
PRStatus status;
|
||||
PRStatus status = PR_SUCCESS;
|
||||
PR_Lock(mLock);
|
||||
while (WaitingForValidation() && (status == PR_SUCCESS) ) {
|
||||
status = PR_WaitCondVar(mCondVar, PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
44
mozilla/netwerk/cache/src/nsCacheService.cpp
vendored
44
mozilla/netwerk/cache/src/nsCacheService.cpp
vendored
@ -33,17 +33,16 @@
|
||||
#include "nsICacheVisitor.h"
|
||||
|
||||
#include "nsAutoLock.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsIEventQueue.h"
|
||||
#include "nsProxiedService.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsIPrefBranchInternal.h"
|
||||
|
||||
#if 0
|
||||
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
|
||||
static NS_DEFINE_CID(kProxyObjectManagerCID, NS_PROXYEVENT_MANAGER_CID);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -222,6 +221,13 @@ nsCacheService::Init()
|
||||
rv = mActiveEntries.Init();
|
||||
if (NS_FAILED(rv)) goto error;
|
||||
|
||||
// get references to services we'll be using frequently
|
||||
mEventQService = do_GetService(NS_EVENTQUEUESERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mProxyObjectManager = do_GetService(NS_XPCOMPROXY_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
{ // scope nsCOMPtr<nsIPrefService> and nsCOMPtr<nsIPrefBranch>
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
@ -508,11 +514,13 @@ nsCacheService::CreateRequest(nsCacheSession * session,
|
||||
|
||||
// get the nsIEventQueue for the request's thread
|
||||
nsresult rv;
|
||||
#if 0
|
||||
// XXX can we just keep a reference so we don't have to do this everytime?
|
||||
NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueServiceCID, &rv);
|
||||
if (NS_FAILED(rv)) goto error;
|
||||
#endif
|
||||
|
||||
rv = eventQService->ResolveEventQueue(NS_CURRENT_EVENTQ,
|
||||
rv = mEventQService->ResolveEventQueue(NS_CURRENT_EVENTQ,
|
||||
getter_AddRefs((*request)->mEventQ));
|
||||
if (NS_FAILED(rv)) goto error;
|
||||
|
||||
@ -539,17 +547,19 @@ nsCacheService::NotifyListener(nsCacheRequest * request,
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
#if 0
|
||||
// XXX can we hold onto the proxy object manager?
|
||||
NS_WITH_SERVICE(nsIProxyObjectManager, proxyObjMgr, kProxyObjectManagerCID, &rv);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsICacheListener> listenerProxy;
|
||||
NS_ASSERTION(request->mEventQ, "no event queue for async request!");
|
||||
rv = proxyObjMgr->GetProxyForObject(request->mEventQ,
|
||||
NS_GET_IID(nsICacheListener),
|
||||
request->mListener,
|
||||
PROXY_ASYNC|PROXY_ALWAYS,
|
||||
getter_AddRefs(listenerProxy));
|
||||
rv = mProxyObjectManager->GetProxyForObject(request->mEventQ,
|
||||
NS_GET_IID(nsICacheListener),
|
||||
request->mListener,
|
||||
PROXY_ASYNC|PROXY_ALWAYS,
|
||||
getter_AddRefs(listenerProxy));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
return listenerProxy->OnCacheEntryAvailable(descriptor, accessGranted, error);
|
||||
@ -868,6 +878,21 @@ nsCacheService::SetCacheDevicesEnabled(PRBool enableDisk, PRBool enableMemory)
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsCacheService::SetCacheElement(nsCacheEntry * entry, nsISupports * element)
|
||||
{
|
||||
nsresult rv;
|
||||
nsIEventQueue * eventQ;
|
||||
rv = mEventQService->ResolveEventQueue(NS_CURRENT_EVENTQ, &eventQ);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
entry->SetEventQ(eventQ);
|
||||
entry->SetData(element);
|
||||
entry->TouchData();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsCacheService::OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize)
|
||||
{
|
||||
@ -1072,6 +1097,7 @@ nsCacheService::ClearActiveEntries()
|
||||
{
|
||||
// XXX really we want a different finalize callback for mActiveEntries
|
||||
PL_DHashTableEnumerate(&mActiveEntries.table, DeactivateAndClearEntry, nsnull);
|
||||
mActiveEntries.Shutdown();
|
||||
}
|
||||
|
||||
|
||||
|
||||
12
mozilla/netwerk/cache/src/nsCacheService.h
vendored
12
mozilla/netwerk/cache/src/nsCacheService.h
vendored
@ -27,13 +27,16 @@
|
||||
#ifndef _nsCacheService_h_
|
||||
#define _nsCacheService_h_
|
||||
|
||||
#include "nspr.h"
|
||||
#include "nsICacheService.h"
|
||||
#include "nsCacheSession.h"
|
||||
#include "nsCacheDevice.h"
|
||||
#include "nsCacheEntry.h"
|
||||
|
||||
#include "nspr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsString.h"
|
||||
#include "nsIEventQueueService.h"
|
||||
#include "nsProxiedService.h"
|
||||
|
||||
class nsCacheRequest;
|
||||
|
||||
@ -74,6 +77,7 @@ public:
|
||||
/**
|
||||
* Methods called by nsCacheEntryDescriptor
|
||||
*/
|
||||
nsresult SetCacheElement(nsCacheEntry * entry, nsISupports * element);
|
||||
|
||||
nsresult OnDataSizeChange(nsCacheEntry * entry, PRInt32 deltaSize);
|
||||
|
||||
@ -157,8 +161,10 @@ private:
|
||||
cacheServiceActiveMask = 1
|
||||
};
|
||||
|
||||
static nsCacheService * gService; // there can be only one...
|
||||
|
||||
static nsCacheService * gService; // there can be only one...
|
||||
nsCOMPtr<nsIEventQueueService> mEventQService;
|
||||
nsCOMPtr<nsIProxyObjectManager> mProxyObjectManager;
|
||||
|
||||
PRLock* mCacheServiceLock;
|
||||
|
||||
PRBool mEnableMemoryDevice;
|
||||
|
||||
@ -51,17 +51,19 @@ nsMemoryCacheDevice::nsMemoryCacheDevice()
|
||||
PR_INIT_CLIST(&mEvictionList);
|
||||
}
|
||||
|
||||
|
||||
nsMemoryCacheDevice::~nsMemoryCacheDevice()
|
||||
{
|
||||
#if DEBUG
|
||||
printf("### starting ~nsMemoryCacheDevice()\n");
|
||||
#endif
|
||||
// XXX dealloc all memory
|
||||
#endif
|
||||
nsresult rv;
|
||||
NS_WITH_SERVICE(nsIPref, prefs, NS_PREF_CONTRACTID, &rv);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
prefs->UnregisterCallback(gMemoryCacheSizePref, MemoryCacheSizeChanged, this);
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
|
||||
@ -123,6 +125,34 @@ nsMemoryCacheDevice::Init()
|
||||
nsresult
|
||||
nsMemoryCacheDevice::Shutdown()
|
||||
{
|
||||
mMemCacheEntries.Shutdown();
|
||||
|
||||
// evict all entries
|
||||
nsCacheEntry * entry, * next;
|
||||
|
||||
entry = (nsCacheEntry *)PR_LIST_HEAD(&mEvictionList);
|
||||
while (entry != &mEvictionList) {
|
||||
NS_ASSERTION(entry->IsInUse() == PR_FALSE, "### shutting down with active entries.\n");
|
||||
next = (nsCacheEntry *)PR_NEXT_LINK(entry);
|
||||
PR_REMOVE_AND_INIT_LINK(entry);
|
||||
|
||||
// update statistics
|
||||
PRUint32 memoryRecovered = entry->Size();
|
||||
mTotalSize -= memoryRecovered;
|
||||
mInactiveSize -= memoryRecovered;
|
||||
--mEntryCount;
|
||||
|
||||
delete entry;
|
||||
entry = next;
|
||||
}
|
||||
|
||||
/*
|
||||
* we're not factoring in changes to meta data yet...
|
||||
* NS_ASSERTION(mTotalSize == 0, "### mem cache leaking entries?\n");
|
||||
*/
|
||||
NS_ASSERTION(mInactiveSize == 0, "### mem cache leaking entries?\n");
|
||||
NS_ASSERTION(mEntryCount == 0, "### mem cache leaking entries?\n");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user