Mercurial > hg > truffle
annotate src/share/vm/utilities/workgroup.cpp @ 14649:f6301b007a16
6498581: ThreadInterruptTest3 produces wrong output on Windows
Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Reviewed-by: acorn, kvn
Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
author | minqi |
---|---|
date | Wed, 26 Feb 2014 15:20:41 -0800 |
parents | f9be75d21404 |
children | 78bbf4d43a14 |
rev | line source |
---|---|
0 | 1 /* |
10271
f9be75d21404
8012902: remove use of global operator new - take 2
minqi
parents:
10161
diff
changeset
|
2 * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. |
0 | 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
342
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
342
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
342
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "memory/allocation.hpp" | |
27 #include "memory/allocation.inline.hpp" | |
28 #include "runtime/os.hpp" | |
29 #include "utilities/workgroup.hpp" | |
0 | 30 |
31 // Definitions of WorkGang methods. | |
32 | |
33 AbstractWorkGang::AbstractWorkGang(const char* name, | |
342 | 34 bool are_GC_task_threads, |
35 bool are_ConcurrentGC_threads) : | |
0 | 36 _name(name), |
342 | 37 _are_GC_task_threads(are_GC_task_threads), |
38 _are_ConcurrentGC_threads(are_ConcurrentGC_threads) { | |
39 | |
40 assert(!(are_GC_task_threads && are_ConcurrentGC_threads), | |
41 "They cannot both be STW GC and Concurrent threads" ); | |
42 | |
0 | 43 // Other initialization. |
44 _monitor = new Monitor(/* priority */ Mutex::leaf, | |
45 /* name */ "WorkGroup monitor", | |
342 | 46 /* allow_vm_block */ are_GC_task_threads); |
0 | 47 assert(monitor() != NULL, "Failed to allocate monitor"); |
48 _terminate = false; | |
49 _task = NULL; | |
50 _sequence_number = 0; | |
51 _started_workers = 0; | |
52 _finished_workers = 0; | |
53 } | |
54 | |
55 WorkGang::WorkGang(const char* name, | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
56 uint workers, |
342 | 57 bool are_GC_task_threads, |
58 bool are_ConcurrentGC_threads) : | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
59 AbstractWorkGang(name, are_GC_task_threads, are_ConcurrentGC_threads) { |
0 | 60 _total_workers = workers; |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
61 } |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
62 |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
63 GangWorker* WorkGang::allocate_worker(uint which) { |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
64 GangWorker* new_worker = new GangWorker(this, which); |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
65 return new_worker; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
66 } |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
67 |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
68 // The current implementation will exit if the allocation |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
69 // of any worker fails. Still, return a boolean so that |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
70 // a future implementation can possibly do a partial |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
71 // initialization of the workers and report such to the |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
72 // caller. |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
73 bool WorkGang::initialize_workers() { |
342 | 74 |
0 | 75 if (TraceWorkGang) { |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
76 tty->print_cr("Constructing work gang %s with %d threads", |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
77 name(), |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
78 total_workers()); |
0 | 79 } |
6197 | 80 _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, total_workers(), mtInternal); |
342 | 81 if (gang_workers() == NULL) { |
10161
746b070f5022
8011661: Insufficient memory message says "malloc" when sometimes it should say "mmap"
ccheung
parents:
10135
diff
changeset
|
82 vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GangWorker array."); |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
83 return false; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
84 } |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
85 os::ThreadType worker_type; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
86 if (are_ConcurrentGC_threads()) { |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
87 worker_type = os::cgc_thread; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
88 } else { |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
89 worker_type = os::pgc_thread; |
342 | 90 } |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
91 for (uint worker = 0; worker < total_workers(); worker += 1) { |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
92 GangWorker* new_worker = allocate_worker(worker); |
0 | 93 assert(new_worker != NULL, "Failed to allocate GangWorker"); |
94 _gang_workers[worker] = new_worker; | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
95 if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) { |
10161
746b070f5022
8011661: Insufficient memory message says "malloc" when sometimes it should say "mmap"
ccheung
parents:
10135
diff
changeset
|
96 vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, |
746b070f5022
8011661: Insufficient memory message says "malloc" when sometimes it should say "mmap"
ccheung
parents:
10135
diff
changeset
|
97 "Cannot create worker GC thread. Out of system resources."); |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
98 return false; |
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
99 } |
0 | 100 if (!DisableStartThread) { |
101 os::start_thread(new_worker); | |
102 } | |
103 } | |
1833
8b10f48633dc
6984287: Regularize how GC parallel workers are specified.
jmasa
parents:
1552
diff
changeset
|
104 return true; |
0 | 105 } |
106 | |
107 AbstractWorkGang::~AbstractWorkGang() { | |
108 if (TraceWorkGang) { | |
109 tty->print_cr("Destructing work gang %s", name()); | |
110 } | |
111 stop(); // stop all the workers | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
112 for (uint worker = 0; worker < total_workers(); worker += 1) { |
0 | 113 delete gang_worker(worker); |
114 } | |
115 delete gang_workers(); | |
116 delete monitor(); | |
117 } | |
118 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
119 GangWorker* AbstractWorkGang::gang_worker(uint i) const { |
0 | 120 // Array index bounds checking. |
121 GangWorker* result = NULL; | |
122 assert(gang_workers() != NULL, "No workers for indexing"); | |
123 assert(((i >= 0) && (i < total_workers())), "Worker index out of bounds"); | |
124 result = _gang_workers[i]; | |
125 assert(result != NULL, "Indexing to null worker"); | |
126 return result; | |
127 } | |
128 | |
129 void WorkGang::run_task(AbstractGangTask* task) { | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
130 run_task(task, total_workers()); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
131 } |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
132 |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
133 void WorkGang::run_task(AbstractGangTask* task, uint no_of_parallel_workers) { |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
134 task->set_for_termination(no_of_parallel_workers); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
135 |
0 | 136 // This thread is executed by the VM thread which does not block |
137 // on ordinary MutexLocker's. | |
138 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
139 if (TraceWorkGang) { | |
140 tty->print_cr("Running work gang %s task %s", name(), task->name()); | |
141 } | |
142 // Tell all the workers to run a task. | |
143 assert(task != NULL, "Running a null task"); | |
144 // Initialize. | |
145 _task = task; | |
146 _sequence_number += 1; | |
147 _started_workers = 0; | |
148 _finished_workers = 0; | |
149 // Tell the workers to get to work. | |
150 monitor()->notify_all(); | |
151 // Wait for them to be finished | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
152 while (finished_workers() < no_of_parallel_workers) { |
0 | 153 if (TraceWorkGang) { |
154 tty->print_cr("Waiting in work gang %s: %d/%d finished sequence %d", | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
155 name(), finished_workers(), no_of_parallel_workers, |
0 | 156 _sequence_number); |
157 } | |
158 monitor()->wait(/* no_safepoint_check */ true); | |
159 } | |
160 _task = NULL; | |
161 if (TraceWorkGang) { | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
162 tty->print_cr("\nFinished work gang %s: %d/%d sequence %d", |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
163 name(), finished_workers(), no_of_parallel_workers, |
0 | 164 _sequence_number); |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
165 Thread* me = Thread::current(); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
166 tty->print_cr(" T: 0x%x VM_thread: %d", me, me->is_VM_thread()); |
2369
92da084fefc9
6668573: CMS: reference processing crash if ParallelCMSThreads > ParallelGCThreads
ysr
parents:
1972
diff
changeset
|
167 } |
0 | 168 } |
169 | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
170 void FlexibleWorkGang::run_task(AbstractGangTask* task) { |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
171 // If active_workers() is passed, _finished_workers |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
172 // must only be incremented for workers that find non_null |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
173 // work (as opposed to all those that just check that the |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
174 // task is not null). |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
175 WorkGang::run_task(task, (uint) active_workers()); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
176 } |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
177 |
0 | 178 void AbstractWorkGang::stop() { |
179 // Tell all workers to terminate, then wait for them to become inactive. | |
180 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
181 if (TraceWorkGang) { | |
182 tty->print_cr("Stopping work gang %s task %s", name(), task()->name()); | |
183 } | |
184 _task = NULL; | |
185 _terminate = true; | |
186 monitor()->notify_all(); | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
187 while (finished_workers() < active_workers()) { |
0 | 188 if (TraceWorkGang) { |
189 tty->print_cr("Waiting in work gang %s: %d/%d finished", | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
190 name(), finished_workers(), active_workers()); |
0 | 191 } |
192 monitor()->wait(/* no_safepoint_check */ true); | |
193 } | |
194 } | |
195 | |
196 void AbstractWorkGang::internal_worker_poll(WorkData* data) const { | |
197 assert(monitor()->owned_by_self(), "worker_poll is an internal method"); | |
198 assert(data != NULL, "worker data is null"); | |
199 data->set_terminate(terminate()); | |
200 data->set_task(task()); | |
201 data->set_sequence_number(sequence_number()); | |
202 } | |
203 | |
204 void AbstractWorkGang::internal_note_start() { | |
205 assert(monitor()->owned_by_self(), "note_finish is an internal method"); | |
206 _started_workers += 1; | |
207 } | |
208 | |
209 void AbstractWorkGang::internal_note_finish() { | |
210 assert(monitor()->owned_by_self(), "note_finish is an internal method"); | |
211 _finished_workers += 1; | |
212 } | |
213 | |
214 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const { | |
215 uint num_thr = total_workers(); | |
216 for (uint i = 0; i < num_thr; i++) { | |
217 gang_worker(i)->print_on(st); | |
218 st->cr(); | |
219 } | |
220 } | |
221 | |
222 void AbstractWorkGang::threads_do(ThreadClosure* tc) const { | |
223 assert(tc != NULL, "Null ThreadClosure"); | |
224 uint num_thr = total_workers(); | |
225 for (uint i = 0; i < num_thr; i++) { | |
226 tc->do_thread(gang_worker(i)); | |
227 } | |
228 } | |
229 | |
230 // GangWorker methods. | |
231 | |
232 GangWorker::GangWorker(AbstractWorkGang* gang, uint id) { | |
233 _gang = gang; | |
234 set_id(id); | |
235 set_name("Gang worker#%d (%s)", id, gang->name()); | |
236 } | |
237 | |
238 void GangWorker::run() { | |
239 initialize(); | |
240 loop(); | |
241 } | |
242 | |
243 void GangWorker::initialize() { | |
244 this->initialize_thread_local_storage(); | |
6197 | 245 this->record_stack_base_and_size(); |
0 | 246 assert(_gang != NULL, "No gang to run in"); |
247 os::set_priority(this, NearMaxPriority); | |
248 if (TraceWorkGang) { | |
249 tty->print_cr("Running gang worker for gang %s id %d", | |
250 gang()->name(), id()); | |
251 } | |
252 // The VM thread should not execute here because MutexLocker's are used | |
253 // as (opposed to MutexLockerEx's). | |
254 assert(!Thread::current()->is_VM_thread(), "VM thread should not be part" | |
255 " of a work gang"); | |
256 } | |
257 | |
258 void GangWorker::loop() { | |
259 int previous_sequence_number = 0; | |
260 Monitor* gang_monitor = gang()->monitor(); | |
261 for ( ; /* !terminate() */; ) { | |
262 WorkData data; | |
263 int part; // Initialized below. | |
264 { | |
265 // Grab the gang mutex. | |
266 MutexLocker ml(gang_monitor); | |
267 // Wait for something to do. | |
268 // Polling outside the while { wait } avoids missed notifies | |
269 // in the outer loop. | |
270 gang()->internal_worker_poll(&data); | |
271 if (TraceWorkGang) { | |
272 tty->print("Polled outside for work in gang %s worker %d", | |
273 gang()->name(), id()); | |
274 tty->print(" terminate: %s", | |
275 data.terminate() ? "true" : "false"); | |
276 tty->print(" sequence: %d (prev: %d)", | |
277 data.sequence_number(), previous_sequence_number); | |
278 if (data.task() != NULL) { | |
279 tty->print(" task: %s", data.task()->name()); | |
280 } else { | |
281 tty->print(" task: NULL"); | |
282 } | |
283 tty->cr(); | |
284 } | |
285 for ( ; /* break or return */; ) { | |
286 // Terminate if requested. | |
287 if (data.terminate()) { | |
288 gang()->internal_note_finish(); | |
289 gang_monitor->notify_all(); | |
290 return; | |
291 } | |
292 // Check for new work. | |
293 if ((data.task() != NULL) && | |
294 (data.sequence_number() != previous_sequence_number)) { | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
295 if (gang()->needs_more_workers()) { |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
296 gang()->internal_note_start(); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
297 gang_monitor->notify_all(); |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
298 part = gang()->started_workers() - 1; |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
299 break; |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
300 } |
0 | 301 } |
302 // Nothing to do. | |
303 gang_monitor->wait(/* no_safepoint_check */ true); | |
304 gang()->internal_worker_poll(&data); | |
305 if (TraceWorkGang) { | |
306 tty->print("Polled inside for work in gang %s worker %d", | |
307 gang()->name(), id()); | |
308 tty->print(" terminate: %s", | |
309 data.terminate() ? "true" : "false"); | |
310 tty->print(" sequence: %d (prev: %d)", | |
311 data.sequence_number(), previous_sequence_number); | |
312 if (data.task() != NULL) { | |
313 tty->print(" task: %s", data.task()->name()); | |
314 } else { | |
315 tty->print(" task: NULL"); | |
316 } | |
317 tty->cr(); | |
318 } | |
319 } | |
320 // Drop gang mutex. | |
321 } | |
322 if (TraceWorkGang) { | |
323 tty->print("Work for work gang %s id %d task %s part %d", | |
324 gang()->name(), id(), data.task()->name(), part); | |
325 } | |
326 assert(data.task() != NULL, "Got null task"); | |
327 data.task()->work(part); | |
328 { | |
329 if (TraceWorkGang) { | |
330 tty->print("Finish for work gang %s id %d task %s part %d", | |
331 gang()->name(), id(), data.task()->name(), part); | |
332 } | |
333 // Grab the gang mutex. | |
334 MutexLocker ml(gang_monitor); | |
335 gang()->internal_note_finish(); | |
336 // Tell the gang you are done. | |
337 gang_monitor->notify_all(); | |
338 // Drop the gang mutex. | |
339 } | |
340 previous_sequence_number = data.sequence_number(); | |
341 } | |
342 } | |
343 | |
344 bool GangWorker::is_GC_task_thread() const { | |
342 | 345 return gang()->are_GC_task_threads(); |
346 } | |
347 | |
348 bool GangWorker::is_ConcurrentGC_thread() const { | |
349 return gang()->are_ConcurrentGC_threads(); | |
0 | 350 } |
351 | |
352 void GangWorker::print_on(outputStream* st) const { | |
353 st->print("\"%s\" ", name()); | |
354 Thread::print_on(st); | |
355 st->cr(); | |
356 } | |
357 | |
358 // Printing methods | |
359 | |
360 const char* AbstractWorkGang::name() const { | |
361 return _name; | |
362 } | |
363 | |
364 #ifndef PRODUCT | |
365 | |
366 const char* AbstractGangTask::name() const { | |
367 return _name; | |
368 } | |
369 | |
370 #endif /* PRODUCT */ | |
371 | |
4095
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
372 // FlexibleWorkGang |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
373 |
bca17e38de00
6593758: RFE: Enhance GC ergonomics to dynamically choose ParallelGCThreads
jmasa
parents:
2369
diff
changeset
|
374 |
0 | 375 // *** WorkGangBarrierSync |
376 | |
377 WorkGangBarrierSync::WorkGangBarrierSync() | |
378 : _monitor(Mutex::safepoint, "work gang barrier sync", true), | |
342 | 379 _n_workers(0), _n_completed(0), _should_reset(false) { |
0 | 380 } |
381 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
382 WorkGangBarrierSync::WorkGangBarrierSync(uint n_workers, const char* name) |
0 | 383 : _monitor(Mutex::safepoint, name, true), |
342 | 384 _n_workers(n_workers), _n_completed(0), _should_reset(false) { |
0 | 385 } |
386 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
387 void WorkGangBarrierSync::set_n_workers(uint n_workers) { |
0 | 388 _n_workers = n_workers; |
389 _n_completed = 0; | |
342 | 390 _should_reset = false; |
0 | 391 } |
392 | |
393 void WorkGangBarrierSync::enter() { | |
394 MutexLockerEx x(monitor(), Mutex::_no_safepoint_check_flag); | |
342 | 395 if (should_reset()) { |
396 // The should_reset() was set and we are the first worker to enter | |
397 // the sync barrier. We will zero the n_completed() count which | |
398 // effectively resets the barrier. | |
399 zero_completed(); | |
400 set_should_reset(false); | |
401 } | |
0 | 402 inc_completed(); |
403 if (n_completed() == n_workers()) { | |
342 | 404 // At this point we would like to reset the barrier to be ready in |
405 // case it is used again. However, we cannot set n_completed() to | |
406 // 0, even after the notify_all(), given that some other workers | |
407 // might still be waiting for n_completed() to become == | |
408 // n_workers(). So, if we set n_completed() to 0, those workers | |
409 // will get stuck (as they will wake up, see that n_completed() != | |
410 // n_workers() and go back to sleep). Instead, we raise the | |
411 // should_reset() flag and the barrier will be reset the first | |
412 // time a worker enters it again. | |
413 set_should_reset(true); | |
0 | 414 monitor()->notify_all(); |
342 | 415 } else { |
0 | 416 while (n_completed() != n_workers()) { |
417 monitor()->wait(/* no_safepoint_check */ true); | |
418 } | |
419 } | |
420 } | |
421 | |
422 // SubTasksDone functions. | |
423 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
424 SubTasksDone::SubTasksDone(uint n) : |
0 | 425 _n_tasks(n), _n_threads(1), _tasks(NULL) { |
6197 | 426 _tasks = NEW_C_HEAP_ARRAY(uint, n, mtInternal); |
0 | 427 guarantee(_tasks != NULL, "alloc failure"); |
428 clear(); | |
429 } | |
430 | |
431 bool SubTasksDone::valid() { | |
432 return _tasks != NULL; | |
433 } | |
434 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
435 void SubTasksDone::set_n_threads(uint t) { |
0 | 436 assert(_claimed == 0 || _threads_completed == _n_threads, |
437 "should not be called while tasks are being processed!"); | |
438 _n_threads = (t == 0 ? 1 : t); | |
439 } | |
440 | |
441 void SubTasksDone::clear() { | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
442 for (uint i = 0; i < _n_tasks; i++) { |
0 | 443 _tasks[i] = 0; |
444 } | |
445 _threads_completed = 0; | |
446 #ifdef ASSERT | |
447 _claimed = 0; | |
448 #endif | |
449 } | |
450 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
451 bool SubTasksDone::is_task_claimed(uint t) { |
0 | 452 assert(0 <= t && t < _n_tasks, "bad task id."); |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
453 uint old = _tasks[t]; |
0 | 454 if (old == 0) { |
455 old = Atomic::cmpxchg(1, &_tasks[t], 0); | |
456 } | |
457 assert(_tasks[t] == 1, "What else?"); | |
458 bool res = old != 0; | |
459 #ifdef ASSERT | |
460 if (!res) { | |
461 assert(_claimed < _n_tasks, "Too many tasks claimed; missing clear?"); | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
462 Atomic::inc((volatile jint*) &_claimed); |
0 | 463 } |
464 #endif | |
465 return res; | |
466 } | |
467 | |
468 void SubTasksDone::all_tasks_completed() { | |
469 jint observed = _threads_completed; | |
470 jint old; | |
471 do { | |
472 old = observed; | |
473 observed = Atomic::cmpxchg(old+1, &_threads_completed, old); | |
474 } while (observed != old); | |
475 // If this was the last thread checking in, clear the tasks. | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
476 if (observed+1 == (jint)_n_threads) clear(); |
0 | 477 } |
478 | |
479 | |
480 SubTasksDone::~SubTasksDone() { | |
6197 | 481 if (_tasks != NULL) FREE_C_HEAP_ARRAY(jint, _tasks, mtInternal); |
0 | 482 } |
483 | |
484 // *** SequentialSubTasksDone | |
485 | |
486 void SequentialSubTasksDone::clear() { | |
487 _n_tasks = _n_claimed = 0; | |
488 _n_threads = _n_completed = 0; | |
489 } | |
490 | |
491 bool SequentialSubTasksDone::valid() { | |
492 return _n_threads > 0; | |
493 } | |
494 | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
495 bool SequentialSubTasksDone::is_task_claimed(uint& t) { |
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
496 uint* n_claimed_ptr = &_n_claimed; |
0 | 497 t = *n_claimed_ptr; |
498 while (t < _n_tasks) { | |
499 jint res = Atomic::cmpxchg(t+1, n_claimed_ptr, t); | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
500 if (res == (jint)t) { |
0 | 501 return false; |
502 } | |
503 t = *n_claimed_ptr; | |
504 } | |
505 return true; | |
506 } | |
507 | |
508 bool SequentialSubTasksDone::all_tasks_completed() { | |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
509 uint* n_completed_ptr = &_n_completed; |
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
510 uint complete = *n_completed_ptr; |
0 | 511 while (true) { |
4728
441e946dc1af
7121618: Change type of number of GC workers to unsigned int.
jmasa
parents:
4095
diff
changeset
|
512 uint res = Atomic::cmpxchg(complete+1, n_completed_ptr, complete); |
0 | 513 if (res == complete) { |
514 break; | |
515 } | |
516 complete = res; | |
517 } | |
518 if (complete+1 == _n_threads) { | |
519 clear(); | |
520 return true; | |
521 } | |
522 return false; | |
523 } | |
342 | 524 |
525 bool FreeIdSet::_stat_init = false; | |
526 FreeIdSet* FreeIdSet::_sets[NSets]; | |
527 bool FreeIdSet::_safepoint; | |
528 | |
529 FreeIdSet::FreeIdSet(int sz, Monitor* mon) : | |
530 _sz(sz), _mon(mon), _hd(0), _waiters(0), _index(-1), _claimed(0) | |
531 { | |
10271
f9be75d21404
8012902: remove use of global operator new - take 2
minqi
parents:
10161
diff
changeset
|
532 _ids = NEW_C_HEAP_ARRAY(int, sz, mtInternal); |
342 | 533 for (int i = 0; i < sz; i++) _ids[i] = i+1; |
534 _ids[sz-1] = end_of_list; // end of list. | |
535 if (_stat_init) { | |
536 for (int j = 0; j < NSets; j++) _sets[j] = NULL; | |
537 _stat_init = true; | |
538 } | |
539 // Add to sets. (This should happen while the system is still single-threaded.) | |
540 for (int j = 0; j < NSets; j++) { | |
541 if (_sets[j] == NULL) { | |
542 _sets[j] = this; | |
543 _index = j; | |
544 break; | |
545 } | |
546 } | |
547 guarantee(_index != -1, "Too many FreeIdSets in use!"); | |
548 } | |
549 | |
550 FreeIdSet::~FreeIdSet() { | |
551 _sets[_index] = NULL; | |
10271
f9be75d21404
8012902: remove use of global operator new - take 2
minqi
parents:
10161
diff
changeset
|
552 FREE_C_HEAP_ARRAY(int, _ids, mtInternal); |
342 | 553 } |
554 | |
555 void FreeIdSet::set_safepoint(bool b) { | |
556 _safepoint = b; | |
557 if (b) { | |
558 for (int j = 0; j < NSets; j++) { | |
559 if (_sets[j] != NULL && _sets[j]->_waiters > 0) { | |
560 Monitor* mon = _sets[j]->_mon; | |
561 mon->lock_without_safepoint_check(); | |
562 mon->notify_all(); | |
563 mon->unlock(); | |
564 } | |
565 } | |
566 } | |
567 } | |
568 | |
569 #define FID_STATS 0 | |
570 | |
571 int FreeIdSet::claim_par_id() { | |
572 #if FID_STATS | |
573 thread_t tslf = thr_self(); | |
574 tty->print("claim_par_id[%d]: sz = %d, claimed = %d\n", tslf, _sz, _claimed); | |
575 #endif | |
576 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); | |
577 while (!_safepoint && _hd == end_of_list) { | |
578 _waiters++; | |
579 #if FID_STATS | |
580 if (_waiters > 5) { | |
581 tty->print("claim_par_id waiting[%d]: %d waiters, %d claimed.\n", | |
582 tslf, _waiters, _claimed); | |
583 } | |
584 #endif | |
585 _mon->wait(Mutex::_no_safepoint_check_flag); | |
586 _waiters--; | |
587 } | |
588 if (_hd == end_of_list) { | |
589 #if FID_STATS | |
590 tty->print("claim_par_id[%d]: returning EOL.\n", tslf); | |
591 #endif | |
592 return -1; | |
593 } else { | |
594 int res = _hd; | |
595 _hd = _ids[res]; | |
596 _ids[res] = claimed; // For debugging. | |
597 _claimed++; | |
598 #if FID_STATS | |
599 tty->print("claim_par_id[%d]: returning %d, claimed = %d.\n", | |
600 tslf, res, _claimed); | |
601 #endif | |
602 return res; | |
603 } | |
604 } | |
605 | |
606 bool FreeIdSet::claim_perm_id(int i) { | |
607 assert(0 <= i && i < _sz, "Out of range."); | |
608 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); | |
609 int prev = end_of_list; | |
610 int cur = _hd; | |
611 while (cur != end_of_list) { | |
612 if (cur == i) { | |
613 if (prev == end_of_list) { | |
614 _hd = _ids[cur]; | |
615 } else { | |
616 _ids[prev] = _ids[cur]; | |
617 } | |
618 _ids[cur] = claimed; | |
619 _claimed++; | |
620 return true; | |
621 } else { | |
622 prev = cur; | |
623 cur = _ids[cur]; | |
624 } | |
625 } | |
626 return false; | |
627 | |
628 } | |
629 | |
630 void FreeIdSet::release_par_id(int id) { | |
631 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag); | |
632 assert(_ids[id] == claimed, "Precondition."); | |
633 _ids[id] = _hd; | |
634 _hd = id; | |
635 _claimed--; | |
636 #if FID_STATS | |
637 tty->print("[%d] release_par_id(%d), waiters =%d, claimed = %d.\n", | |
638 thr_self(), id, _waiters, _claimed); | |
639 #endif | |
640 if (_waiters > 0) | |
641 // Notify all would be safer, but this is OK, right? | |
642 _mon->notify_all(); | |
643 } |