|
33 | 33 | #include "mmtkRootsClosure.hpp"
|
34 | 34 | #include "mmtkUpcalls.hpp"
|
35 | 35 | #include "mmtkVMCompanionThread.hpp"
|
| 36 | +#include "runtime/atomic.hpp" |
36 | 37 | #include "runtime/mutexLocker.hpp"
|
37 | 38 | #include "runtime/os.hpp"
|
38 | 39 | #include "runtime/safepoint.hpp"
|
|
41 | 42 | #include "runtime/vmThread.hpp"
|
42 | 43 | #include "utilities/debug.hpp"
|
43 | 44 |
|
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; |
45 | 47 |
|
46 | 48 | static void mmtk_stop_all_mutators(void *tls, void (*create_stack_scan_work)(void* mutator)) {
|
47 | 49 | MMTkHeap::_create_stack_scan_work = create_stack_scan_work;
|
@@ -79,9 +81,11 @@ static void mmtk_resume_mutators(void *tls) {
|
79 | 81 | MMTkHeap::heap()->companion_thread()->request(MMTkVMCompanionThread::_threads_resumed, true);
|
80 | 82 | log_debug(gc)("Mutators resumed. Now notify any mutators waiting for GC to finish...");
|
81 | 83 |
|
| 84 | + // Note: we don't have to hold gc_lock to increment the counter. |
| 85 | + Atomic::inc(&mmtk_start_the_world_count); |
| 86 | + |
82 | 87 | {
|
83 | 88 | MutexLockerEx locker(MMTkHeap::heap()->gc_lock(), true);
|
84 |
| - mmtk_start_the_world_count++; |
85 | 89 | MMTkHeap::heap()->gc_lock()->notify_all();
|
86 | 90 | }
|
87 | 91 | log_debug(gc)("Mutators notified.");
|
@@ -120,12 +124,25 @@ static void mmtk_spawn_collector_thread(void* tls, int kind, void* ctx) {
|
120 | 124 | static void mmtk_block_for_gc() {
|
121 | 125 | MMTkHeap::heap()->_last_gc_time = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
|
122 | 126 | 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 | + |
123 | 139 | {
|
| 140 | + // Once this thread acquires the lock, the VM will consider this thread to be "in safe point". |
124 | 141 | MutexLocker locker(MMTkHeap::heap()->gc_lock());
|
125 |
| - size_t my_count = mmtk_start_the_world_count; |
126 |
| - size_t next_count = my_count + 1; |
127 | 142 |
|
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. |
129 | 146 | MMTkHeap::heap()->gc_lock()->wait();
|
130 | 147 | }
|
131 | 148 | }
|
|
0 commit comments