--- old/src/hotspot/share/runtime/threadSMR.cpp 2017-12-08 10:00:00.000000000 -0500 +++ new/src/hotspot/share/runtime/threadSMR.cpp 2017-12-08 10:00:00.000000000 -0500 @@ -673,6 +673,82 @@ Atomic::dec(&_delete_notify); } +bool ThreadsSMRSupport::delete_notify() { + // Use load_acquire() in order to see any updates to _delete_notify + // earlier than when delete_lock is grabbed. + return (OrderAccess::load_acquire(&_delete_notify) != 0); +} + +// Safely free a ThreadsList after a Threads::add() or Threads::remove(). +// The specified ThreadsList may not get deleted during this call if it +// is still in-use (referenced by a hazard ptr). Other ThreadsLists +// in the chain may get deleted by this call if they are no longer in-use. +void ThreadsSMRSupport::free_list(ThreadsList* threads) { + assert_locked_or_safepoint(Threads_lock); + + threads->set_next_list(_to_delete_list); + _to_delete_list = threads; + if (EnableThreadSMRStatistics) { + _to_delete_list_cnt++; + if (_to_delete_list_cnt > _to_delete_list_max) { + _to_delete_list_max = _to_delete_list_cnt; + } + } + + // Hash table size should be first power of two higher than twice the length of the ThreadsList + int hash_table_size = MIN2((int)get_java_thread_list()->length(), 32) << 1; + hash_table_size--; + hash_table_size |= hash_table_size >> 1; + hash_table_size |= hash_table_size >> 2; + hash_table_size |= hash_table_size >> 4; + hash_table_size |= hash_table_size >> 8; + hash_table_size |= hash_table_size >> 16; + hash_table_size++; + + // Gather a hash table of the current hazard ptrs: + ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size); + ScanHazardPtrGatherThreadsListClosure scan_cl(scan_table); + Threads::threads_do(&scan_cl); + + // Walk through the linked list of pending freeable ThreadsLists + // and free the ones that are not referenced from hazard ptrs. + ThreadsList* current = _to_delete_list; + ThreadsList* prev = NULL; + ThreadsList* next = NULL; + bool threads_is_freed = false; + while (current != NULL) { + next = current->next_list(); + if (!scan_table->has_entry((void*)current)) { + // This ThreadsList is not referenced by a hazard ptr. + if (prev != NULL) { + prev->set_next_list(next); + } + if (_to_delete_list == current) { + _to_delete_list = next; + } + + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::free_list: threads=" INTPTR_FORMAT " is freed.", os::current_thread_id(), p2i(current)); + if (current == threads) threads_is_freed = true; + delete current; + if (EnableThreadSMRStatistics) { + _java_thread_list_free_cnt++; + _to_delete_list_cnt--; + } + } else { + prev = current; + } + current = next; + } + + if (!threads_is_freed) { + // Only report "is not freed" on the original call to + // free_list() for this ThreadsList. + log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::free_list: threads=" INTPTR_FORMAT " is not freed.", os::current_thread_id(), p2i(threads)); + } + + delete scan_table; +} + // Return true if the specified JavaThread is protected by a hazard // pointer (ThreadsList reference). Otherwise, returns false. // @@ -901,82 +977,6 @@ log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::smr_delete: thread=" INTPTR_FORMAT " is deleted.", os::current_thread_id(), p2i(thread)); } -bool ThreadsSMRSupport::delete_notify() { - // Use load_acquire() in order to see any updates to _delete_notify - // earlier than when delete_lock is grabbed. - return (OrderAccess::load_acquire(&_delete_notify) != 0); -} - -// Safely free a ThreadsList after a Threads::add() or Threads::remove(). -// The specified ThreadsList may not get deleted during this call if it -// is still in-use (referenced by a hazard ptr). Other ThreadsLists -// in the chain may get deleted by this call if they are no longer in-use. -void ThreadsSMRSupport::free_list(ThreadsList* threads) { - assert_locked_or_safepoint(Threads_lock); - - threads->set_next_list(_to_delete_list); - _to_delete_list = threads; - if (EnableThreadSMRStatistics) { - _to_delete_list_cnt++; - if (_to_delete_list_cnt > _to_delete_list_max) { - _to_delete_list_max = _to_delete_list_cnt; - } - } - - // Hash table size should be first power of two higher than twice the length of the ThreadsList - int hash_table_size = MIN2((int)get_java_thread_list()->length(), 32) << 1; - hash_table_size--; - hash_table_size |= hash_table_size >> 1; - hash_table_size |= hash_table_size >> 2; - hash_table_size |= hash_table_size >> 4; - hash_table_size |= hash_table_size >> 8; - hash_table_size |= hash_table_size >> 16; - hash_table_size++; - - // Gather a hash table of the current hazard ptrs: - ThreadScanHashtable *scan_table = new ThreadScanHashtable(hash_table_size); - ScanHazardPtrGatherThreadsListClosure scan_cl(scan_table); - Threads::threads_do(&scan_cl); - - // Walk through the linked list of pending freeable ThreadsLists - // and free the ones that are not referenced from hazard ptrs. - ThreadsList* current = _to_delete_list; - ThreadsList* prev = NULL; - ThreadsList* next = NULL; - bool threads_is_freed = false; - while (current != NULL) { - next = current->next_list(); - if (!scan_table->has_entry((void*)current)) { - // This ThreadsList is not referenced by a hazard ptr. - if (prev != NULL) { - prev->set_next_list(next); - } - if (_to_delete_list == current) { - _to_delete_list = next; - } - - log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::free_list: threads=" INTPTR_FORMAT " is freed.", os::current_thread_id(), p2i(current)); - if (current == threads) threads_is_freed = true; - delete current; - if (EnableThreadSMRStatistics) { - _java_thread_list_free_cnt++; - _to_delete_list_cnt--; - } - } else { - prev = current; - } - current = next; - } - - if (!threads_is_freed) { - // Only report "is not freed" on the original call to - // free_list() for this ThreadsList. - log_debug(thread, smr)("tid=" UINTX_FORMAT ": ThreadsSMRSupport::free_list: threads=" INTPTR_FORMAT " is not freed.", os::current_thread_id(), p2i(threads)); - } - - delete scan_table; -} - // Debug, logging, and printing stuff at the end: