RFR: JDK-8145315: VM crashes in print_task_time_stamps()
Bengt Rutisson
bengt.rutisson at oracle.com
Tue Dec 15 11:56:24 UTC 2015
Hi everyone,
Could I have a couple of reviews for this patch?
http://cr.openjdk.java.net/~brutisso/8145315/webrev.00/
https://bugs.openjdk.java.net/browse/JDK-8145315
The fix will make sure that the VM does not crash. But there is still an
issue with that a task may not be printed if we run into the race that
exist. This is a separate problem and outside the scope of this bug fix.
From the bug report:
The crash is due to an existing race condition in the ParallelGC. This
race existed even before the new logging was introduced but we did not
run with this logging enabled before.
The test now runs with -Xlog:gc*=debug, which enables logging that was
previously guarded by the PrintGCTaskTimeStamps flag.
In the GCTaskThread::run() method we have this code:
GCTaskTimeStamp* time_stamp =
time_stamp_at(_time_stamp_index++);
time_stamp->set_name(name);
time_stamp->set_entry_time(entry_time);
time_stamp->set_exit_time(timer.ticks());
And in GCTaskThread::print_task_time_stamps() we have this code:
for(uint i=0; i<_time_stamp_index; i++) {
GCTaskTimeStamp* time_stamp = time_stamp_at(i);
log_debug(gc, task, time)("\t[ %s " JLONG_FORMAT " " JLONG_FORMAT "
]",
time_stamp->name(),
time_stamp->entry_time(),
time_stamp->exit_time());
}
The code in GCTaskThread::run() increments the _time_stamp_index value
before setting the name, entry and exit times, which means that the code
in GCTaskThread::print_task_time_stamps() can see the new value of
_time_stamp_index before the name, entry and exit times have been set.
I can reproduce this on Linux x64 with the following patch that
introduces a sleep and an assert:
diff --git a/src/share/vm/gc/parallel/gcTaskThread.cpp
b/src/share/vm/gc/parallel/gcTaskThread.cpp
--- a/src/share/vm/gc/parallel/gcTaskThread.cpp
+++ b/src/share/vm/gc/parallel/gcTaskThread.cpp
@@ -83,6 +83,7 @@
log_debug(gc, task, time)("GC-Thread %u entries: %d", id(),
_time_stamp_index);
for(uint i=0; i<_time_stamp_index; i++) {
GCTaskTimeStamp* time_stamp = time_stamp_at(i);
+ assert(time_stamp->name() != NULL, "NULL name");
log_debug(gc, task, time)("\t[ %s " JLONG_FORMAT " " JLONG_FORMAT
" ]",
time_stamp->name(),
time_stamp->entry_time(),
@@ -154,6 +155,12 @@
GCTaskTimeStamp* time_stamp =
time_stamp_at(_time_stamp_index++);
+ if (os::random() % 100 == 0) {
+ time_stamp->set_name(NULL);
+ tty->print_cr("####### WAITING: %s", name);
+ sleep(1);
+ }
+
time_stamp->set_name(name);
time_stamp->set_entry_time(entry_time);
time_stamp->set_exit_time(timer.ticks());
By updating the _time_stamp_index after we have set the other values we
remove the crash:
diff --git a/src/share/vm/gc/parallel/gcTaskThread.cpp
b/src/share/vm/gc/parallel/gcTaskThread.cpp
--- a/src/share/vm/gc/parallel/gcTaskThread.cpp
+++ b/src/share/vm/gc/parallel/gcTaskThread.cpp
@@ -153,7 +153,7 @@
if (log_is_enabled(Debug, gc, task, time)) {
timer.update();
- GCTaskTimeStamp* time_stamp = time_stamp_at(_time_stamp_index++);
+ GCTaskTimeStamp* time_stamp = time_stamp_at(_time_stamp_index);
if (os::random() % 100 == 0) {
time_stamp->set_name(NULL);
@@ -164,6 +164,7 @@
time_stamp->set_name(name);
time_stamp->set_entry_time(entry_time);
time_stamp->set_exit_time(timer.ticks());
+ _time_stamp_index++;
}
} else {
// idle tasks complete outside the normal accounting
Running with the first patch asserts every time. Adding the second patch
does not hit the assert.
More information about the hotspot-gc-dev
mailing list