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 "services/threadTable.hpp"
  31 #include "utilities/concurrentHashTable.inline.hpp"
  32 #include "utilities/concurrentHashTableTasks.inline.hpp"
  33 
  34 
  35 // 2^24 is max size
  36 static const size_t END_SIZE = 24;
  37 // Initial size 256
  38 static const size_t ThreadTableSizeLog = 8;
  39 // Prefer short chains of avg 2
  40 static const double PREF_AVG_LIST_LEN = 2.0;
  41 
  42 typedef ConcurrentHashTable<ThreadTableConfig, mtInternal> ThreadTableHash;
  43 
  44 static ThreadTableHash* _local_table = NULL;
  45 
  46 volatile bool ThreadTable::_has_work = false;
  47 
  48 static volatile size_t _current_size = 0;
  49 static volatile size_t _items_count = 0;
  50 
  51 
  52 class ThreadTableEntry : public CHeapObj<mtInternal> {
  53   private:
  54     jlong _tid;
  55     JavaThread* _java_thread;
  56   public:
  57     ThreadTableEntry(jlong tid, JavaThread* java_thread) :
  58     _tid(tid),_java_thread(java_thread) {}
  59 
  60     jlong tid() const { return _tid;}
  61     JavaThread* thread() const {return _java_thread;}
  62 };
  63 
  64 class ThreadTableConfig : public AllStatic {
  65   public:
  66     typedef ThreadTableEntry* Value;
  67 
  68     static uintx get_hash(Value const& value, bool* is_dead) {
  69       *is_dead = false;
  70       jlong tid = value->tid();
  71       return primitive_hash(tid);
  72     }
  73     static void* allocate_node(size_t size, Value const& value) {
  74       ThreadTable::item_added();
  75       return AllocateHeap(size, mtInternal);
  76     }
  77     static void free_node(void* memory, Value const& value) {
  78       delete value;
  79       FreeHeap(memory);
  80       ThreadTable::item_removed();
  81     }
  82 };
  83 
  84 void ThreadTable::create_table() {
  85   _current_size = (size_t)1 << ThreadTableSizeLog;
  86   _local_table = new ThreadTableHash(ThreadTableSizeLog, END_SIZE);
  87 }
  88 
  89 void ThreadTable::item_added() {
  90   Atomic::inc(&_items_count);
  91   log_trace(thread, table) ("Thread entry added");
  92 }
  93 
  94 void ThreadTable::item_removed() {
  95   Atomic::dec(&_items_count);
  96   log_trace(thread, table) ("Thread entry removed");
  97 }
  98 
  99 double ThreadTable::get_load_factor() {
 100   return (double)_items_count/_current_size;
 101 }
 102 
 103 size_t ThreadTable::table_size() {
 104   return (size_t)1 << _local_table->get_size_log2(Thread::current());
 105 }
 106 
 107 void ThreadTable::check_concurrent_work() {
 108   if (_has_work) {
 109     return;
 110   }
 111     
 112   double load_factor = get_load_factor();
 113   // Resize if we have more items than preferred load factor
 114   if (load_factor > PREF_AVG_LIST_LEN) {
 115     log_debug(thread, table)("Concurrent work triggered, load factor: %g",
 116                              load_factor);
 117     trigger_concurrent_work();
 118   }
 119 }
 120 
 121 void ThreadTable::trigger_concurrent_work() {
 122   MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
 123   _has_work = true;
 124   Service_lock->notify_all();
 125 }
 126 
 127 void ThreadTable::do_concurrent_work(JavaThread* jt) {
 128   _has_work = false;
 129   double load_factor = get_load_factor();
 130   log_debug(thread, table)("Concurrent work, load factor: %g", load_factor);
 131   if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
 132     grow(jt);
 133   }
 134 }
 135 
 136 void ThreadTable::grow(JavaThread* jt) {
 137   ThreadTableHash::GrowTask gt(_local_table);
 138   if (!gt.prepare(jt)) {
 139     return;
 140   }
 141   log_trace(thread, table)("Started to grow");
 142   TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf));
 143   while (gt.do_task(jt)) {
 144     gt.pause(jt);
 145     {
 146       ThreadBlockInVM tbivm(jt);
 147     }
 148     gt.cont(jt);
 149   }
 150   gt.done(jt);
 151   _current_size = table_size();
 152   log_info(thread, table)("Grown to size:" SIZE_FORMAT, _current_size);
 153 }
 154 
 155 class ThreadTableLookup : public StackObj {
 156   private:
 157     jlong          _tid;
 158     uintx         _hash;
 159   public:
 160     ThreadTableLookup(jlong tid)
 161     : _tid(tid), _hash(primitive_hash(tid)) {}
 162     uintx get_hash() const {
 163       return _hash;
 164     }
 165     bool equals(ThreadTableEntry **value, bool* is_dead) {
 166       *is_dead = false;
 167       bool equals = primitive_equals(_tid, (*value)->tid());
 168       if (!equals) {
 169         return false;
 170       }
 171       return true;
 172     }
 173 };
 174 
 175 class ThreadGet : public StackObj {
 176   private:
 177     JavaThread* _return;
 178   public:
 179     ThreadGet():_return(NULL) {}
 180     void operator()(ThreadTableEntry** val) {
 181       _return = (*val)->thread();
 182     }
 183     JavaThread* get_res_thread() {
 184       return _return;
 185     }
 186 };
 187 
 188 JavaThread* ThreadTable::find_thread_by_tid(jlong tid) {
 189   Thread* thread = Thread::current();
 190   ThreadTableLookup lookup(tid);
 191   ThreadGet tg;
 192   _local_table->get(thread, lookup, tg);
 193   return tg.get_res_thread();
 194 }
 195 
 196 
 197 JavaThread* ThreadTable::add_thread(jlong tid, JavaThread* java_thread) {
 198   Thread* thread = Thread::current();
 199   ThreadTableLookup lookup(tid);
 200   ThreadGet tg;
 201   while(true) {
 202     if (_local_table->get(thread, lookup, tg)) {
 203       return tg.get_res_thread();
 204     }
 205     ThreadTableEntry* entry = new ThreadTableEntry(tid,java_thread);
 206     // The hash table takes ownership of the ThreadTableEntry,
 207     // even if it's not inserted.
 208     if (_local_table->insert(thread, lookup, entry)) {
 209       check_concurrent_work();
 210       return java_thread;
 211     }
 212   }
 213 }
 214 
 215 bool ThreadTable::remove_thread(jlong tid) {
 216   Thread* thread = Thread::current();
 217   ThreadTableLookup lookup(tid);
 218   return _local_table->remove(thread,lookup);
 219 }