1 /* 2 * Copyright (c) 2001, 2019, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #ifndef SHARE_GC_SHARED_PTRQUEUE_HPP 26 #define SHARE_GC_SHARED_PTRQUEUE_HPP 27 28 #include "memory/padded.hpp" 29 #include "utilities/align.hpp" 30 #include "utilities/debug.hpp" 31 #include "utilities/lockFreeStack.hpp" 32 #include "utilities/sizes.hpp" 33 34 class Mutex; 35 class Monitor; 36 37 // There are various techniques that require threads to be able to log 38 // addresses. For example, a generational write barrier might log 39 // the addresses of modified old-generation objects. This type supports 40 // this operation. 41 42 class BufferNode; 43 class PtrQueueSet; 44 class PtrQueue { 45 friend class VMStructs; 46 47 // Noncopyable - not defined. 48 PtrQueue(const PtrQueue&); 49 PtrQueue& operator=(const PtrQueue&); 50 51 // The ptr queue set to which this queue belongs. 52 PtrQueueSet* const _qset; 53 54 // Whether updates should be logged. 55 bool _active; 56 57 // The (byte) index at which an object was last enqueued. Starts at 58 // capacity_in_bytes (indicating an empty buffer) and goes towards zero. 59 // Value is always pointer-size aligned. 60 size_t _index; 61 62 // Size of the current buffer, in bytes. 63 // Value is always pointer-size aligned. 64 size_t _capacity_in_bytes; 65 66 static const size_t _element_size = sizeof(void*); 67 68 // Get the capacity, in bytes. The capacity must have been set. 69 size_t capacity_in_bytes() const { 70 assert(_capacity_in_bytes > 0, "capacity not set"); 71 return _capacity_in_bytes; 72 } 73 74 static size_t byte_index_to_index(size_t ind) { 75 assert(is_aligned(ind, _element_size), "precondition"); 76 return ind / _element_size; 77 } 78 79 static size_t index_to_byte_index(size_t ind) { 80 return ind * _element_size; 81 } 82 83 protected: 84 // The buffer. 85 void** _buf; 86 87 size_t index() const { 88 return byte_index_to_index(_index); 89 } 90 91 void set_index(size_t new_index) { 92 size_t byte_index = index_to_byte_index(new_index); 93 assert(byte_index <= capacity_in_bytes(), "precondition"); 94 _index = byte_index; 95 } 96 97 size_t capacity() const { 98 return byte_index_to_index(capacity_in_bytes()); 99 } 100 101 PtrQueueSet* qset() const { return _qset; } 102 103 // Process queue entries and release resources. 104 void flush_impl(); 105 106 // Process (some of) the buffer and leave it in place for further use, 107 // or enqueue the buffer and allocate a new one. 108 virtual void handle_completed_buffer() = 0; 109 110 void allocate_buffer(); 111 112 // Enqueue the current buffer in the qset and allocate a new buffer. 113 void enqueue_completed_buffer(); 114 115 // Initialize this queue to contain a null buffer, and be part of the 116 // given PtrQueueSet. 117 PtrQueue(PtrQueueSet* qset, bool active = false); 118 119 // Requires queue flushed. 120 ~PtrQueue(); 121 122 public: 123 124 // Forcibly set empty. 125 void reset() { 126 if (_buf != NULL) { 127 _index = capacity_in_bytes(); 128 } 129 } 130 131 void enqueue(volatile void* ptr) { 132 enqueue((void*)(ptr)); 133 } 134 135 // Enqueues the given "obj". 136 void enqueue(void* ptr) { 137 if (!_active) return; 138 else enqueue_known_active(ptr); 139 } 140 141 void handle_zero_index(); 142 143 void enqueue_known_active(void* ptr); 144 145 // Return the size of the in-use region. 146 size_t size() const { 147 size_t result = 0; 148 if (_buf != NULL) { 149 assert(_index <= capacity_in_bytes(), "Invariant"); 150 result = byte_index_to_index(capacity_in_bytes() - _index); 151 } 152 return result; 153 } 154 155 bool is_empty() const { 156 return _buf == NULL || capacity_in_bytes() == _index; 157 } 158 159 // Set the "active" property of the queue to "b". An enqueue to an 160 // inactive thread is a no-op. Setting a queue to inactive resets its 161 // log to the empty state. 162 void set_active(bool b) { 163 _active = b; 164 if (!b && _buf != NULL) { 165 reset(); 166 } else if (b && _buf != NULL) { 167 assert(index() == capacity(), 168 "invariant: queues are empty when activated."); 169 } 170 } 171 172 bool is_active() const { return _active; } 173 174 // To support compiler. 175 176 protected: 177 template<typename Derived> 178 static ByteSize byte_offset_of_index() { 179 return byte_offset_of(Derived, _index); 180 } 181 182 static ByteSize byte_width_of_index() { return in_ByteSize(sizeof(size_t)); } 183 184 template<typename Derived> 185 static ByteSize byte_offset_of_buf() { 186 return byte_offset_of(Derived, _buf); 187 } 188 189 static ByteSize byte_width_of_buf() { return in_ByteSize(_element_size); } 190 191 template<typename Derived> 192 static ByteSize byte_offset_of_active() { 193 return byte_offset_of(Derived, _active); 194 } 195 196 static ByteSize byte_width_of_active() { return in_ByteSize(sizeof(bool)); } 197 198 }; 199 200 class BufferNode { 201 size_t _index; 202 BufferNode* volatile _next; 203 void* _buffer[1]; // Pseudo flexible array member. 204 205 BufferNode() : _index(0), _next(NULL) { } 206 ~BufferNode() { } 207 208 static size_t buffer_offset() { 209 return offset_of(BufferNode, _buffer); 210 } 211 212 static BufferNode* volatile* next_ptr(BufferNode& bn) { return &bn._next; } 213 214 // Allocate a new BufferNode with the "buffer" having size elements. 215 static BufferNode* allocate(size_t size); 216 217 // Free a BufferNode. 218 static void deallocate(BufferNode* node); 219 220 public: 221 typedef LockFreeStack<BufferNode, &next_ptr> Stack; 222 223 BufferNode* next() const { return _next; } 224 void set_next(BufferNode* n) { _next = n; } 225 size_t index() const { return _index; } 226 void set_index(size_t i) { _index = i; } 227 228 // Return the BufferNode containing the buffer, after setting its index. 229 static BufferNode* make_node_from_buffer(void** buffer, size_t index) { 230 BufferNode* node = 231 reinterpret_cast<BufferNode*>( 232 reinterpret_cast<char*>(buffer) - buffer_offset()); 233 node->set_index(index); 234 return node; 235 } 236 237 // Return the buffer for node. 238 static void** make_buffer_from_node(BufferNode *node) { 239 // &_buffer[0] might lead to index out of bounds warnings. 240 return reinterpret_cast<void**>( 241 reinterpret_cast<char*>(node) + buffer_offset()); 242 } 243 244 class Allocator; // Free-list based allocator. 245 class TestSupport; // Unit test support. 246 }; 247 248 // Allocation is based on a lock-free free list of nodes, linked through 249 // BufferNode::_next (see BufferNode::Stack). To solve the ABA problem, 250 // popping a node from the free list is performed within a GlobalCounter 251 // critical section, and pushing nodes onto the free list is done after 252 // a GlobalCounter synchronization associated with the nodes to be pushed. 253 // This is documented behavior so that other parts of the node life-cycle 254 // can depend on and make use of it too. 255 class BufferNode::Allocator { 256 friend class TestSupport; 257 258 // Since we don't expect many instances, and measured >15% speedup 259 // on stress gtest, padding seems like a good tradeoff here. 260 #define DECLARE_PADDED_MEMBER(Id, Type, Name) \ 261 Type Name; DEFINE_PAD_MINUS_SIZE(Id, DEFAULT_CACHE_LINE_SIZE, sizeof(Type)) 262 263 const size_t _buffer_size; 264 char _name[DEFAULT_CACHE_LINE_SIZE - sizeof(size_t)]; // Use name as padding. 265 DECLARE_PADDED_MEMBER(1, Stack, _pending_list); 266 DECLARE_PADDED_MEMBER(2, Stack, _free_list); 267 DECLARE_PADDED_MEMBER(3, volatile size_t, _pending_count); 268 DECLARE_PADDED_MEMBER(4, volatile size_t, _free_count); 269 DECLARE_PADDED_MEMBER(5, volatile bool, _transfer_lock); 270 271 #undef DECLARE_PADDED_MEMBER 272 273 void delete_list(BufferNode* list); 274 bool try_transfer_pending(); 275 276 public: 277 Allocator(const char* name, size_t buffer_size); 278 ~Allocator(); 279 280 const char* name() const { return _name; } 281 size_t buffer_size() const { return _buffer_size; } 282 size_t free_count() const; 283 BufferNode* allocate(); 284 void release(BufferNode* node); 285 286 // Deallocate some of the available buffers. remove_goal is the target 287 // number to remove. Returns the number actually deallocated, which may 288 // be less than the goal if there were fewer available. 289 size_t reduce_free_list(size_t remove_goal); 290 }; 291 292 // A PtrQueueSet represents resources common to a set of pointer queues. 293 // In particular, the individual queues allocate buffers from this shared 294 // set, and return completed buffers to the set. 295 class PtrQueueSet { 296 BufferNode::Allocator* _allocator; 297 298 // Noncopyable - not defined. 299 PtrQueueSet(const PtrQueueSet&); 300 PtrQueueSet& operator=(const PtrQueueSet&); 301 302 protected: 303 bool _all_active; 304 305 // Create an empty ptr queue set. 306 PtrQueueSet(BufferNode::Allocator* allocator); 307 ~PtrQueueSet(); 308 309 public: 310 311 // Return the associated BufferNode allocator. 312 BufferNode::Allocator* allocator() const { return _allocator; } 313 314 // Return the buffer for a BufferNode of size buffer_size(). 315 void** allocate_buffer(); 316 317 // Return an empty buffer to the free list. The node is required 318 // to have been allocated with a size of buffer_size(). 319 void deallocate_buffer(BufferNode* node); 320 321 // A completed buffer is a buffer the mutator is finished with, and 322 // is ready to be processed by the collector. It need not be full. 323 324 // Adds node to the completed buffer list. 325 virtual void enqueue_completed_buffer(BufferNode* node) = 0; 326 327 bool is_active() { return _all_active; } 328 329 size_t buffer_size() const { 330 return _allocator->buffer_size(); 331 } 332 }; 333 334 #endif // SHARE_GC_SHARED_PTRQUEUE_HPP