Bug 1126739 - Add locking to SurfaceCache entry points that bypass the public API. r=tn

This commit is contained in:
Seth Fowler 2015-01-31 15:29:48 -08:00
parent f9b8d259fd
commit aaf43f6f99
3 changed files with 36 additions and 31 deletions

View File

@ -614,16 +614,11 @@ RasterImage::IsOpaque()
void void
RasterImage::OnSurfaceDiscarded() RasterImage::OnSurfaceDiscarded()
{ {
if (!NS_IsMainThread()) { MOZ_ASSERT(mProgressTracker);
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableMethod(this, &RasterImage::OnSurfaceDiscarded);
NS_DispatchToMainThread(runnable);
return;
}
if (mProgressTracker) { nsCOMPtr<nsIRunnable> runnable =
mProgressTracker->OnDiscard(); NS_NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard);
} NS_DispatchToMainThread(runnable);
} }
//****************************************************************************** //******************************************************************************

View File

@ -362,7 +362,7 @@ public:
SurfaceCacheImpl(uint32_t aSurfaceCacheExpirationTimeMS, SurfaceCacheImpl(uint32_t aSurfaceCacheExpirationTimeMS,
uint32_t aSurfaceCacheDiscardFactor, uint32_t aSurfaceCacheDiscardFactor,
uint32_t aSurfaceCacheSize) uint32_t aSurfaceCacheSize)
: mExpirationTracker(this, aSurfaceCacheExpirationTimeMS) : mExpirationTracker(aSurfaceCacheExpirationTimeMS)
, mMemoryPressureObserver(new MemoryPressureObserver) , mMemoryPressureObserver(new MemoryPressureObserver)
, mMutex("SurfaceCache") , mMutex("SurfaceCache")
, mDiscardFactor(aSurfaceCacheDiscardFactor) , mDiscardFactor(aSurfaceCacheDiscardFactor)
@ -742,6 +742,8 @@ public:
nsISupports* aData, nsISupports* aData,
bool aAnonymize) MOZ_OVERRIDE bool aAnonymize) MOZ_OVERRIDE
{ {
MutexAutoLock lock(mMutex);
// We have explicit memory reporting for the surface cache which is more // We have explicit memory reporting for the surface cache which is more
// accurate than the cost metrics we report here, but these metrics are // accurate than the cost metrics we report here, but these metrics are
// still useful to report, since they control the cache's behavior. // still useful to report, since they control the cache's behavior.
@ -809,21 +811,18 @@ private:
struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2> struct SurfaceTracker : public nsExpirationTracker<CachedSurface, 2>
{ {
SurfaceTracker(SurfaceCacheImpl* aCache, uint32_t aSurfaceCacheExpirationTimeMS) explicit SurfaceTracker(uint32_t aSurfaceCacheExpirationTimeMS)
: nsExpirationTracker<CachedSurface, 2>(aSurfaceCacheExpirationTimeMS) : nsExpirationTracker<CachedSurface, 2>(aSurfaceCacheExpirationTimeMS)
, mCache(aCache)
{ } { }
protected: protected:
virtual void NotifyExpired(CachedSurface* aSurface) MOZ_OVERRIDE virtual void NotifyExpired(CachedSurface* aSurface) MOZ_OVERRIDE
{ {
if (mCache) { if (sInstance) {
mCache->Remove(aSurface); MutexAutoLock lock(sInstance->GetMutex());
sInstance->Remove(aSurface);
} }
} }
private:
SurfaceCacheImpl* const mCache; // Weak pointer to owner.
}; };
struct MemoryPressureObserver : public nsIObserver struct MemoryPressureObserver : public nsIObserver
@ -835,6 +834,7 @@ private:
const char16_t*) MOZ_OVERRIDE const char16_t*) MOZ_OVERRIDE
{ {
if (sInstance && strcmp(aTopic, "memory-pressure") == 0) { if (sInstance && strcmp(aTopic, "memory-pressure") == 0) {
MutexAutoLock lock(sInstance->GetMutex());
sInstance->DiscardForMemoryPressure(); sInstance->DiscardForMemoryPressure();
} }
return NS_OK; return NS_OK;

View File

@ -27,18 +27,6 @@ function currentRequest() {
return img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST); return img.getRequest(Ci.nsIImageLoadingContent.CURRENT_REQUEST);
} }
function attachDiscardObserver(result) {
// Create the discard observer.
let observer = new ImageDiscardObserver(result);
let scriptedObserver = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(observer);
// Clone the current imgIRequest with our new observer.
let request = currentRequest();
return request.clone(scriptedObserver);
}
function isImgDecoded() { function isImgDecoded() {
let request = currentRequest(); let request = currentRequest();
return request.imageStatus & Ci.imgIRequest.STATUS_FRAME_COMPLETE ? true : false; return request.imageStatus & Ci.imgIRequest.STATUS_FRAME_COMPLETE ? true : false;
@ -69,9 +57,18 @@ function test() {
} }
function step2() { function step2() {
// Attach a discard listener and create a place to hold the result. // Create a place to hold the result.
var result = { wasDiscarded: false }; var result = { wasDiscarded: false };
var clonedRequest = attachDiscardObserver(result);
// Create the discard observer.
var observer = new ImageDiscardObserver(result);
var scriptedObserver = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.createScriptedObserver(observer);
// Clone the current imgIRequest with our new observer.
var request = currentRequest();
var clonedRequest = request.clone(scriptedObserver);
// Check that the image is decoded. // Check that the image is decoded.
forceDecodeImg(); forceDecodeImg();
@ -83,6 +80,19 @@ function step2() {
var os = Cc["@mozilla.org/observer-service;1"] var os = Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService); .getService(Ci.nsIObserverService);
os.notifyObservers(null, 'memory-pressure', 'heap-minimize'); os.notifyObservers(null, 'memory-pressure', 'heap-minimize');
// The discard notification is delivered asynchronously, so pump the event
// loop before checking.
window.addEventListener('message', function (event) {
if (event.data == 'step3') {
step3(result, scriptedObserver, clonedRequest);
}
}, false);
window.postMessage('step3', '*');
}
function step3(result, scriptedObserver, clonedRequest) {
ok(result.wasDiscarded, 'Image should be discarded.'); ok(result.wasDiscarded, 'Image should be discarded.');
// And we're done. // And we're done.