| /* |
| * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #include "precompiled.hpp" |
| #include "gc/shared/barrierSet.hpp" |
| #include "gc/shared/gcId.hpp" |
| #include "jvm_io.h" |
| #include "runtime/atomic.hpp" |
| #include "runtime/javaThread.hpp" |
| #include "runtime/jniHandles.hpp" |
| #include "runtime/mutexLocker.hpp" |
| #include "runtime/nonJavaThread.hpp" |
| #include "runtime/osThread.hpp" |
| #include "runtime/task.hpp" |
| #include "sanitizers/leak.hpp" |
| #include "utilities/defaultStream.hpp" |
| #include "utilities/singleWriterSynchronizer.hpp" |
| #include "utilities/vmError.hpp" |
| #if INCLUDE_JFR |
| #include "jfr/jfr.hpp" |
| #endif |
| |
| // List of all NonJavaThreads and safe iteration over that list. |
| |
| class NonJavaThread::List { |
| public: |
| NonJavaThread* volatile _head; |
| SingleWriterSynchronizer _protect; |
| |
| List() : _head(nullptr), _protect() {} |
| }; |
| |
| NonJavaThread::List NonJavaThread::_the_list; |
| |
| NonJavaThread::Iterator::Iterator() : |
| _protect_enter(_the_list._protect.enter()), |
| _current(Atomic::load_acquire(&_the_list._head)) |
| {} |
| |
| NonJavaThread::Iterator::~Iterator() { |
| _the_list._protect.exit(_protect_enter); |
| } |
| |
| void NonJavaThread::Iterator::step() { |
| assert(!end(), "precondition"); |
| _current = Atomic::load_acquire(&_current->_next); |
| } |
| |
| NonJavaThread::NonJavaThread() : Thread(), _next(nullptr) { |
| assert(BarrierSet::barrier_set() != nullptr, "NonJavaThread created too soon!"); |
| } |
| |
| NonJavaThread::~NonJavaThread() { } |
| |
| void NonJavaThread::add_to_the_list() { |
| MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag); |
| // Initialize BarrierSet-related data before adding to list. |
| BarrierSet::barrier_set()->on_thread_attach(this); |
| Atomic::release_store(&_next, _the_list._head); |
| Atomic::release_store(&_the_list._head, this); |
| } |
| |
| void NonJavaThread::remove_from_the_list() { |
| { |
| MutexLocker ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag); |
| // Cleanup BarrierSet-related data before removing from list. |
| BarrierSet::barrier_set()->on_thread_detach(this); |
| NonJavaThread* volatile* p = &_the_list._head; |
| for (NonJavaThread* t = *p; t != nullptr; p = &t->_next, t = *p) { |
| if (t == this) { |
| *p = _next; |
| break; |
| } |
| } |
| } |
| // Wait for any in-progress iterators. Concurrent synchronize is not |
| // allowed, so do it while holding a dedicated lock. Outside and distinct |
| // from NJTList_lock in case an iteration attempts to lock it. |
| MutexLocker ml(NonJavaThreadsListSync_lock, Mutex::_no_safepoint_check_flag); |
| _the_list._protect.synchronize(); |
| _next = nullptr; // Safe to drop the link now. |
| } |
| |
| void NonJavaThread::pre_run() { |
| add_to_the_list(); |
| |
| // This is slightly odd in that NamedThread is a subclass, but |
| // in fact name() is defined in Thread |
| assert(this->name() != nullptr, "thread name was not set before it was started"); |
| this->set_native_thread_name(this->name()); |
| } |
| |
| void NonJavaThread::post_run() { |
| JFR_ONLY(Jfr::on_thread_exit(this);) |
| remove_from_the_list(); |
| unregister_thread_stack_with_NMT(); |
| // Ensure thread-local-storage is cleared before termination. |
| Thread::clear_thread_current(); |
| osthread()->set_state(ZOMBIE); |
| } |
| |
| // NamedThread -- non-JavaThread subclasses with multiple |
| // uniquely named instances should derive from this. |
| NamedThread::NamedThread() : |
| NonJavaThread(), |
| _name(nullptr), |
| _processed_thread(nullptr), |
| _gc_id(GCId::undefined()) |
| {} |
| |
| NamedThread::~NamedThread() { |
| FREE_C_HEAP_ARRAY(char, _name); |
| } |
| |
| void NamedThread::set_name(const char* format, ...) { |
| guarantee(_name == nullptr, "Only get to set name once."); |
| _name = NEW_C_HEAP_ARRAY(char, max_name_len, mtThread); |
| va_list ap; |
| va_start(ap, format); |
| jio_vsnprintf(_name, max_name_len, format, ap); |
| va_end(ap); |
| } |
| |
| void NamedThread::print_on(outputStream* st) const { |
| st->print("\"%s\" ", name()); |
| Thread::print_on(st); |
| st->cr(); |
| } |
| |
| |
| // ======= WatcherThread ======== |
| |
| // The watcher thread exists to simulate timer interrupts. It should |
| // be replaced by an abstraction over whatever native support for |
| // timer interrupts exists on the platform. |
| |
| WatcherThread* WatcherThread::_watcher_thread = nullptr; |
| bool WatcherThread::_run_all_tasks = false; |
| volatile bool WatcherThread::_should_terminate = false; |
| |
| WatcherThread::WatcherThread() : NonJavaThread() { |
| assert(watcher_thread() == nullptr, "we can only allocate one WatcherThread"); |
| if (os::create_thread(this, os::watcher_thread)) { |
| _watcher_thread = this; |
| |
| // Set the watcher thread to the highest OS priority which should not be |
| // used, unless a Java thread with priority java.lang.Thread.MAX_PRIORITY |
| // is created. The only normal thread using this priority is the reference |
| // handler thread, which runs for very short intervals only. |
| // If the VMThread's priority is not lower than the WatcherThread profiling |
| // will be inaccurate. |
| os::set_priority(this, MaxPriority); |
| os::start_thread(this); |
| } |
| } |
| |
| int WatcherThread::sleep() const { |
| // The WatcherThread does not participate in the safepoint protocol |
| // for the PeriodicTask_lock because it is not a JavaThread. |
| MonitorLocker ml(PeriodicTask_lock, Mutex::_no_safepoint_check_flag); |
| |
| if (_should_terminate) { |
| // check for termination before we do any housekeeping or wait |
| return 0; // we did not sleep. |
| } |
| |
| if (!_run_all_tasks) { |
| ml.wait(100); |
| return 0; |
| } |
| |
| // remaining will be zero if there are no tasks, |
| // causing the WatcherThread to sleep until a task is |
| // enrolled |
| int remaining = PeriodicTask::time_to_wait(); |
| int time_slept = 0; |
| |
| // we expect this to timeout - we only ever get unparked when |
| // we should terminate or when a new task has been enrolled |
| OSThreadWaitState osts(this->osthread(), false /* not Object.wait() */); |
| |
| jlong time_before_loop = os::javaTimeNanos(); |
| |
| while (true) { |
| bool timedout = ml.wait(remaining); |
| jlong now = os::javaTimeNanos(); |
| |
| if (remaining == 0) { |
| // if we didn't have any tasks we could have waited for a long time |
| // consider the time_slept zero and reset time_before_loop |
| time_slept = 0; |
| time_before_loop = now; |
| } else { |
| // need to recalculate since we might have new tasks in _tasks |
| time_slept = (int) ((now - time_before_loop) / 1000000); |
| } |
| |
| // Change to task list or spurious wakeup of some kind |
| if (timedout || _should_terminate) { |
| break; |
| } |
| |
| remaining = PeriodicTask::time_to_wait(); |
| if (remaining == 0) { |
| // Last task was just disenrolled so loop around and wait until |
| // another task gets enrolled |
| continue; |
| } |
| |
| remaining -= time_slept; |
| if (remaining <= 0) { |
| break; |
| } |
| } |
| |
| return time_slept; |
| } |
| |
| void WatcherThread::run() { |
| assert(this == watcher_thread(), "just checking"); |
| |
| while (true) { |
| assert(watcher_thread() == Thread::current(), "thread consistency check"); |
| assert(watcher_thread() == this, "thread consistency check"); |
| |
| // Calculate how long it'll be until the next PeriodicTask work |
| // should be done, and sleep that amount of time. |
| int time_waited = sleep(); |
| |
| if (VMError::is_error_reported()) { |
| // A fatal error has happened, the error handler(VMError::report_and_die) |
| // should abort JVM after creating an error log file. However in some |
| // rare cases, the error handler itself might deadlock. Here periodically |
| // check for error reporting timeouts, and if it happens, just proceed to |
| // abort the VM. |
| |
| // This code is in WatcherThread because WatcherThread wakes up |
| // periodically so the fatal error handler doesn't need to do anything; |
| // also because the WatcherThread is less likely to crash than other |
| // threads. |
| |
| for (;;) { |
| // Note: we use naked sleep in this loop because we want to avoid using |
| // any kind of VM infrastructure which may be broken at this point. |
| if (VMError::check_timeout()) { |
| // We hit error reporting timeout. Error reporting was interrupted and |
| // will be wrapping things up now (closing files etc). Give it some more |
| // time, then quit the VM. |
| os::naked_short_sleep(200); |
| // Print a message to stderr. |
| fdStream err(defaultStream::output_fd()); |
| err.print_raw_cr("# [ timer expired, abort... ]"); |
| // skip atexit/vm_exit/vm_abort hooks |
| os::die(); |
| } |
| |
| // Wait a bit, then recheck for timeout. |
| os::naked_short_sleep(250); |
| } |
| } |
| |
| if (_should_terminate) { |
| // check for termination before posting the next tick |
| break; |
| } |
| |
| // Don't process enrolled tasks until VM is fully initialized. |
| if (_run_all_tasks) { |
| PeriodicTask::real_time_tick(time_waited); |
| } |
| } |
| |
| // Signal that it is terminated |
| { |
| MutexLocker mu(Terminator_lock, Mutex::_no_safepoint_check_flag); |
| LSAN_IGNORE_OBJECT(_watcher_thread); |
| _watcher_thread = nullptr; |
| Terminator_lock->notify_all(); |
| } |
| } |
| |
| void WatcherThread::start() { |
| MonitorLocker ml(PeriodicTask_lock); |
| _should_terminate = false; |
| // Create the single instance of WatcherThread |
| new WatcherThread(); |
| } |
| |
| void WatcherThread::run_all_tasks() { |
| MonitorLocker ml(PeriodicTask_lock); |
| _run_all_tasks = true; |
| ml.notify(); |
| } |
| |
| void WatcherThread::stop() { |
| { |
| // Follow normal safepoint aware lock enter protocol since the |
| // WatcherThread is stopped by another JavaThread. |
| MutexLocker ml(PeriodicTask_lock); |
| _should_terminate = true; |
| |
| WatcherThread* watcher = watcher_thread(); |
| if (watcher != nullptr) { |
| // unpark the WatcherThread so it can see that it should terminate |
| watcher->unpark(); |
| } |
| } |
| |
| MonitorLocker mu(Terminator_lock); |
| |
| while (watcher_thread() != nullptr) { |
| // This wait should make safepoint checks and wait without a timeout. |
| mu.wait(0); |
| } |
| } |
| |
| void WatcherThread::unpark() { |
| assert(PeriodicTask_lock->owned_by_self(), "PeriodicTask_lock required"); |
| PeriodicTask_lock->notify(); |
| } |
| |
| void WatcherThread::print_on(outputStream* st) const { |
| st->print("\"%s\" ", name()); |
| Thread::print_on(st); |
| st->cr(); |
| } |
| |