Path: blob/master/runtime/gc_realtime/IncrementalParallelTask.cpp
5986 views
/*******************************************************************************1* Copyright (c) 1991, 2020 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "EnvironmentRealtime.hpp"23#include "IncrementalParallelTask.hpp"24#include "ParallelDispatcher.hpp"25#include "Scheduler.hpp"2627#include "ModronAssertions.h"2829void30MM_IncrementalParallelTask::synchronizeGCThreads(MM_EnvironmentBase *envBase, const char *id)31{32MM_EnvironmentRealtime *env = MM_EnvironmentRealtime::getEnvironment(envBase);33if(1 < _totalThreadCount) {3435if (env->isMainThread()) {36/* ignore nested sync points */37if (_entryCount >= 1) {38return;39}40}41omrthread_monitor_enter(_synchronizeMutex);4243/*check synchronization point*/44if (0 ==_synchronizeCount) {45_syncPointUniqueId = id;46} else {47Assert_MM_true(_syncPointUniqueId == id);48}4950_synchronizeCount += 1;5152if(_synchronizeCount == _threadCount) {53_synchronizeCount = 0;54_synchronizeIndex += 1;55/* notify all threads last thread synced */56_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::synchedThreads);57omrthread_monitor_notify_all(_synchronizeMutex);58} else {59volatile uintptr_t index = _synchronizeIndex;6061do {62if (_yieldCollaborator.getYieldCount() + _synchronizeCount >= _threadCount && _yieldCollaborator.getYieldCount() > 0) {63if (env->isMainThread()) {64((MM_Scheduler*)_dispatcher)->condYieldFromGC(env);65} else {66/* notify main last thread synced/yielded */67_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::notifyMain);68omrthread_monitor_notify_all(_synchronizeMutex);69}70}7172/* A worker is only interested in synchedThreads event. For any other events it remains to be blocked */73/* We check synchronizeIndex, so we can exit this iteration ASAP before synchedThreads is overwritten by another event in the next iteration74* (We may be overly cautious here, since we are not that sure that overlap between iterations may even happen)75*/76do {77env->reportScanningSuspended();78omrthread_monitor_wait(_synchronizeMutex);79env->reportScanningResumed();80} while ((index == _synchronizeIndex) && !env->isMainThread() && (_yieldCollaborator.getResumeEvent() != MM_YieldCollaborator::synchedThreads));8182} while(index == _synchronizeIndex);83}84omrthread_monitor_exit(_synchronizeMutex);85}86}8788bool89MM_IncrementalParallelTask::synchronizeGCThreadsAndReleaseMain(MM_EnvironmentBase *envBase, const char *id)90{91MM_EnvironmentRealtime *env = MM_EnvironmentRealtime::getEnvironment(envBase);92bool isMainThread = false;9394if(1 < _totalThreadCount) {95volatile uintptr_t index = _synchronizeIndex;9697if (env->isMainThread()) {98/* This function only has to be re-entrant for the main thread */99_entryCount += 1;100if (_entryCount > 1) {101isMainThread = true;102goto done;103}104}105106omrthread_monitor_enter(_synchronizeMutex);107108/*check synchronization point*/109if (0 == _synchronizeCount) {110_syncPointUniqueId = id;111} else {112Assert_MM_true(_syncPointUniqueId == id);113}114115_synchronizeCount += 1;116if(_synchronizeCount == _threadCount) {117if(env->isMainThread()) {118omrthread_monitor_exit(_synchronizeMutex);119isMainThread = true;120_synchronized = true;121goto done;122}123/* notify main last thread synced */124_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::notifyMain);125omrthread_monitor_notify_all(_synchronizeMutex);126}127128while(index == _synchronizeIndex) {129if(env->isMainThread() && (_synchronizeCount == _threadCount)) {130omrthread_monitor_exit(_synchronizeMutex);131isMainThread = true;132_synchronized = true;133goto done;134}135136if ((_yieldCollaborator.getYieldCount() + _synchronizeCount >= _threadCount) && (_yieldCollaborator.getYieldCount() > 0)) {137if (env->isMainThread()) {138((MM_Scheduler*)_dispatcher)->condYieldFromGC(env);139} else {140/* notify main last thread synced/yielded */141_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::notifyMain);142omrthread_monitor_notify_all(_synchronizeMutex);143}144}145146/* A worker is only interested in synchedThreads event. For any other events it remains to be blocked */147/* We check synchronizeIndex, so we can exit this iteration ASAP before synchedThreads is overwritten by another event in the next iteration148* (We may be overly cautious here, since we are not that sure that overlap between iterations may even happen)149*/150do {151env->reportScanningSuspended();152omrthread_monitor_wait(_synchronizeMutex);153env->reportScanningResumed();154} while ((index == _synchronizeIndex) && !env->isMainThread() && (_yieldCollaborator.getResumeEvent() != MM_YieldCollaborator::synchedThreads));155}156omrthread_monitor_exit(_synchronizeMutex);157} else {158isMainThread = true;159}160161done:162return isMainThread;163}164165bool166MM_IncrementalParallelTask::synchronizeGCThreadsAndReleaseSingleThread(MM_EnvironmentBase *env, const char *id)167{168/* this task doesn't support synchronizeGCThreadsAndReleaseSingleThread currently */169Assert_MM_unreachable();170/* TODO if implementing make sure to fix the isMain check in releaseSynchronizedGCThreads */171return MM_ParallelTask::synchronizeGCThreadsAndReleaseSingleThread(env, id);172}173174void175MM_IncrementalParallelTask::releaseSynchronizedGCThreads(MM_EnvironmentBase *env)176{177if(1 == _totalThreadCount) {178return;179}180181if(env->isMainThread()) {182/* sync/release sequence actually takes time (excluding the work within the sync/release pair).183* Take advantage of the fact the all workers are blocked to check if it is time to yield */184((MM_Scheduler*)_dispatcher)->condYieldFromGC(env);185186/* Could not have gotten here unless all other threads are sync'd - don't check, just release */187_entryCount -= 1;188if (_entryCount == 0) {189_synchronized = false;190omrthread_monitor_enter(_synchronizeMutex);191_synchronizeCount = 0;192_synchronizeIndex += 1;193_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::synchedThreads);194omrthread_monitor_notify_all(_synchronizeMutex);195omrthread_monitor_exit(_synchronizeMutex);196}197}198}199200201