| /* | |
| * 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 |