src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp

Wed, 17 Jun 2020 11:43:05 +0300

author
apetushkov
date
Wed, 17 Jun 2020 11:43:05 +0300
changeset 9928
d2c2cd90513e
parent 9858
b985cbb00e68
permissions
-rw-r--r--

8220293: Deadlock in JFR string pool
Reviewed-by: rehn, egahlin

     1 /*
     2  * Copyright (c) 2016, 2018, 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  */
    25 #ifndef SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
    26 #define SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP
    28 #include "jfr/recorder/storage/jfrMemorySpace.hpp"
    30 template <typename T, template <typename> class RetrievalType, typename Callback>
    31 JfrMemorySpace<T, RetrievalType, Callback>::
    32 JfrMemorySpace(size_t min_elem_size, size_t limit_size, size_t cache_count, Callback* callback) :
    33   _free(),
    34   _full(),
    35   _min_elem_size(min_elem_size),
    36   _limit_size(limit_size),
    37   _cache_count(cache_count),
    38   _callback(callback) {}
    40 template <typename T, template <typename> class RetrievalType, typename Callback>
    41 JfrMemorySpace<T, RetrievalType, Callback>::~JfrMemorySpace() {
    42   Iterator full_iter(_full);
    43   while (full_iter.has_next()) {
    44     Type* t = full_iter.next();
    45     _full.remove(t);
    46     deallocate(t);
    47   }
    48   Iterator free_iter(_free);
    49   while (free_iter.has_next()) {
    50     Type* t = free_iter.next();
    51     _free.remove(t);
    52     deallocate(t);
    53   }
    54 }
    56 template <typename T, template <typename> class RetrievalType, typename Callback>
    57 bool JfrMemorySpace<T, RetrievalType, Callback>::initialize() {
    58   assert(_min_elem_size % os::vm_page_size() == 0, "invariant");
    59   assert(_limit_size % os::vm_page_size() == 0, "invariant");
    60   // pre-allocate cache elements
    61   for (size_t i = 0; i < _cache_count; ++i) {
    62     Type* const t = allocate(_min_elem_size);
    63     if (t == NULL) {
    64       return false;
    65     }
    66     insert_free_head(t);
    67   }
    68   assert(_free.count() == _cache_count, "invariant");
    69   return true;
    70 }
    72 template <typename T, template <typename> class RetrievalType, typename Callback>
    73 inline void JfrMemorySpace<T, RetrievalType, Callback>::release_full(T* t) {
    74   assert(is_locked(), "invariant");
    75   assert(t != NULL, "invariant");
    76   assert(_full.in_list(t), "invariant");
    77   remove_full(t);
    78   assert(!_full.in_list(t), "invariant");
    79   if (t->transient()) {
    80     deallocate(t);
    81     return;
    82   }
    83   assert(t->empty(), "invariant");
    84   assert(!t->retired(), "invariant");
    85   assert(t->identity() == NULL, "invariant");
    86   if (should_populate_cache()) {
    87     assert(!_free.in_list(t), "invariant");
    88     insert_free_head(t);
    89   } else {
    90     deallocate(t);
    91   }
    92 }
    94 template <typename T, template <typename> class RetrievalType, typename Callback>
    95 inline void JfrMemorySpace<T, RetrievalType, Callback>::release_free(T* t) {
    96   assert(is_locked(), "invariant");
    97   assert(t != NULL, "invariant");
    98   assert(_free.in_list(t), "invariant");
    99   if (t->transient()) {
   100     remove_free(t);
   101     assert(!_free.in_list(t), "invariant");
   102     deallocate(t);
   103     return;
   104   }
   105   assert(t->empty(), "invariant");
   106   assert(!t->retired(), "invariant");
   107   assert(t->identity() == NULL, "invariant");
   108   if (!should_populate_cache()) {
   109     remove_free(t);
   110     assert(!_free.in_list(t), "invariant");
   111     deallocate(t);
   112   }
   113 }
   115 template <typename T, template <typename> class RetrievalType, typename Callback>
   116 template <typename IteratorCallback, typename IteratorType>
   117 inline void JfrMemorySpace<T, RetrievalType, Callback>
   118 ::iterate(IteratorCallback& callback, bool full, jfr_iter_direction direction) {
   119   IteratorType iterator(full ? _full : _free, direction);
   120   while (iterator.has_next()) {
   121     callback.process(iterator.next());
   122   }
   123 }
   125 template <typename Mspace>
   126 inline size_t size_adjustment(size_t size, Mspace* mspace) {
   127   assert(mspace != NULL, "invariant");
   128   static const size_t min_elem_size = mspace->min_elem_size();
   129   if (size < min_elem_size) {
   130     size = min_elem_size;
   131   }
   132   return size;
   133 }
   135 template <typename Mspace>
   136 inline typename Mspace::Type* mspace_allocate(size_t size, Mspace* mspace) {
   137   return mspace->allocate(size_adjustment(size, mspace));
   138 }
   140 template <typename Mspace>
   141 inline typename Mspace::Type* mspace_allocate_acquired(size_t size, Mspace* mspace, Thread* thread) {
   142   typename Mspace::Type* const t = mspace_allocate(size, mspace);
   143   if (t == NULL) return NULL;
   144   t->acquire(thread);
   145   return t;
   146 }
   148 template <typename Mspace>
   149 inline typename Mspace::Type* mspace_allocate_transient(size_t size, Mspace* mspace, Thread* thread) {
   150   typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread);
   151   if (t == NULL) return NULL;
   152   assert(t->acquired_by_self(), "invariant");
   153   t->set_transient();
   154   return t;
   155 }
   157 template <typename Mspace>
   158 inline typename Mspace::Type* mspace_allocate_transient_lease(size_t size, Mspace* mspace, Thread* thread) {
   159   typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
   160   if (t == NULL) return NULL;
   161   assert(t->acquired_by_self(), "invariant");
   162   assert(t->transient(), "invaiant");
   163   t->set_lease();
   164   return t;
   165 }
   167 template <typename Mspace>
   168 inline typename Mspace::Type* mspace_allocate_to_full(size_t size, Mspace* mspace, Thread* thread) {
   169   assert(mspace->is_locked(), "invariant");
   170   typename Mspace::Type* const t = mspace_allocate_acquired(size, mspace, thread);
   171   if (t == NULL) return NULL;
   172   mspace->insert_full_head(t);
   173   return t;
   174 }
   176 template <typename Mspace>
   177 inline typename Mspace::Type* mspace_allocate_transient_to_full(size_t size, Mspace* mspace, Thread* thread) {
   178   typename Mspace::Type* const t = mspace_allocate_transient(size, mspace, thread);
   179   if (t == NULL) return NULL;
   180   MspaceLock<Mspace> lock(mspace);
   181   mspace->insert_full_head(t);
   182   return t;
   183 }
   185 template <typename Mspace>
   186 inline typename Mspace::Type* mspace_allocate_transient_lease_to_full(size_t size, Mspace* mspace, Thread* thread) {
   187   typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread);
   188   if (t == NULL) return NULL;
   189   assert(t->acquired_by_self(), "invariant");
   190   assert(t->transient(), "invaiant");
   191   assert(t->lease(), "invariant");
   192   MspaceLock<Mspace> lock(mspace);
   193   mspace->insert_full_head(t);
   194   return t;
   195 }
   197 template <typename Mspace>
   198 inline typename Mspace::Type* mspace_allocate_transient_lease_to_free(size_t size, Mspace* mspace, Thread* thread) {
   199   typename Mspace::Type* const t = mspace_allocate_transient_lease(size, mspace, thread);
   200   if (t == NULL) return NULL;
   201   assert(t->acquired_by_self(), "invariant");
   202   assert(t->transient(), "invaiant");
   203   assert(t->lease(), "invariant");
   204   MspaceLock<Mspace> lock(mspace);
   205   mspace->insert_free_head(t);
   206   return t;
   207 }
   209 template <typename Mspace>
   210 inline typename Mspace::Type* mspace_get_free(size_t size, Mspace* mspace, Thread* thread) {
   211   return mspace->get(size, thread);
   212 }
   214 template <typename Mspace>
   215 inline typename Mspace::Type* mspace_get_free_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) {
   216   assert(size <= mspace->min_elem_size(), "invariant");
   217   for (size_t i = 0; i < retry_count; ++i) {
   218     typename Mspace::Type* const t = mspace_get_free(size, mspace, thread);
   219     if (t != NULL) {
   220       return t;
   221     }
   222   }
   223   return NULL;
   224 }
   226 template <typename Mspace>
   227 inline typename Mspace::Type* mspace_get_free_with_detach(size_t size, Mspace* mspace, Thread* thread) {
   228   typename Mspace::Type* t = mspace_get_free(size, mspace, thread);
   229   if (t != NULL) {
   230     mspace->remove_free(t);
   231   }
   232   return t;
   233 }
   235 template <typename Mspace>
   236 inline typename Mspace::Type* mspace_get_free_to_full(size_t size, Mspace* mspace, Thread* thread) {
   237   assert(size <= mspace->min_elem_size(), "invariant");
   238   assert(mspace->is_locked(), "invariant");
   239   typename Mspace::Type* t = mspace_get_free(size, mspace, thread);
   240   if (t == NULL) {
   241     return NULL;
   242   }
   243   assert(t->acquired_by_self(), "invariant");
   244   move_to_head(t, mspace->free(), mspace->full());
   245   return t;
   246 }
   248 template <typename Mspace>
   249 inline typename Mspace::Type* mspace_get_to_full(size_t size, Mspace* mspace, Thread* thread) {
   250   size = size_adjustment(size, mspace);
   251   MspaceLock<Mspace> lock(mspace);
   252   if (size <= mspace->min_elem_size()) {
   253     typename Mspace::Type* const t = mspace_get_free_to_full(size, mspace, thread);
   254     if (t != NULL) {
   255       return t;
   256     }
   257   }
   258   return mspace_allocate_to_full(size, mspace, thread);
   259 }
   261 template <typename Mspace>
   262 inline typename Mspace::Type* mspace_get_free_lease_with_retry(size_t size, Mspace* mspace, size_t retry_count, Thread* thread) {
   263   typename Mspace::Type* t = mspace_get_free_with_retry(size, mspace, retry_count, thread);
   264   if (t != NULL) {
   265     t->set_lease();
   266   }
   267   return t;
   268 }
   270 template <typename Mspace>
   271 inline typename Mspace::Type* mspace_get_lease(size_t size, Mspace* mspace, Thread* thread) {
   272   typename Mspace::Type* t;
   273   t = mspace_get_free_lease(size, mspace, thread);
   274   if (t != NULL) {
   275     assert(t->acquired_by_self(), "invariant");
   276     assert(t->lease(), "invariant");
   277     return t;
   278   }
   279   t = mspace_allocate_transient_to_full(size, mspace, thread);
   280   if (t != NULL) {
   281     t->set_lease();
   282   }
   283   return t;
   284 }
   286 template <typename Mspace>
   287 inline void mspace_release_full(typename Mspace::Type* t, Mspace* mspace) {
   288   assert(t != NULL, "invariant");
   289   assert(t->unflushed_size() == 0, "invariant");
   290   assert(mspace != NULL, "invariant");
   291   assert(mspace->is_locked(), "invariant");
   292   mspace->release_full(t);
   293 }
   295 template <typename Mspace>
   296 inline void mspace_release_free(typename Mspace::Type* t, Mspace* mspace) {
   297   assert(t != NULL, "invariant");
   298   assert(t->unflushed_size() == 0, "invariant");
   299   assert(mspace != NULL, "invariant");
   300   assert(mspace->is_locked(), "invariant");
   301   mspace->release_free(t);
   302 }
   304 template <typename Mspace>
   305 inline void mspace_release_full_critical(typename Mspace::Type* t, Mspace* mspace) {
   306   MspaceLock<Mspace> lock(mspace);
   307   mspace_release_full(t, mspace);
   308 }
   310 template <typename Mspace>
   311 inline void mspace_release_free_critical(typename Mspace::Type* t, Mspace* mspace) {
   312   MspaceLock<Mspace> lock(mspace);
   313   mspace_release_free(t, mspace);
   314 }
   316 template <typename List>
   317 inline void move_to_head(typename List::Node* t, List& from, List& to) {
   318   assert(from.in_list(t), "invariant");
   319   to.prepend(from.remove(t));
   320 }
   322 template <typename Processor, typename Mspace, typename Iterator>
   323 inline void process_free_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
   324   mspace->template iterate<Processor, Iterator>(processor, false, direction);
   325 }
   327 template <typename Processor, typename Mspace, typename Iterator>
   328 inline void process_full_list_iterator_control(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
   329   mspace->template iterate<Processor, Iterator>(processor, true, direction);
   330 }
   332 template <typename Processor, typename Mspace>
   333 inline void process_full_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
   334   assert(mspace != NULL, "invariant");
   335   if (mspace->is_full_empty()) return;
   336   process_full_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction);
   337 }
   339 template <typename Processor, typename Mspace>
   340 inline void process_free_list(Processor& processor, Mspace* mspace, jfr_iter_direction direction = forward) {
   341   assert(mspace != NULL, "invariant");
   342   assert(mspace->has_free(), "invariant");
   343   process_free_list_iterator_control<Processor, Mspace, typename Mspace::Iterator>(processor, mspace, direction);
   344 }
   346 template <typename Mspace>
   347 inline bool ReleaseOp<Mspace>::process(typename Mspace::Type* t) {
   348   assert(t != NULL, "invariant");
   349   // assumes some means of exclusive access to t
   350   if (t->transient()) {
   351     if (_release_full) {
   352       mspace_release_full_critical(t, _mspace);
   353     } else {
   354       mspace_release_free_critical(t, _mspace);
   355     }
   356     return true;
   357   }
   358   t->reinitialize();
   359   assert(t->empty(), "invariant");
   360   assert(!t->retired(), "invariant");
   361   t->release(); // publish
   362   return true;
   363 }
   365 #ifdef ASSERT
   366 template <typename T>
   367 inline void assert_migration_state(const T* old, const T* new_buffer, size_t used, size_t requested) {
   368   assert(old != NULL, "invariant");
   369   assert(new_buffer != NULL, "invariant");
   370   assert(old->pos() >= old->start(), "invariant");
   371   assert(old->pos() + used <= old->end(), "invariant");
   372   assert(new_buffer->free_size() >= (used + requested), "invariant");
   373 }
   374 #endif // ASSERT
   376 template <typename T>
   377 inline void migrate_outstanding_writes(const T* old, T* new_buffer, size_t used, size_t requested) {
   378   DEBUG_ONLY(assert_migration_state(old, new_buffer, used, requested);)
   379   if (used > 0) {
   380     memcpy(new_buffer->pos(), old->pos(), used);
   381   }
   382 }
   384 #endif // SHARE_VM_JFR_RECORDER_STORAGE_JFRMEMORYSPACE_INLINE_HPP

mercurial