| /* | |
| * Copyright (c) 2002, 2021, 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_WORKERUTILS_HPP | |
| #define SHARE_GC_SHARED_WORKERUTILS_HPP | |
| #include "memory/allocation.hpp" | |
| #include "metaprogramming/enableIf.hpp" | |
| #include "metaprogramming/logical.hpp" | |
| #include "runtime/mutex.hpp" | |
| #include "utilities/debug.hpp" | |
| #include "utilities/globalDefinitions.hpp" | |
| // A class that acts as a synchronisation barrier. Workers enter | |
| // the barrier and must wait until all other workers have entered | |
| // before any of them may leave. | |
| class WorkerThreadsBarrierSync : public StackObj { | |
| protected: | |
| Monitor _monitor; | |
| uint _n_workers; | |
| uint _n_completed; | |
| bool _should_reset; | |
| bool _aborted; | |
| Monitor* monitor() { return &_monitor; } | |
| uint n_workers() { return _n_workers; } | |
| uint n_completed() { return _n_completed; } | |
| bool should_reset() { return _should_reset; } | |
| bool aborted() { return _aborted; } | |
| void zero_completed() { _n_completed = 0; } | |
| void inc_completed() { _n_completed++; } | |
| void set_aborted() { _aborted = true; } | |
| void set_should_reset(bool v) { _should_reset = v; } | |
| public: | |
| WorkerThreadsBarrierSync(); | |
| // Set the number of workers that will use the barrier. | |
| // Must be called before any of the workers start running. | |
| void set_n_workers(uint n_workers); | |
| // Enter the barrier. A worker that enters the barrier will | |
| // not be allowed to leave until all other threads have | |
| // also entered the barrier or the barrier is aborted. | |
| // Returns false if the barrier was aborted. | |
| bool enter(); | |
| // Aborts the barrier and wakes up any threads waiting for | |
| // the barrier to complete. The barrier will remain in the | |
| // aborted state until the next call to set_n_workers(). | |
| void abort(); | |
| }; | |
| // A class to manage claiming of subtasks within a group of tasks. The | |
| // subtasks will be identified by integer indices, usually elements of an | |
| // enumeration type. | |
| class SubTasksDone: public CHeapObj<mtInternal> { | |
| volatile bool* _tasks; | |
| uint _n_tasks; | |
| // make sure verification logic is run exactly once to avoid duplicate assertion failures | |
| DEBUG_ONLY(volatile bool _verification_done = false;) | |
| void all_tasks_claimed_impl(uint skipped[], size_t skipped_size) NOT_DEBUG_RETURN; | |
| NONCOPYABLE(SubTasksDone); | |
| public: | |
| // Initializes "this" to a state in which there are "n" tasks to be | |
| // processed, none of the which are originally claimed. | |
| SubTasksDone(uint n); | |
| // Attempt to claim the task "t", returning true if successful, | |
| // false if it has already been claimed. The task "t" is required | |
| // to be within the range of "this". | |
| bool try_claim_task(uint t); | |
| // The calling thread asserts that it has attempted to claim all the tasks | |
| // that it will try to claim. Tasks that are meant to be skipped must be | |
| // explicitly passed as extra arguments. Every thread in the parallel task | |
| // must execute this. | |
| template<typename T0, typename... Ts, | |
| ENABLE_IF(Conjunction<std::is_same<T0, Ts>...>::value)> | |
| void all_tasks_claimed(T0 first_skipped, Ts... more_skipped) { | |
| static_assert(std::is_convertible<T0, uint>::value, "not convertible"); | |
| uint skipped[] = { static_cast<uint>(first_skipped), static_cast<uint>(more_skipped)... }; | |
| all_tasks_claimed_impl(skipped, ARRAY_SIZE(skipped)); | |
| } | |
| // if there are no skipped tasks. | |
| void all_tasks_claimed() { | |
| all_tasks_claimed_impl(nullptr, 0); | |
| } | |
| // Destructor. | |
| ~SubTasksDone(); | |
| }; | |
| // As above, but for sequential tasks, i.e. instead of claiming | |
| // sub-tasks from a set (possibly an enumeration), claim sub-tasks | |
| // in sequential order. This is ideal for claiming dynamically | |
| // partitioned tasks (like striding in the parallel remembered | |
| // set scanning). | |
| class SequentialSubTasksDone : public CHeapObj<mtInternal> { | |
| uint _num_tasks; // Total number of tasks available. | |
| volatile uint _num_claimed; // Number of tasks claimed. | |
| NONCOPYABLE(SequentialSubTasksDone); | |
| public: | |
| SequentialSubTasksDone(uint num_tasks) : _num_tasks(num_tasks), _num_claimed(0) { } | |
| ~SequentialSubTasksDone() { | |
| // Claiming may try to claim more tasks than there are. | |
| assert(_num_claimed >= _num_tasks, "Claimed %u tasks of %u", _num_claimed, _num_tasks); | |
| } | |
| // Attempt to claim the next unclaimed task in the sequence, | |
| // returning true if successful, with t set to the index of the | |
| // claimed task. Returns false if there are no more unclaimed tasks | |
| // in the sequence. In this case t is undefined. | |
| bool try_claim_task(uint& t); | |
| }; | |
| #endif // SHARE_GC_SHARED_WORKERUTILS_HPP |