|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef mozilla_imagelib_DiscardTracker_h_ |
|
7 #define mozilla_imagelib_DiscardTracker_h_ |
|
8 |
|
9 #include "mozilla/Atomics.h" |
|
10 #include "mozilla/LinkedList.h" |
|
11 #include "mozilla/Mutex.h" |
|
12 #include "mozilla/TimeStamp.h" |
|
13 #include "prlock.h" |
|
14 #include "nsThreadUtils.h" |
|
15 #include "nsAutoPtr.h" |
|
16 |
|
17 class nsITimer; |
|
18 |
|
19 namespace mozilla { |
|
20 namespace image { |
|
21 |
|
22 class RasterImage; |
|
23 |
|
24 /** |
|
25 * This static class maintains a linked list of RasterImage objects which are |
|
26 * eligible for discarding. |
|
27 * |
|
28 * When Reset() is called, the node is removed from its position in the list |
|
29 * (if it was there before) and appended to the beginnings of the list. |
|
30 * |
|
31 * Periodically (on a timer and when we notice that we're using more memory |
|
32 * than we'd like for decoded images), we go through the list and discard |
|
33 * decoded data from images at the end of the list. |
|
34 */ |
|
35 class DiscardTracker |
|
36 { |
|
37 public: |
|
38 /** |
|
39 * The DiscardTracker keeps a linked list of Node objects. Each object |
|
40 * points to a RasterImage and contains a timestamp indicating when the |
|
41 * node was inserted into the tracker. |
|
42 * |
|
43 * This structure is embedded within each RasterImage object, and we do |
|
44 * |mDiscardTrackerNode.img = this| on RasterImage construction. Thus, a |
|
45 * RasterImage must always call DiscardTracker::Remove() in its destructor |
|
46 * to avoid having the tracker point to bogus memory. |
|
47 */ |
|
48 struct Node : public LinkedListElement<Node> |
|
49 { |
|
50 RasterImage *img; |
|
51 TimeStamp timestamp; |
|
52 }; |
|
53 |
|
54 /** |
|
55 * Add an image to the front of the tracker's list, or move it to the front |
|
56 * if it's already in the list. This function is main thread only. |
|
57 */ |
|
58 static nsresult Reset(struct Node* node); |
|
59 |
|
60 /** |
|
61 * Remove a node from the tracker; do nothing if the node is currently |
|
62 * untracked. This function is main thread only. |
|
63 */ |
|
64 static void Remove(struct Node* node); |
|
65 |
|
66 /** |
|
67 * Initializes the discard tracker. This function is main thread only. |
|
68 */ |
|
69 static nsresult Initialize(); |
|
70 |
|
71 /** |
|
72 * Shut the discard tracker down. This should be called on XPCOM shutdown |
|
73 * so we destroy the discard timer's nsITimer. This function is main thread |
|
74 * only. |
|
75 */ |
|
76 static void Shutdown(); |
|
77 |
|
78 /** |
|
79 * Discard the decoded image data for all images tracked by the discard |
|
80 * tracker. This function is main thread only. |
|
81 */ |
|
82 static void DiscardAll(); |
|
83 |
|
84 /** |
|
85 * Inform the discard tracker that we are going to allocate some memory |
|
86 * for a decoded image. We use this to determine when we've allocated |
|
87 * too much memory and should discard some images. This function can be |
|
88 * called from any thread and is thread-safe. If this function succeeds, the |
|
89 * caller is now responsible for ensuring that InformDeallocation is called. |
|
90 */ |
|
91 static bool TryAllocation(uint64_t aBytes); |
|
92 |
|
93 /** |
|
94 * Inform the discard tracker that we've deallocated some memory for a |
|
95 * decoded image. This function can be called from any thread and is |
|
96 * thread-safe. |
|
97 */ |
|
98 static void InformDeallocation(uint64_t aBytes); |
|
99 |
|
100 private: |
|
101 /** |
|
102 * This is called when the discard timer fires; it calls into DiscardNow(). |
|
103 */ |
|
104 friend void DiscardTimeoutChangedCallback(const char* aPref, void *aClosure); |
|
105 |
|
106 /** |
|
107 * When run, this runnable sets sDiscardRunnablePending to false and calls |
|
108 * DiscardNow(). |
|
109 */ |
|
110 class DiscardRunnable : public nsRunnable |
|
111 { |
|
112 NS_IMETHOD Run(); |
|
113 }; |
|
114 |
|
115 static void ReloadTimeout(); |
|
116 static nsresult EnableTimer(); |
|
117 static void DisableTimer(); |
|
118 static void MaybeDiscardSoon(); |
|
119 static void TimerCallback(nsITimer *aTimer, void *aClosure); |
|
120 static void DiscardNow(); |
|
121 |
|
122 static LinkedList<Node> sDiscardableImages; |
|
123 static nsCOMPtr<nsITimer> sTimer; |
|
124 static bool sInitialized; |
|
125 static bool sTimerOn; |
|
126 static mozilla::Atomic<bool> sDiscardRunnablePending; |
|
127 static uint64_t sCurrentDecodedImageBytes; |
|
128 static uint32_t sMinDiscardTimeoutMs; |
|
129 static uint32_t sMaxDecodedImageKB; |
|
130 static uint32_t sHardLimitDecodedImageKB; |
|
131 // Lock for safegarding the 64-bit sCurrentDecodedImageBytes |
|
132 static PRLock *sAllocationLock; |
|
133 static mozilla::Mutex* sNodeListMutex; |
|
134 static Atomic<bool> sShutdown; |
|
135 }; |
|
136 |
|
137 } // namespace image |
|
138 } // namespace mozilla |
|
139 |
|
140 #endif /* mozilla_imagelib_DiscardTracker_h_ */ |