michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this file, michael@0: * You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_imagelib_DiscardTracker_h_ michael@0: #define mozilla_imagelib_DiscardTracker_h_ michael@0: michael@0: #include "mozilla/Atomics.h" michael@0: #include "mozilla/LinkedList.h" michael@0: #include "mozilla/Mutex.h" michael@0: #include "mozilla/TimeStamp.h" michael@0: #include "prlock.h" michael@0: #include "nsThreadUtils.h" michael@0: #include "nsAutoPtr.h" michael@0: michael@0: class nsITimer; michael@0: michael@0: namespace mozilla { michael@0: namespace image { michael@0: michael@0: class RasterImage; michael@0: michael@0: /** michael@0: * This static class maintains a linked list of RasterImage objects which are michael@0: * eligible for discarding. michael@0: * michael@0: * When Reset() is called, the node is removed from its position in the list michael@0: * (if it was there before) and appended to the beginnings of the list. michael@0: * michael@0: * Periodically (on a timer and when we notice that we're using more memory michael@0: * than we'd like for decoded images), we go through the list and discard michael@0: * decoded data from images at the end of the list. michael@0: */ michael@0: class DiscardTracker michael@0: { michael@0: public: michael@0: /** michael@0: * The DiscardTracker keeps a linked list of Node objects. Each object michael@0: * points to a RasterImage and contains a timestamp indicating when the michael@0: * node was inserted into the tracker. michael@0: * michael@0: * This structure is embedded within each RasterImage object, and we do michael@0: * |mDiscardTrackerNode.img = this| on RasterImage construction. Thus, a michael@0: * RasterImage must always call DiscardTracker::Remove() in its destructor michael@0: * to avoid having the tracker point to bogus memory. michael@0: */ michael@0: struct Node : public LinkedListElement michael@0: { michael@0: RasterImage *img; michael@0: TimeStamp timestamp; michael@0: }; michael@0: michael@0: /** michael@0: * Add an image to the front of the tracker's list, or move it to the front michael@0: * if it's already in the list. This function is main thread only. michael@0: */ michael@0: static nsresult Reset(struct Node* node); michael@0: michael@0: /** michael@0: * Remove a node from the tracker; do nothing if the node is currently michael@0: * untracked. This function is main thread only. michael@0: */ michael@0: static void Remove(struct Node* node); michael@0: michael@0: /** michael@0: * Initializes the discard tracker. This function is main thread only. michael@0: */ michael@0: static nsresult Initialize(); michael@0: michael@0: /** michael@0: * Shut the discard tracker down. This should be called on XPCOM shutdown michael@0: * so we destroy the discard timer's nsITimer. This function is main thread michael@0: * only. michael@0: */ michael@0: static void Shutdown(); michael@0: michael@0: /** michael@0: * Discard the decoded image data for all images tracked by the discard michael@0: * tracker. This function is main thread only. michael@0: */ michael@0: static void DiscardAll(); michael@0: michael@0: /** michael@0: * Inform the discard tracker that we are going to allocate some memory michael@0: * for a decoded image. We use this to determine when we've allocated michael@0: * too much memory and should discard some images. This function can be michael@0: * called from any thread and is thread-safe. If this function succeeds, the michael@0: * caller is now responsible for ensuring that InformDeallocation is called. michael@0: */ michael@0: static bool TryAllocation(uint64_t aBytes); michael@0: michael@0: /** michael@0: * Inform the discard tracker that we've deallocated some memory for a michael@0: * decoded image. This function can be called from any thread and is michael@0: * thread-safe. michael@0: */ michael@0: static void InformDeallocation(uint64_t aBytes); michael@0: michael@0: private: michael@0: /** michael@0: * This is called when the discard timer fires; it calls into DiscardNow(). michael@0: */ michael@0: friend void DiscardTimeoutChangedCallback(const char* aPref, void *aClosure); michael@0: michael@0: /** michael@0: * When run, this runnable sets sDiscardRunnablePending to false and calls michael@0: * DiscardNow(). michael@0: */ michael@0: class DiscardRunnable : public nsRunnable michael@0: { michael@0: NS_IMETHOD Run(); michael@0: }; michael@0: michael@0: static void ReloadTimeout(); michael@0: static nsresult EnableTimer(); michael@0: static void DisableTimer(); michael@0: static void MaybeDiscardSoon(); michael@0: static void TimerCallback(nsITimer *aTimer, void *aClosure); michael@0: static void DiscardNow(); michael@0: michael@0: static LinkedList sDiscardableImages; michael@0: static nsCOMPtr sTimer; michael@0: static bool sInitialized; michael@0: static bool sTimerOn; michael@0: static mozilla::Atomic sDiscardRunnablePending; michael@0: static uint64_t sCurrentDecodedImageBytes; michael@0: static uint32_t sMinDiscardTimeoutMs; michael@0: static uint32_t sMaxDecodedImageKB; michael@0: static uint32_t sHardLimitDecodedImageKB; michael@0: // Lock for safegarding the 64-bit sCurrentDecodedImageBytes michael@0: static PRLock *sAllocationLock; michael@0: static mozilla::Mutex* sNodeListMutex; michael@0: static Atomic sShutdown; michael@0: }; michael@0: michael@0: } // namespace image michael@0: } // namespace mozilla michael@0: michael@0: #endif /* mozilla_imagelib_DiscardTracker_h_ */