1 
   2 /*
   3 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
   4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5 *
   6 * This code is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 only, as
   8 * published by the Free Software Foundation.
   9 *
  10 * This code is distributed in the hope that it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13 * version 2 for more details (a copy is included in the LICENSE file that
  14 * accompanied this code).
  15 *
  16 * You should have received a copy of the GNU General Public License version
  17 * 2 along with this work; if not, write to the Free Software Foundation,
  18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19 *
  20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21 * or visit www.oracle.com if you need additional information or have any
  22 * questions.
  23 *
  24 */
  25 
  26 #include "precompiled.hpp"
  27 #include "runtime/interfaceSupport.inline.hpp"
  28 #include "runtime/timerTrace.hpp"
  29 #include "runtime/thread.hpp"
  30 #include "runtime/threadSMR.hpp"
  31 #include "services/threadTable.hpp"
  32 #include "utilities/concurrentHashTable.inline.hpp"
  33 #include "utilities/concurrentHashTableTasks.inline.hpp"
  34 
  35 
  36 // 2^24 is max size
  37 static const size_t END_SIZE = 24;
  38 // Default initial size 256
  39 static const size_t DefaultThreadTableSizeLog = 8;
  40 // Prefer short chains of avg 2
  41 static const double PREF_AVG_LIST_LEN = 2.0;
  42 
  43 typedef ConcurrentHashTable<ThreadTableConfig, mtInternal> ThreadTableHash;
  44 
  45 static ThreadTableHash* volatile _local_table = NULL;
  46 
  47 volatile bool ThreadTable::_is_initialized = false;
  48 
  49 
  50 static volatile size_t _current_size = 0;
  51 static volatile size_t _items_count = 0;
  52 
  53 
  54 class ThreadTableEntry : public CHeapObj<mtInternal> {
  55 private:
  56   jlong _tid;
  57   JavaThread* _java_thread;
  58 public:
  59   ThreadTableEntry(jlong tid, JavaThread* java_thread) :
  60     _tid(tid),_java_thread(java_thread) {}
  61 
  62   jlong tid() const { return _tid;}
  63   JavaThread* thread() const {return _java_thread;}
  64 };
  65 
  66 class ThreadTableConfig : public AllStatic {
  67   public:
  68     typedef ThreadTableEntry* Value;
  69 
  70     static uintx get_hash(Value const& value, bool* is_dead) {
  71       jlong tid = value->tid();
  72       return primitive_hash(tid);
  73     }
  74     static void* allocate_node(size_t size, Value const& value) {
  75       ThreadTable::item_added();
  76       return AllocateHeap(size, mtInternal);
  77     }
  78     static void free_node(void* memory, Value const& value) {
  79       delete value;
  80       FreeHeap(memory);
  81       ThreadTable::item_removed();
  82     }
  83 };
  84 
  85 static size_t ceil_log2(size_t val) {
  86   size_t ret;
  87   for (ret = 1; ((size_t)1 << ret) < val; ++ret);
  88   return ret;
  89 }
  90 
  91 // Lazily creates the table and populates it with the given
  92 // thread list
  93 void ThreadTable::lazy_initialize(const ThreadsList *threads) {
  94   if (!_is_initialized) {
  95     {
  96       MutexLocker ml(ThreadTableCreate_lock);
  97       if (!_is_initialized) {
  98         create_table(threads->length());
  99         _is_initialized = true;
 100       }
 101     }
 102     for (uint i = 0; i < threads->length(); i++) {
 103       JavaThread* thread = threads->thread_at(i);
 104       oop tobj = thread->threadObj();
 105       if (tobj != NULL && !thread->is_exiting()) {
 106         jlong java_tid = java_lang_Thread::thread_id(tobj);
 107         add_thread(java_tid, thread);
 108       }
 109     }
 110   }
 111 }
 112 
 113 void ThreadTable::create_table(size_t size) {
 114   assert(_local_table == NULL, "Thread table is already created");
 115   size_t size_log = ceil_log2(size);
 116   size_t start_size_log =
 117       size_log > DefaultThreadTableSizeLog ? size_log : DefaultThreadTableSizeLog;
 118   _current_size = (size_t)1 << start_size_log;
 119   _local_table = new ThreadTableHash(start_size_log, END_SIZE);
 120 }
 121 
 122 void ThreadTable::item_added() {
 123   Atomic::inc(&_items_count);
 124   log_trace(thread, table) ("Thread entry added");
 125 }
 126 
 127 void ThreadTable::item_removed() {
 128   Atomic::dec(&_items_count);
 129   log_trace(thread, table) ("Thread entry removed");
 130 }
 131 
 132 double ThreadTable::get_load_factor() {
 133   return ((double)_items_count)/_current_size;
 134 }
 135 
 136 size_t ThreadTable::table_size() {
 137   return (size_t)1 << _local_table->get_size_log2(Thread::current());
 138 }
 139 
 140 void ThreadTable::grow(JavaThread* jt) {
 141   ThreadTableHash::GrowTask gt(_local_table);
 142   if (!gt.prepare(jt)) {
 143     return;
 144   }
 145   log_trace(thread, table)("Started to grow");
 146   TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf));
 147   while (gt.do_task(jt)) {
 148     gt.pause(jt);
 149     {
 150       ThreadBlockInVM tbivm(jt);
 151     }
 152     gt.cont(jt);
 153   }
 154   gt.done(jt);
 155   _current_size = table_size();
 156   log_info(thread, table)("Grown to size:" SIZE_FORMAT, _current_size);
 157 }
 158 
 159 class ThreadTableLookup : public StackObj {
 160 private:
 161   jlong _tid;
 162   uintx _hash;
 163 public:
 164   ThreadTableLookup(jlong tid)
 165     : _tid(tid), _hash(primitive_hash(tid)) {}
 166   uintx get_hash() const {
 167     return _hash;
 168   }
 169   bool equals(ThreadTableEntry **value, bool* is_dead) {
 170     bool equals = primitive_equals(_tid, (*value)->tid());
 171     if (!equals) {
 172       return false;
 173     }
 174     return true;
 175   }
 176 };
 177 
 178 class ThreadGet : public StackObj {
 179 private:
 180   JavaThread* _return;
 181 public:
 182   ThreadGet(): _return(NULL) {}
 183   void operator()(ThreadTableEntry** val) {
 184     _return = (*val)->thread();
 185   }
 186   JavaThread* get_res_thread() {
 187     return _return;
 188   }
 189 };
 190 
 191 void ThreadTable::grow_if_required() {
 192   assert(Thread::current()->is_Java_thread(),"Must be Java thread");
 193   assert(_is_initialized, "Thread table is not initialized");
 194   double load_factor = get_load_factor();
 195   log_debug(thread, table)("Concurrent work, load factor: %g", load_factor);
 196   if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
 197     grow(JavaThread::current());
 198   }
 199 }
 200 
 201 JavaThread* ThreadTable::add_thread(jlong tid, JavaThread* java_thread) {
 202   assert(_is_initialized, "Thread table is not initialized");
 203   Thread* thread = Thread::current();
 204   ThreadTableLookup lookup(tid);
 205   ThreadGet tg;
 206   while(true) {
 207     if (_local_table->get(thread, lookup, tg)) {
 208       return tg.get_res_thread();
 209     }
 210     ThreadTableEntry* entry = new ThreadTableEntry(tid, java_thread);
 211     // The hash table takes ownership of the ThreadTableEntry,
 212     // even if it's not inserted.
 213     if (_local_table->insert(thread, lookup, entry)) {
 214       grow_if_required();
 215       return java_thread;
 216     }
 217   }
 218 }
 219 
 220 JavaThread* ThreadTable::find_thread_by_tid(jlong tid) {
 221   assert(_is_initialized, "Thread table is not initialized");
 222   Thread* thread = Thread::current();
 223   ThreadTableLookup lookup(tid);
 224   ThreadGet tg;
 225   _local_table->get(thread, lookup, tg);
 226   return tg.get_res_thread();
 227 }
 228 
 229 bool ThreadTable::remove_thread(jlong tid) {
 230   assert(_is_initialized, "Thread table is not initialized");
 231   Thread* thread = Thread::current();
 232   ThreadTableLookup lookup(tid);
 233   return _local_table->remove(thread, lookup);
 234 }