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:
gordon%netscape.com 2001-05-03 02:35:26 +00:00
parent 815a874b3a
commit a3fc07f496
7 changed files with 162 additions and 58 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -236,7 +236,8 @@ nsCacheEntryDescriptor::SetCacheElement(nsISupports * cacheElement)
mCacheEntry->SetData(cacheElement);
mCacheEntry->TouchData();
return NS_OK;
return nsCacheService::GlobalInstance()->SetCacheElement(mCacheEntry, cacheElement);
}

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}