1 /* 2 * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #ifndef GDIHASHTABLE_H 27 #define GDIHASHTABLE_H 28 29 #include "Hashtable.h" 30 31 /* 32 * This class has been created to fix bug #4191297. 33 */ 34 35 /** 36 * GDIHashtable class. Subclasses Hashtable to provide 37 * capability of batch destruction of freed GDI resources. 38 * Assumes that values are only of AwtGDIObject type. 39 */ 40 class GDIHashtable : public Hashtable { 41 struct ListEntry { 42 GDIHashtable* table; 43 ListEntry* next; 44 }; 45 46 /** 47 * GDIHashtable::List class. Designed to store pointers 48 * to all existing GDIHashtables. This is required 49 * to flush all GDIHashtables at once. 50 */ 51 class List { 52 public: List()53 List() : m_pHead(NULL) {} ~List()54 ~List() { clear(); } 55 56 void add(GDIHashtable*); 57 void remove(GDIHashtable*); 58 void flushAll(); 59 60 private: 61 void clear(); 62 63 ListEntry* m_pHead; 64 65 CriticalSection m_listLock; 66 }; 67 68 friend class List; 69 70 /** 71 * GDIHashtable::BatchDestructionManager class. 72 * Tracks the amount of remaining space in the GDI 73 * and flushes GDIHashtables when needed. 74 */ 75 class BatchDestructionManager { 76 private: 77 int m_nCounter; 78 UINT m_nFirstThreshold; 79 UINT m_nSecondThreshold; 80 UINT m_nDestroyPeriod; 81 BOOL m_bBatchingEnabled; 82 83 List m_list; 84 85 CriticalSection m_managerLock; 86 87 public: 88 /** 89 * Constructs a new BatchDestructionManager with the specified parameters. 90 * The care should be taken when non-default values are used, since it 91 * affects performance. They always should satisfy the inequality 92 * 10 < nSecondThreshold < nFirstThreshold. 93 * 94 * @param nFirstThreshold if less than <code>nFirstThreshold</code> percents 95 * of space in GDI heaps is free all existing GDIHashtables will be 96 * flushed on the next call of <code>update</code>. 97 * @param nSecondThreshold if less than <code>nSecondThreshold</code> 98 * percents of space in GDI heaps is free after the flush 99 * <code>update</code> will return <code>TRUE</code>. 100 * @param nDestroyPeriod specifies how often free space in GDI heaps 101 * will be rechecked in low-resource situation. 102 * In detailss: after <code>update</code> prohibit batching by 103 * setting <code>m_bBatchingEnabled</code> to <code>FALSE</code> 104 * it won't recheck free GDI space for the next 105 * <code>nDestroyPeriod<code> calls. So during this time 106 * <code>shouldDestroy</code> will return <code>TRUE</code>. 107 * This is done to reduce performance impact 108 * caused by calls to <code>GetFreeSystemResourses</code>. 109 */ 110 BatchDestructionManager(UINT nFirstThreshold = 50, 111 UINT nSecondThreshold = 15, 112 UINT nDestroyPeriod = 200); 113 114 /** 115 * Adds the specified GDIHashtable to the internal list. 116 * <code>flushAll</code> flushes all GDIHashtables from this list. 117 * @param table pointer to the GDIHashtable to be added. 118 */ add(GDIHashtable * table)119 INLINE void add(GDIHashtable* table) { m_list.add(table); } 120 121 /** 122 * Removes the specified GDIHashtable to the internal list. 123 * Does nothing if the specified table doesn't exist. 124 * @param table pointer to the GDIHashtable to be removed. 125 */ remove(GDIHashtable * table)126 INLINE void remove(GDIHashtable* table) { m_list.remove(table); } 127 128 /** 129 * @return <code>TRUE</code> if unreferenced AwtGDIObjects shouldn't 130 * be destroyed immediatelly. They will be deleted in 131 * a batch when needed. 132 * <code>FALSE</code> if unreferenced AwtGDIObjects should 133 * be destroyed as soon as freed. 134 */ isBatchingEnabled()135 INLINE BOOL isBatchingEnabled() { return m_bBatchingEnabled; } 136 137 /** 138 * Flushes all the GDIHashtables from the internal list. 139 */ flushAll()140 INLINE void flushAll() { m_list.flushAll(); } 141 142 /** 143 * Decrements the internal counter. The initial value 144 * is assigned by <code>update</code> according to 145 * the BatchDestructionManager parameters. When the 146 * counter hits zero the BatchDestructionManager will 147 * recheck the amount of free space in GDI heaps. 148 * This is done to reduce the performance impact caused 149 * by calls to GetFreeSystemResources. Currently this 150 * method is called when a new GDI resource is created. 151 */ decrementCounter()152 INLINE void decrementCounter() { m_nCounter--; } 153 getLock()154 INLINE CriticalSection& getLock() { return m_managerLock; } 155 }; 156 157 public: 158 /** 159 * Constructs a new, empty GDIHashtable with the specified initial 160 * capacity and the specified load factor. 161 */ 162 GDIHashtable(const char* name, void (*deleteProc)(void*) = NULL, 163 int initialCapacity = 29, float loadFactor = 0.75) : Hashtable(name,deleteProc,initialCapacity,loadFactor)164 Hashtable(name, deleteProc, initialCapacity, loadFactor) { 165 manager.add(this); 166 } 167 ~GDIHashtable()168 ~GDIHashtable() { 169 manager.remove(this); 170 } 171 172 /** 173 * Puts the specified element into the hashtable, using the specified 174 * key. The element may be retrieved by doing a get() with the same key. 175 * The key and the element cannot be null. 176 */ 177 void* put(void* key, void* value); 178 179 /** 180 * Depending on the amount of free space in GDI heads destroys 181 * as unreferenced the element corresponding to the key or keeps 182 * it for destruction in batch. 183 * Does nothing if the key is not present. 184 */ 185 void release(void* key); 186 187 /** 188 * Removes all unreferenced elements from the hastable. 189 */ 190 void flush(); 191 192 /** 193 * Flushes all existing GDIHashtable instances. 194 */ flushAll()195 INLINE static void flushAll() { manager.flushAll(); } 196 getManagerLock()197 INLINE CriticalSection& getManagerLock() { return manager.getLock(); } 198 199 private: 200 201 static BatchDestructionManager manager; 202 203 }; 204 205 #endif // GDIHASHTABLE_H 206