/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "utilities/workgroup.hpp"
// Definitions of WorkGang methods.
bool are_GC_task_threads,
bool are_ConcurrentGC_threads) :
"They cannot both be STW GC and Concurrent threads" );
// Other initialization.
/* name */ "WorkGroup monitor",
/* allow_vm_block */ are_GC_task_threads);
_terminate = false;
_sequence_number = 0;
_started_workers = 0;
_finished_workers = 0;
}
bool are_GC_task_threads,
bool are_ConcurrentGC_threads) :
}
return new_worker;
}
// The current implementation will exit if the allocation
// of any worker fails. Still, return a boolean so that
// a future implementation can possibly do a partial
// initialization of the workers and report such to the
// caller.
if (TraceWorkGang) {
name(),
total_workers());
}
if (gang_workers() == NULL) {
vm_exit_out_of_memory(0, "Cannot create GangWorker array.");
return false;
}
if (are_ConcurrentGC_threads()) {
} else {
}
vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
return false;
}
if (!DisableStartThread) {
}
}
return true;
}
if (TraceWorkGang) {
}
stop(); // stop all the workers
delete gang_worker(worker);
}
delete gang_workers();
delete monitor();
}
// Array index bounds checking.
result = _gang_workers[i];
return result;
}
}
// This thread is executed by the VM thread which does not block
// on ordinary MutexLocker's.
if (TraceWorkGang) {
}
// Tell all the workers to run a task.
// Initialize.
_sequence_number += 1;
_started_workers = 0;
_finished_workers = 0;
// Tell the workers to get to work.
monitor()->notify_all();
// Wait for them to be finished
while (finished_workers() < no_of_parallel_workers) {
if (TraceWorkGang) {
}
}
if (TraceWorkGang) {
}
}
// If active_workers() is passed, _finished_workers
// must only be incremented for workers that find non_null
// work (as opposed to all those that just check that the
// task is not null).
}
// Tell all workers to terminate, then wait for them to become inactive.
if (TraceWorkGang) {
}
_terminate = true;
monitor()->notify_all();
while (finished_workers() < active_workers()) {
if (TraceWorkGang) {
}
}
}
}
_started_workers += 1;
}
_finished_workers += 1;
}
}
}
}
}
// GangWorker methods.
}
initialize();
loop();
}
this->initialize_thread_local_storage();
this->record_stack_base_and_size();
if (TraceWorkGang) {
}
// The VM thread should not execute here because MutexLocker's are used
// as (opposed to MutexLockerEx's).
" of a work gang");
}
int previous_sequence_number = 0;
for ( ; /* !terminate() */; ) {
{
// Grab the gang mutex.
// Wait for something to do.
// Polling outside the while { wait } avoids missed notifies
// in the outer loop.
if (TraceWorkGang) {
} else {
}
}
for ( ; /* break or return */; ) {
// Terminate if requested.
gang()->internal_note_finish();
return;
}
// Check for new work.
if (gang()->needs_more_workers()) {
gang()->internal_note_start();
break;
}
}
// Nothing to do.
if (TraceWorkGang) {
} else {
}
}
}
// Drop gang mutex.
}
if (TraceWorkGang) {
}
{
if (TraceWorkGang) {
}
// Grab the gang mutex.
gang()->internal_note_finish();
// Tell the gang you are done.
// Drop the gang mutex.
}
}
}
return gang()->are_GC_task_threads();
}
return gang()->are_ConcurrentGC_threads();
}
}
// Printing methods
return _name;
}
#ifndef PRODUCT
return _name;
}
#endif /* PRODUCT */
// FlexibleWorkGang
// *** WorkGangBarrierSync
}
}
_n_completed = 0;
_should_reset = false;
}
if (should_reset()) {
// The should_reset() was set and we are the first worker to enter
// the sync barrier. We will zero the n_completed() count which
// effectively resets the barrier.
set_should_reset(false);
}
if (n_completed() == n_workers()) {
// At this point we would like to reset the barrier to be ready in
// case it is used again. However, we cannot set n_completed() to
// 0, even after the notify_all(), given that some other workers
// might still be waiting for n_completed() to become ==
// n_workers(). So, if we set n_completed() to 0, those workers
// will get stuck (as they will wake up, see that n_completed() !=
// n_workers() and go back to sleep). Instead, we raise the
// should_reset() flag and the barrier will be reset the first
// time a worker enters it again.
set_should_reset(true);
monitor()->notify_all();
} else {
while (n_completed() != n_workers()) {
}
}
}
// SubTasksDone functions.
clear();
}
}
"should not be called while tasks are being processed!");
_n_threads = (t == 0 ? 1 : t);
}
_tasks[i] = 0;
}
_threads_completed = 0;
#ifdef ASSERT
_claimed = 0;
#endif
}
if (old == 0) {
}
#ifdef ASSERT
if (!res) {
}
#endif
return res;
}
void SubTasksDone::all_tasks_completed() {
do {
// If this was the last thread checking in, clear the tasks.
}
SubTasksDone::~SubTasksDone() {
}
// *** SequentialSubTasksDone
void SequentialSubTasksDone::clear() {
_n_tasks = _n_claimed = 0;
_n_threads = _n_completed = 0;
}
bool SequentialSubTasksDone::valid() {
return _n_threads > 0;
}
t = *n_claimed_ptr;
while (t < _n_tasks) {
return false;
}
t = *n_claimed_ptr;
}
return true;
}
bool SequentialSubTasksDone::all_tasks_completed() {
while (true) {
break;
}
}
clear();
return true;
}
return false;
}
bool FreeIdSet::_stat_init = false;
bool FreeIdSet::_safepoint;
{
if (_stat_init) {
_stat_init = true;
}
// Add to sets. (This should happen while the system is still single-threaded.)
for (int j = 0; j < NSets; j++) {
_sets[j] = this;
_index = j;
break;
}
}
}
}
void FreeIdSet::set_safepoint(bool b) {
_safepoint = b;
if (b) {
for (int j = 0; j < NSets; j++) {
mon->notify_all();
}
}
}
}
#define FID_STATS 0
int FreeIdSet::claim_par_id() {
#if FID_STATS
#endif
_waiters++;
#if FID_STATS
if (_waiters > 5) {
}
#endif
_waiters--;
}
if (_hd == end_of_list) {
#if FID_STATS
#endif
return -1;
} else {
_claimed++;
#if FID_STATS
#endif
return res;
}
}
bool FreeIdSet::claim_perm_id(int i) {
int prev = end_of_list;
while (cur != end_of_list) {
if (cur == i) {
if (prev == end_of_list) {
} else {
}
_claimed++;
return true;
} else {
}
}
return false;
}
_claimed--;
#if FID_STATS
#endif
if (_waiters > 0)
// Notify all would be safer, but this is OK, right?
_mon->notify_all();
}