| /* |
| * Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved. |
| * Copyright (c) 2020, 2024, 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_GC_SHARED_TASKTERMINATOR_HPP |
| #define SHARE_GC_SHARED_TASKTERMINATOR_HPP |
| |
| #include "memory/allocation.hpp" |
| #include "memory/padded.hpp" |
| #include "runtime/mutex.hpp" |
| |
| class TaskQueueSetSuper; |
| class TerminatorTerminator; |
| class Thread; |
| |
| /* |
| * Provides a task termination protocol. |
| * |
| * This is an enhanced implementation of Google's OWST work stealing task termination |
| * protocol (OWST stands for Optimized Work Stealing Threads). |
| * |
| * It is described in the paper: |
| * "Wessam Hassanein. 2016. Understanding and improving JVM GC work |
| * stealing at the data center scale. In Proceedings of the 2016 ACM |
| * SIGPLAN International Symposium on Memory Management (ISMM 2016). ACM, |
| * New York, NY, USA, 46-54. DOI: https://doi.org/10.1145/2926697.2926706" |
| * |
| * Instead of a dedicated spin-master, our implementation will let spin-master |
| * relinquish the role before it goes to sleep/wait, allowing newly arrived |
| * threads to compete for the role. |
| * The intention of above enhancement is to reduce spin-master's latency on |
| * detecting new tasks for stealing and termination condition. |
| */ |
| class TaskTerminator : public CHeapObj<mtGC> { |
| class DelayContext { |
| uint _yield_count; |
| // Number of hard spin loops done since last yield |
| uint _hard_spin_count; |
| // Number of iterations in the current hard spin loop. |
| uint _hard_spin_limit; |
| |
| void reset_hard_spin_information(); |
| public: |
| DelayContext(); |
| |
| // Should the caller sleep (wait) or perform a spin step? |
| bool needs_sleep() const; |
| // Perform one delay iteration. |
| void do_step(); |
| }; |
| |
| uint _n_threads; |
| TaskQueueSetSuper* _queue_set; |
| |
| DEFINE_PAD_MINUS_SIZE(0, DEFAULT_PADDING_SIZE, 0); |
| volatile uint _offered_termination; |
| DEFINE_PAD_MINUS_SIZE(1, DEFAULT_PADDING_SIZE, sizeof(volatile uint)); |
| |
| Monitor _blocker; |
| Thread* _spin_master; |
| |
| void assert_queue_set_empty() const NOT_DEBUG_RETURN; |
| |
| // Prepare for return from offer_termination. Gives up the spin master token |
| // and wakes up up to tasks threads waiting on _blocker (the default value |
| // means to wake up everyone). |
| void prepare_for_return(Thread* this_thread, size_t tasks = SIZE_MAX); |
| |
| // If we should exit current termination protocol |
| bool exit_termination(size_t tasks, TerminatorTerminator* terminator); |
| |
| size_t tasks_in_queue_set() const; |
| |
| NONCOPYABLE(TaskTerminator); |
| |
| public: |
| TaskTerminator(uint n_threads, TaskQueueSetSuper* queue_set); |
| ~TaskTerminator(); |
| |
| // The current thread has no work, and is ready to terminate if everyone |
| // else is. If returns "true", all threads are terminated. If returns |
| // "false", available work has been observed in one of the task queues, |
| // so the global task is not complete. |
| bool offer_termination() { |
| return offer_termination(nullptr); |
| } |
| |
| // As above, but it also terminates if the should_exit_termination() |
| // method of the terminator parameter returns true. If terminator is |
| // null, then it is ignored. |
| bool offer_termination(TerminatorTerminator* terminator); |
| |
| // Reset the terminator, so that it may be reused again. |
| // The caller is responsible for ensuring that this is done |
| // in an MT-safe manner, once the previous round of use of |
| // the terminator is finished. |
| void reset_for_reuse(); |
| // Same as above but the number of parallel threads is set to the |
| // given number. |
| void reset_for_reuse(uint n_threads); |
| }; |
| |
| #endif // SHARE_GC_SHARED_TASKTERMINATOR_HPP |