Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_realtime/IncrementalParallelTask.cpp
5986 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2020 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#include "EnvironmentRealtime.hpp"
24
#include "IncrementalParallelTask.hpp"
25
#include "ParallelDispatcher.hpp"
26
#include "Scheduler.hpp"
27
28
#include "ModronAssertions.h"
29
30
void
31
MM_IncrementalParallelTask::synchronizeGCThreads(MM_EnvironmentBase *envBase, const char *id)
32
{
33
MM_EnvironmentRealtime *env = MM_EnvironmentRealtime::getEnvironment(envBase);
34
if(1 < _totalThreadCount) {
35
36
if (env->isMainThread()) {
37
/* ignore nested sync points */
38
if (_entryCount >= 1) {
39
return;
40
}
41
}
42
omrthread_monitor_enter(_synchronizeMutex);
43
44
/*check synchronization point*/
45
if (0 ==_synchronizeCount) {
46
_syncPointUniqueId = id;
47
} else {
48
Assert_MM_true(_syncPointUniqueId == id);
49
}
50
51
_synchronizeCount += 1;
52
53
if(_synchronizeCount == _threadCount) {
54
_synchronizeCount = 0;
55
_synchronizeIndex += 1;
56
/* notify all threads last thread synced */
57
_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::synchedThreads);
58
omrthread_monitor_notify_all(_synchronizeMutex);
59
} else {
60
volatile uintptr_t index = _synchronizeIndex;
61
62
do {
63
if (_yieldCollaborator.getYieldCount() + _synchronizeCount >= _threadCount && _yieldCollaborator.getYieldCount() > 0) {
64
if (env->isMainThread()) {
65
((MM_Scheduler*)_dispatcher)->condYieldFromGC(env);
66
} else {
67
/* notify main last thread synced/yielded */
68
_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::notifyMain);
69
omrthread_monitor_notify_all(_synchronizeMutex);
70
}
71
}
72
73
/* A worker is only interested in synchedThreads event. For any other events it remains to be blocked */
74
/* We check synchronizeIndex, so we can exit this iteration ASAP before synchedThreads is overwritten by another event in the next iteration
75
* (We may be overly cautious here, since we are not that sure that overlap between iterations may even happen)
76
*/
77
do {
78
env->reportScanningSuspended();
79
omrthread_monitor_wait(_synchronizeMutex);
80
env->reportScanningResumed();
81
} while ((index == _synchronizeIndex) && !env->isMainThread() && (_yieldCollaborator.getResumeEvent() != MM_YieldCollaborator::synchedThreads));
82
83
} while(index == _synchronizeIndex);
84
}
85
omrthread_monitor_exit(_synchronizeMutex);
86
}
87
}
88
89
bool
90
MM_IncrementalParallelTask::synchronizeGCThreadsAndReleaseMain(MM_EnvironmentBase *envBase, const char *id)
91
{
92
MM_EnvironmentRealtime *env = MM_EnvironmentRealtime::getEnvironment(envBase);
93
bool isMainThread = false;
94
95
if(1 < _totalThreadCount) {
96
volatile uintptr_t index = _synchronizeIndex;
97
98
if (env->isMainThread()) {
99
/* This function only has to be re-entrant for the main thread */
100
_entryCount += 1;
101
if (_entryCount > 1) {
102
isMainThread = true;
103
goto done;
104
}
105
}
106
107
omrthread_monitor_enter(_synchronizeMutex);
108
109
/*check synchronization point*/
110
if (0 == _synchronizeCount) {
111
_syncPointUniqueId = id;
112
} else {
113
Assert_MM_true(_syncPointUniqueId == id);
114
}
115
116
_synchronizeCount += 1;
117
if(_synchronizeCount == _threadCount) {
118
if(env->isMainThread()) {
119
omrthread_monitor_exit(_synchronizeMutex);
120
isMainThread = true;
121
_synchronized = true;
122
goto done;
123
}
124
/* notify main last thread synced */
125
_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::notifyMain);
126
omrthread_monitor_notify_all(_synchronizeMutex);
127
}
128
129
while(index == _synchronizeIndex) {
130
if(env->isMainThread() && (_synchronizeCount == _threadCount)) {
131
omrthread_monitor_exit(_synchronizeMutex);
132
isMainThread = true;
133
_synchronized = true;
134
goto done;
135
}
136
137
if ((_yieldCollaborator.getYieldCount() + _synchronizeCount >= _threadCount) && (_yieldCollaborator.getYieldCount() > 0)) {
138
if (env->isMainThread()) {
139
((MM_Scheduler*)_dispatcher)->condYieldFromGC(env);
140
} else {
141
/* notify main last thread synced/yielded */
142
_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::notifyMain);
143
omrthread_monitor_notify_all(_synchronizeMutex);
144
}
145
}
146
147
/* A worker is only interested in synchedThreads event. For any other events it remains to be blocked */
148
/* We check synchronizeIndex, so we can exit this iteration ASAP before synchedThreads is overwritten by another event in the next iteration
149
* (We may be overly cautious here, since we are not that sure that overlap between iterations may even happen)
150
*/
151
do {
152
env->reportScanningSuspended();
153
omrthread_monitor_wait(_synchronizeMutex);
154
env->reportScanningResumed();
155
} while ((index == _synchronizeIndex) && !env->isMainThread() && (_yieldCollaborator.getResumeEvent() != MM_YieldCollaborator::synchedThreads));
156
}
157
omrthread_monitor_exit(_synchronizeMutex);
158
} else {
159
isMainThread = true;
160
}
161
162
done:
163
return isMainThread;
164
}
165
166
bool
167
MM_IncrementalParallelTask::synchronizeGCThreadsAndReleaseSingleThread(MM_EnvironmentBase *env, const char *id)
168
{
169
/* this task doesn't support synchronizeGCThreadsAndReleaseSingleThread currently */
170
Assert_MM_unreachable();
171
/* TODO if implementing make sure to fix the isMain check in releaseSynchronizedGCThreads */
172
return MM_ParallelTask::synchronizeGCThreadsAndReleaseSingleThread(env, id);
173
}
174
175
void
176
MM_IncrementalParallelTask::releaseSynchronizedGCThreads(MM_EnvironmentBase *env)
177
{
178
if(1 == _totalThreadCount) {
179
return;
180
}
181
182
if(env->isMainThread()) {
183
/* sync/release sequence actually takes time (excluding the work within the sync/release pair).
184
* Take advantage of the fact the all workers are blocked to check if it is time to yield */
185
((MM_Scheduler*)_dispatcher)->condYieldFromGC(env);
186
187
/* Could not have gotten here unless all other threads are sync'd - don't check, just release */
188
_entryCount -= 1;
189
if (_entryCount == 0) {
190
_synchronized = false;
191
omrthread_monitor_enter(_synchronizeMutex);
192
_synchronizeCount = 0;
193
_synchronizeIndex += 1;
194
_yieldCollaborator.setResumeEvent(MM_YieldCollaborator::synchedThreads);
195
omrthread_monitor_notify_all(_synchronizeMutex);
196
omrthread_monitor_exit(_synchronizeMutex);
197
}
198
}
199
}
200
201