Skip to content

Commit 90e659f

Browse files
authored
Merge pull request #161 from wks/fix-resume-mutators
Fix resuming mutators.
2 parents 040da09 + 7236297 commit 90e659f

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed

openjdk/mmtkUpcalls.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "mmtkRootsClosure.hpp"
3434
#include "mmtkUpcalls.hpp"
3535
#include "mmtkVMCompanionThread.hpp"
36+
#include "runtime/atomic.hpp"
3637
#include "runtime/mutexLocker.hpp"
3738
#include "runtime/os.hpp"
3839
#include "runtime/safepoint.hpp"
@@ -41,7 +42,8 @@
4142
#include "runtime/vmThread.hpp"
4243
#include "utilities/debug.hpp"
4344

44-
static size_t mmtk_start_the_world_count = 0;
45+
// Note: This counter must be accessed using the Atomic class.
46+
static volatile size_t mmtk_start_the_world_count = 0;
4547

4648
static void mmtk_stop_all_mutators(void *tls, void (*create_stack_scan_work)(void* mutator)) {
4749
MMTkHeap::_create_stack_scan_work = create_stack_scan_work;
@@ -79,9 +81,11 @@ static void mmtk_resume_mutators(void *tls) {
7981
MMTkHeap::heap()->companion_thread()->request(MMTkVMCompanionThread::_threads_resumed, true);
8082
log_debug(gc)("Mutators resumed. Now notify any mutators waiting for GC to finish...");
8183

84+
// Note: we don't have to hold gc_lock to increment the counter.
85+
Atomic::inc(&mmtk_start_the_world_count);
86+
8287
{
8388
MutexLockerEx locker(MMTkHeap::heap()->gc_lock(), true);
84-
mmtk_start_the_world_count++;
8589
MMTkHeap::heap()->gc_lock()->notify_all();
8690
}
8791
log_debug(gc)("Mutators notified.");
@@ -120,12 +124,25 @@ static void mmtk_spawn_collector_thread(void* tls, int kind, void* ctx) {
120124
static void mmtk_block_for_gc() {
121125
MMTkHeap::heap()->_last_gc_time = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
122126
log_debug(gc)("Thread (id=%d) will block waiting for GC to finish.", Thread::current()->osthread()->thread_id());
127+
128+
// We must read the counter before entering safepoint.
129+
// This thread has just triggered GC.
130+
// Before this thread enters safe point, the GC cannot start, and therefore cannot finish,
131+
// and cannot increment the counter mmtk_start_the_world_count.
132+
// Otherwise, if we attempt to acquire the gc_lock first, GC may have triggered stop-the-world
133+
// first, and this thread will be blocked for the entire stop-the-world duration before it can
134+
// get the lock. Once that happens, the current thread will read the counter after the GC, and
135+
// wait for the next non-existing GC forever.
136+
size_t my_count = Atomic::load(&mmtk_start_the_world_count);
137+
size_t next_count = my_count + 1;
138+
123139
{
140+
// Once this thread acquires the lock, the VM will consider this thread to be "in safe point".
124141
MutexLocker locker(MMTkHeap::heap()->gc_lock());
125-
size_t my_count = mmtk_start_the_world_count;
126-
size_t next_count = my_count + 1;
127142

128-
while (mmtk_start_the_world_count < next_count) {
143+
while (Atomic::load(&mmtk_start_the_world_count) < next_count) {
144+
// wait() may wake up spuriously, but the authoritative condition for unblocking is
145+
// mmtk_start_the_world_count being incremented.
129146
MMTkHeap::heap()->gc_lock()->wait();
130147
}
131148
}

0 commit comments

Comments
 (0)