| /* |
| * Copyright (c) 1997, 2022, 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. |
| * |
| */ |
| |
| #ifndef SHARE_RUNTIME_SAFEPOINT_HPP |
| #define SHARE_RUNTIME_SAFEPOINT_HPP |
| |
| #include "memory/allStatic.hpp" |
| #include "runtime/javaThread.hpp" |
| #include "runtime/os.hpp" |
| #include "runtime/vmOperation.hpp" |
| #include "utilities/ostream.hpp" |
| #include "utilities/waitBarrier.hpp" |
| |
| // |
| // Safepoint synchronization |
| //// |
| // The VMThread uses the SafepointSynchronize::begin/end |
| // methods to enter/exit a safepoint region. The begin method will roll |
| // all JavaThreads forward to a safepoint. |
| // |
| // JavaThreads must use the ThreadSafepointState abstraction (defined in |
| // thread.hpp) to indicate that that they are at a safepoint. |
| // |
| // The Mutex/Condition variable and ObjectLocker classes calls the enter/ |
| // exit safepoint methods, when a thread is blocked/restarted. Hence, all mutex exter/ |
| // exit points *must* be at a safepoint. |
| |
| class ThreadSafepointState; |
| |
| class SafepointStateTracker { |
| uint64_t _safepoint_id; |
| bool _at_safepoint; |
| public: |
| SafepointStateTracker(uint64_t safepoint_id, bool at_safepoint); |
| bool safepoint_state_changed(); |
| }; |
| |
| // |
| // Implements roll-forward to safepoint (safepoint synchronization) |
| // |
| class SafepointSynchronize : AllStatic { |
| public: |
| enum SynchronizeState { |
| _not_synchronized = 0, // Threads not synchronized at a safepoint. Keep this value 0. |
| _synchronizing = 1, // Synchronizing in progress |
| _synchronized = 2 // All Java threads are running in native, blocked in OS or stopped at safepoint. |
| // VM thread and any NonJavaThread may be running. |
| }; |
| |
| // The enums are listed in the order of the tasks when done serially. |
| enum SafepointCleanupTasks { |
| SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING, |
| SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES, |
| SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH, |
| SAFEPOINT_CLEANUP_STRING_TABLE_REHASH, |
| SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP, |
| // Leave this one last. |
| SAFEPOINT_CLEANUP_NUM_TASKS |
| }; |
| |
| private: |
| friend class SafepointMechanism; |
| friend class ThreadSafepointState; |
| friend class HandshakeState; |
| friend class SafepointStateTracker; |
| |
| // Threads might read this flag directly, without acquiring the Threads_lock: |
| static volatile SynchronizeState _state; |
| // Number of threads we are waiting for to block: |
| static int _waiting_to_block; |
| // Counts the number of active critical natives during the safepoint: |
| static int _current_jni_active_count; |
| |
| // This counter is used for fast versions of jni_Get<Primitive>Field. |
| // An even value means there are no ongoing safepoint operations. |
| // The counter is incremented ONLY at the beginning and end of each |
| // safepoint. |
| static volatile uint64_t _safepoint_counter; |
| |
| // A change in this counter or a change in the result of |
| // is_at_safepoint() are used by SafepointStateTracker:: |
| // safepoint_state_changed() to determine its answer. |
| static uint64_t _safepoint_id; |
| |
| // JavaThreads that need to block for the safepoint will stop on the |
| // _wait_barrier, where they can quickly be started again. |
| static WaitBarrier* _wait_barrier; |
| static julong _coalesced_vmop_count; // coalesced vmop count |
| |
| // For debug long safepoint |
| static void print_safepoint_timeout(); |
| |
| // Helper methods for safepoint procedure: |
| static void arm_safepoint(); |
| static int synchronize_threads(jlong safepoint_limit_time, int nof_threads, int* initial_running); |
| static void disarm_safepoint(); |
| static void increment_jni_active_count(); |
| static void decrement_waiting_to_block(); |
| static bool thread_not_running(ThreadSafepointState *cur_state); |
| |
| // Used in safepoint_safe to do a stable load of the thread state. |
| static bool try_stable_load_state(JavaThreadState *state, |
| JavaThread *thread, |
| uint64_t safepoint_count); |
| |
| // Called when a thread voluntarily blocks |
| static void block(JavaThread *thread); |
| |
| // Called from VMThread during handshakes. |
| // If true the VMThread may safely process the handshake operation for the JavaThread. |
| static bool handshake_safe(JavaThread *thread); |
| |
| static uint64_t safepoint_counter() { return _safepoint_counter; } |
| |
| public: |
| |
| static void init(Thread* vmthread); |
| |
| // Roll all threads forward to safepoint. Must be called by the VMThread. |
| static void begin(); |
| static void end(); // Start all suspended threads again... |
| |
| // The value for a not set safepoint id. |
| static const uint64_t InactiveSafepointCounter; |
| |
| // Query |
| static bool is_at_safepoint() { return _state == _synchronized; } |
| static bool is_synchronizing() { return _state == _synchronizing; } |
| |
| static uint64_t safepoint_id() { |
| return _safepoint_id; |
| } |
| |
| static SafepointStateTracker safepoint_state_tracker() { |
| return SafepointStateTracker(safepoint_id(), is_at_safepoint()); |
| } |
| |
| // Exception handling for page polling |
| static void handle_polling_page_exception(JavaThread *thread); |
| |
| static bool is_cleanup_needed(); |
| static void do_cleanup_tasks(); |
| |
| static void set_is_at_safepoint() { _state = _synchronized; } |
| static void set_is_not_at_safepoint() { _state = _not_synchronized; } |
| |
| // Only used for making sure that no safepoint has happened in |
| // JNI_FastGetField. Therefore only the low 32-bits are needed |
| // even if this is a 64-bit counter. |
| static address safepoint_counter_addr() { |
| #ifdef VM_LITTLE_ENDIAN |
| return (address)&_safepoint_counter; |
| #else /* BIG */ |
| // Return pointer to the 32 LSB: |
| return (address) (((uint32_t*)(&_safepoint_counter)) + 1); |
| #endif |
| } |
| }; |
| |
| // Some helper assert macros for safepoint checks. |
| |
| #define assert_at_safepoint() \ |
| assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint") |
| |
| #define assert_at_safepoint_msg(...) \ |
| assert(SafepointSynchronize::is_at_safepoint(), __VA_ARGS__) |
| |
| #define assert_not_at_safepoint() \ |
| assert(!SafepointSynchronize::is_at_safepoint(), "should not be at a safepoint") |
| |
| #define assert_not_at_safepoint_msg(...) \ |
| assert(!SafepointSynchronize::is_at_safepoint(), __VA_ARGS__) |
| |
| // State class for a thread suspended at a safepoint |
| class ThreadSafepointState: public CHeapObj<mtThread> { |
| private: |
| // At polling page safepoint (NOT a poll return safepoint): |
| volatile bool _at_poll_safepoint; |
| JavaThread* _thread; |
| bool _safepoint_safe; |
| volatile uint64_t _safepoint_id; |
| |
| ThreadSafepointState* _next; |
| |
| void account_safe_thread(); |
| |
| public: |
| ThreadSafepointState(JavaThread *thread); |
| |
| // Linked list support: |
| ThreadSafepointState* get_next() const { return _next; } |
| void set_next(ThreadSafepointState* value) { _next = value; } |
| ThreadSafepointState** next_ptr() { return &_next; } |
| |
| // examine/restart |
| void examine_state_of_thread(uint64_t safepoint_count); |
| void restart(); |
| |
| // Query |
| JavaThread* thread() const { return _thread; } |
| bool is_running() const { return !_safepoint_safe; } |
| |
| uint64_t get_safepoint_id() const; |
| void reset_safepoint_id(); |
| void set_safepoint_id(uint64_t sid); |
| |
| // Support for safepoint timeout (debugging) |
| bool is_at_poll_safepoint() { return _at_poll_safepoint; } |
| void set_at_poll_safepoint(bool val) { _at_poll_safepoint = val; } |
| |
| void handle_polling_page_exception(); |
| |
| // debugging |
| void print_on(outputStream* st) const; |
| |
| // Initialize |
| static void create(JavaThread *thread); |
| static void destroy(JavaThread *thread); |
| }; |
| |
| class SafepointTracing : public AllStatic { |
| private: |
| // Absolute |
| static jlong _last_safepoint_begin_time_ns; |
| static jlong _last_safepoint_sync_time_ns; |
| static jlong _last_safepoint_cleanup_time_ns; |
| static jlong _last_safepoint_end_time_ns; |
| |
| // Relative |
| static jlong _last_app_time_ns; |
| |
| static int _nof_threads; |
| static int _nof_running; |
| static int _page_trap; |
| |
| static VM_Operation::VMOp_Type _current_type; |
| static jlong _max_sync_time; |
| static jlong _max_cleanup_time; |
| static jlong _max_vmop_time; |
| static uint64_t _op_count[VM_Operation::VMOp_Terminating]; |
| |
| static void statistics_log(); |
| |
| public: |
| static void init(); |
| |
| static void begin(VM_Operation::VMOp_Type type); |
| static void synchronized(int nof_threads, int nof_running, int traps); |
| static void cleanup(); |
| static void end(); |
| |
| static void statistics_exit_log(); |
| |
| static jlong time_since_last_safepoint_ms() { |
| return nanos_to_millis(os::javaTimeNanos() - _last_safepoint_end_time_ns); |
| } |
| |
| static jlong end_of_last_safepoint_ms() { |
| return nanos_to_millis(_last_safepoint_end_time_ns); |
| } |
| |
| static jlong start_of_safepoint() { |
| return _last_safepoint_begin_time_ns; |
| } |
| }; |
| |
| #endif // SHARE_RUNTIME_SAFEPOINT_HPP |