RFR: JDK-8145315: VM crashes in print_task_time_stamps()
Bengt Rutisson
bengt.rutisson at oracle.com
Wed Dec 16 08:42:41 UTC 2015
Thanks for the reviews, Jon and Jesper!
Bengt
On 2015-12-15 20:05, Jon Masamitsu wrote:
> Looks good.
>
> Jon
>
> On 12/15/2015 3:56 AM, Bengt Rutisson wrote:
>>
>> 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