Tue, 18 Jun 2013 08:44:08 -0400
8013651: NMT: reserve/release sequence id's in incorrect order due to race
Summary: Fixed NMT race condition for realloc, uncommit and release
Reviewed-by: coleenp, ccheung
zgu@3900 | 1 | /* |
zgu@5272 | 2 | * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. |
zgu@3900 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
zgu@3900 | 4 | * |
zgu@3900 | 5 | * This code is free software; you can redistribute it and/or modify it |
zgu@3900 | 6 | * under the terms of the GNU General Public License version 2 only, as |
zgu@3900 | 7 | * published by the Free Software Foundation. |
zgu@3900 | 8 | * |
zgu@3900 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
zgu@3900 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
zgu@3900 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
zgu@3900 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
zgu@3900 | 13 | * accompanied this code). |
zgu@3900 | 14 | * |
zgu@3900 | 15 | * You should have received a copy of the GNU General Public License version |
zgu@3900 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
zgu@3900 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
zgu@3900 | 18 | * |
zgu@3900 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
zgu@3900 | 20 | * or visit www.oracle.com if you need additional information or have any |
zgu@3900 | 21 | * questions. |
zgu@3900 | 22 | * |
zgu@3900 | 23 | */ |
zgu@3900 | 24 | |
zgu@3900 | 25 | #ifndef SHARE_VM_SERVICES_MEM_RECORDER_HPP |
zgu@3900 | 26 | #define SHARE_VM_SERVICES_MEM_RECORDER_HPP |
zgu@3900 | 27 | |
zgu@3900 | 28 | #include "memory/allocation.hpp" |
zgu@3900 | 29 | #include "runtime/os.hpp" |
zgu@3900 | 30 | #include "services/memPtrArray.hpp" |
zgu@3900 | 31 | |
zgu@3900 | 32 | class MemSnapshot; |
zgu@3900 | 33 | class MemTracker; |
zgu@3900 | 34 | class MemTrackWorker; |
zgu@3900 | 35 | |
zgu@3900 | 36 | // Fixed size memory pointer array implementation |
zgu@3900 | 37 | template <class E, int SIZE> class FixedSizeMemPointerArray : |
zgu@3900 | 38 | public MemPointerArray { |
zgu@3900 | 39 | // This implementation is for memory recorder only |
zgu@3900 | 40 | friend class MemRecorder; |
zgu@3900 | 41 | |
zgu@3900 | 42 | private: |
zgu@3900 | 43 | E _data[SIZE]; |
zgu@3900 | 44 | int _size; |
zgu@3900 | 45 | |
zgu@3900 | 46 | protected: |
zgu@3900 | 47 | FixedSizeMemPointerArray(bool init_elements = false): |
zgu@3900 | 48 | _size(0){ |
zgu@3900 | 49 | if (init_elements) { |
zgu@3900 | 50 | for (int index = 0; index < SIZE; index ++) { |
zgu@3900 | 51 | ::new ((void*)&_data[index]) E(); |
zgu@3900 | 52 | } |
zgu@3900 | 53 | } |
zgu@3900 | 54 | } |
zgu@3900 | 55 | |
zgu@3900 | 56 | void* operator new(size_t size, const std::nothrow_t& nothrow_constant) { |
zgu@3900 | 57 | // the instance is part of memRecorder, needs to be tagged with 'otNMTRecorder' |
zgu@3900 | 58 | // to avoid recursion |
zgu@3900 | 59 | return os::malloc(size, (mtNMT | otNMTRecorder)); |
zgu@3900 | 60 | } |
zgu@3900 | 61 | |
zgu@3900 | 62 | void* operator new(size_t size) { |
zgu@3900 | 63 | assert(false, "use nothrow version"); |
zgu@3900 | 64 | return NULL; |
zgu@3900 | 65 | } |
zgu@3900 | 66 | |
zgu@3900 | 67 | void operator delete(void* p) { |
zgu@3900 | 68 | os::free(p, (mtNMT | otNMTRecorder)); |
zgu@3900 | 69 | } |
zgu@3900 | 70 | |
zgu@3900 | 71 | // instance size |
zgu@3900 | 72 | inline size_t instance_size() const { |
zgu@3900 | 73 | return sizeof(FixedSizeMemPointerArray<E, SIZE>); |
zgu@3900 | 74 | } |
zgu@3900 | 75 | |
zgu@3994 | 76 | NOT_PRODUCT(int capacity() const { return SIZE; }) |
zgu@3900 | 77 | |
zgu@3900 | 78 | public: |
zgu@3900 | 79 | // implementation of public interface |
zgu@3900 | 80 | bool out_of_memory() const { return false; } |
zgu@3900 | 81 | bool is_empty() const { return _size == 0; } |
zgu@3900 | 82 | bool is_full() { return length() >= SIZE; } |
zgu@3900 | 83 | int length() const { return _size; } |
zgu@3900 | 84 | |
zgu@3900 | 85 | void clear() { |
zgu@3900 | 86 | _size = 0; |
zgu@3900 | 87 | } |
zgu@3900 | 88 | |
zgu@3900 | 89 | bool append(MemPointer* ptr) { |
zgu@3900 | 90 | if (is_full()) return false; |
zgu@3900 | 91 | _data[_size ++] = *(E*)ptr; |
zgu@3900 | 92 | return true; |
zgu@3900 | 93 | } |
zgu@3900 | 94 | |
zgu@3900 | 95 | virtual bool insert_at(MemPointer* p, int pos) { |
zgu@3900 | 96 | assert(false, "append only"); |
zgu@3900 | 97 | return false; |
zgu@3900 | 98 | } |
zgu@3900 | 99 | |
zgu@3900 | 100 | virtual bool remove_at(int pos) { |
zgu@3900 | 101 | assert(false, "not supported"); |
zgu@3900 | 102 | return false; |
zgu@3900 | 103 | } |
zgu@3900 | 104 | |
zgu@3900 | 105 | MemPointer* at(int index) const { |
zgu@3900 | 106 | assert(index >= 0 && index < length(), |
zgu@3900 | 107 | "parameter check"); |
zgu@3900 | 108 | return ((E*)&_data[index]); |
zgu@3900 | 109 | } |
zgu@3900 | 110 | |
zgu@3900 | 111 | void sort(FN_SORT fn) { |
zgu@3900 | 112 | qsort((void*)_data, _size, sizeof(E), fn); |
zgu@3900 | 113 | } |
zgu@3900 | 114 | |
zgu@3900 | 115 | bool shrink() { |
zgu@3900 | 116 | return false; |
zgu@3900 | 117 | } |
zgu@3900 | 118 | }; |
zgu@3900 | 119 | |
zgu@3900 | 120 | |
zgu@3900 | 121 | // This iterator requires pre-sorted MemPointerArray, which is sorted by: |
zgu@3900 | 122 | // 1. address |
zgu@3900 | 123 | // 2. allocation type |
zgu@3900 | 124 | // 3. sequence number |
zgu@3900 | 125 | // During the array walking, iterator collapses pointers with the same |
zgu@3900 | 126 | // address and allocation type, and only returns the one with highest |
zgu@3900 | 127 | // sequence number. |
zgu@3900 | 128 | // |
zgu@3900 | 129 | // This is read-only iterator, update methods are asserted. |
zgu@3900 | 130 | class SequencedRecordIterator : public MemPointerArrayIterator { |
zgu@3900 | 131 | private: |
zgu@3900 | 132 | MemPointerArrayIteratorImpl _itr; |
zgu@3900 | 133 | MemPointer* _cur; |
zgu@3900 | 134 | |
zgu@3900 | 135 | public: |
zgu@3900 | 136 | SequencedRecordIterator(const MemPointerArray* arr): |
zgu@3900 | 137 | _itr(const_cast<MemPointerArray*>(arr)) { |
zgu@3900 | 138 | _cur = next_record(); |
zgu@3900 | 139 | } |
zgu@3900 | 140 | |
zgu@3900 | 141 | SequencedRecordIterator(const SequencedRecordIterator& itr): |
zgu@3900 | 142 | _itr(itr._itr) { |
zgu@3900 | 143 | _cur = next_record(); |
zgu@3900 | 144 | } |
zgu@3900 | 145 | |
zgu@3900 | 146 | // return the pointer at current position |
zgu@3900 | 147 | virtual MemPointer* current() const { |
zgu@3900 | 148 | return _cur; |
zgu@3900 | 149 | }; |
zgu@3900 | 150 | |
zgu@3900 | 151 | // return the next pointer and advance current position |
zgu@3900 | 152 | virtual MemPointer* next() { |
zgu@3900 | 153 | _cur = next_record(); |
zgu@3900 | 154 | return _cur; |
zgu@3900 | 155 | } |
zgu@3900 | 156 | |
zgu@3900 | 157 | // return the next pointer without advancing current position |
zgu@3900 | 158 | virtual MemPointer* peek_next() const { |
zgu@3900 | 159 | assert(false, "not implemented"); |
zgu@3900 | 160 | return NULL; |
zgu@3900 | 161 | |
zgu@3900 | 162 | } |
zgu@3900 | 163 | // return the previous pointer without changing current position |
zgu@3900 | 164 | virtual MemPointer* peek_prev() const { |
zgu@3900 | 165 | assert(false, "not implemented"); |
zgu@3900 | 166 | return NULL; |
zgu@3900 | 167 | } |
zgu@3900 | 168 | |
zgu@3900 | 169 | // remove the pointer at current position |
zgu@3900 | 170 | virtual void remove() { |
zgu@3900 | 171 | assert(false, "read-only iterator"); |
zgu@3900 | 172 | }; |
zgu@3900 | 173 | // insert the pointer at current position |
zgu@3900 | 174 | virtual bool insert(MemPointer* ptr) { |
zgu@3900 | 175 | assert(false, "read-only iterator"); |
zgu@3900 | 176 | return false; |
zgu@3900 | 177 | } |
zgu@3900 | 178 | |
zgu@3900 | 179 | virtual bool insert_after(MemPointer* ptr) { |
zgu@3900 | 180 | assert(false, "read-only iterator"); |
zgu@3900 | 181 | return false; |
zgu@3900 | 182 | } |
zgu@3900 | 183 | private: |
zgu@3900 | 184 | // collapse the 'same kind' of records, and return this 'kind' of |
zgu@3900 | 185 | // record with highest sequence number |
zgu@3900 | 186 | MemPointer* next_record(); |
zgu@3900 | 187 | |
zgu@3900 | 188 | // Test if the two records are the same kind: the same memory block and allocation |
zgu@3900 | 189 | // type. |
zgu@3900 | 190 | inline bool same_kind(const MemPointerRecord* p1, const MemPointerRecord* p2) const { |
zgu@4193 | 191 | assert(!p1->is_vm_pointer() && !p2->is_vm_pointer(), "malloc pointer only"); |
zgu@3900 | 192 | return (p1->addr() == p2->addr() && |
zgu@3900 | 193 | (p1->flags() &MemPointerRecord::tag_masks) == |
zgu@3900 | 194 | (p2->flags() & MemPointerRecord::tag_masks)); |
zgu@3900 | 195 | } |
zgu@3900 | 196 | }; |
zgu@3900 | 197 | |
zgu@3900 | 198 | |
zgu@3900 | 199 | |
zgu@3900 | 200 | #define DEFAULT_RECORDER_PTR_ARRAY_SIZE 512 |
zgu@3900 | 201 | |
zgu@3900 | 202 | class MemRecorder : public CHeapObj<mtNMT|otNMTRecorder> { |
zgu@3900 | 203 | friend class MemSnapshot; |
zgu@3900 | 204 | friend class MemTracker; |
zgu@3900 | 205 | friend class MemTrackWorker; |
zgu@4400 | 206 | friend class GenerationData; |
zgu@3900 | 207 | |
zgu@3900 | 208 | protected: |
zgu@3900 | 209 | // the array that holds memory records |
zgu@3900 | 210 | MemPointerArray* _pointer_records; |
zgu@3900 | 211 | |
zgu@3900 | 212 | private: |
zgu@3900 | 213 | // used for linked list |
zgu@3900 | 214 | MemRecorder* _next; |
zgu@3900 | 215 | // active recorder can only record a certain generation data |
ctornqvi@4512 | 216 | unsigned long _generation; |
zgu@3900 | 217 | |
zgu@3900 | 218 | protected: |
zgu@3900 | 219 | _NOINLINE_ MemRecorder(); |
zgu@3900 | 220 | ~MemRecorder(); |
zgu@3900 | 221 | |
zgu@3900 | 222 | // record a memory operation |
zgu@5272 | 223 | bool record(address addr, MEMFLAGS flags, size_t size, jint seq, address caller_pc = 0); |
zgu@3900 | 224 | |
zgu@3900 | 225 | // linked list support |
zgu@3900 | 226 | inline void set_next(MemRecorder* rec) { |
zgu@3900 | 227 | _next = rec; |
zgu@3900 | 228 | } |
zgu@3900 | 229 | |
zgu@3900 | 230 | inline MemRecorder* next() const { |
zgu@3900 | 231 | return _next; |
zgu@3900 | 232 | } |
zgu@3900 | 233 | |
zgu@3900 | 234 | // if the recorder is full |
zgu@3900 | 235 | inline bool is_full() const { |
zgu@3900 | 236 | assert(_pointer_records != NULL, "just check"); |
zgu@3900 | 237 | return _pointer_records->is_full(); |
zgu@3900 | 238 | } |
zgu@3900 | 239 | |
zgu@3900 | 240 | // if running out of memory when initializing recorder's internal |
zgu@3900 | 241 | // data |
zgu@3900 | 242 | inline bool out_of_memory() const { |
zgu@3900 | 243 | return (_pointer_records == NULL || |
zgu@3900 | 244 | _pointer_records->out_of_memory()); |
zgu@3900 | 245 | } |
zgu@3900 | 246 | |
zgu@3900 | 247 | inline void clear() { |
zgu@3900 | 248 | assert(_pointer_records != NULL, "Just check"); |
zgu@3900 | 249 | _pointer_records->clear(); |
zgu@3900 | 250 | } |
zgu@3900 | 251 | |
zgu@3900 | 252 | SequencedRecordIterator pointer_itr(); |
zgu@3900 | 253 | |
ctornqvi@4512 | 254 | // return the generation of this recorder which it belongs to |
ctornqvi@4512 | 255 | unsigned long get_generation() const { return _generation; } |
zgu@3935 | 256 | protected: |
zgu@3900 | 257 | // number of MemRecorder instance |
zgu@3935 | 258 | static volatile jint _instance_count; |
zgu@3900 | 259 | |
zgu@3900 | 260 | private: |
zgu@3900 | 261 | // sorting function, sort records into following order |
zgu@3900 | 262 | // 1. memory address |
zgu@3900 | 263 | // 2. allocation type |
zgu@3900 | 264 | // 3. sequence number |
zgu@3900 | 265 | static int sort_record_fn(const void* e1, const void* e2); |
zgu@3900 | 266 | |
zgu@3900 | 267 | debug_only(void check_dup_seq(jint seq) const;) |
ctornqvi@4512 | 268 | void set_generation(); |
zgu@3900 | 269 | }; |
zgu@3900 | 270 | |
zgu@3900 | 271 | #endif // SHARE_VM_SERVICES_MEM_RECORDER_HPP |