36 ShenandoahEvacOOMHandler::ShenandoahEvacOOMHandler() : |
36 ShenandoahEvacOOMHandler::ShenandoahEvacOOMHandler() : |
37 _threads_in_evac(0) { |
37 _threads_in_evac(0) { |
38 } |
38 } |
39 |
39 |
40 void ShenandoahEvacOOMHandler::wait_for_no_evac_threads() { |
40 void ShenandoahEvacOOMHandler::wait_for_no_evac_threads() { |
41 while ((OrderAccess::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) != 0) { |
41 while ((Atomic::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) != 0) { |
42 os::naked_short_sleep(1); |
42 os::naked_short_sleep(1); |
43 } |
43 } |
44 // At this point we are sure that no threads can evacuate anything. Raise |
44 // At this point we are sure that no threads can evacuate anything. Raise |
45 // the thread-local oom_during_evac flag to indicate that any attempt |
45 // the thread-local oom_during_evac flag to indicate that any attempt |
46 // to evacuate should simply return the forwarding pointer instead (which is safe now). |
46 // to evacuate should simply return the forwarding pointer instead (which is safe now). |
47 ShenandoahThreadLocalData::set_oom_during_evac(Thread::current(), true); |
47 ShenandoahThreadLocalData::set_oom_during_evac(Thread::current(), true); |
48 } |
48 } |
49 |
49 |
50 void ShenandoahEvacOOMHandler::enter_evacuation() { |
50 void ShenandoahEvacOOMHandler::enter_evacuation() { |
51 jint threads_in_evac = OrderAccess::load_acquire(&_threads_in_evac); |
51 jint threads_in_evac = Atomic::load_acquire(&_threads_in_evac); |
52 |
52 |
53 assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "sanity"); |
53 assert(!ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "sanity"); |
54 assert(!ShenandoahThreadLocalData::is_oom_during_evac(Thread::current()), "TL oom-during-evac must not be set"); |
54 assert(!ShenandoahThreadLocalData::is_oom_during_evac(Thread::current()), "TL oom-during-evac must not be set"); |
55 |
55 |
56 if ((threads_in_evac & OOM_MARKER_MASK) != 0) { |
56 if ((threads_in_evac & OOM_MARKER_MASK) != 0) { |
77 } |
77 } |
78 } |
78 } |
79 |
79 |
80 void ShenandoahEvacOOMHandler::leave_evacuation() { |
80 void ShenandoahEvacOOMHandler::leave_evacuation() { |
81 if (!ShenandoahThreadLocalData::is_oom_during_evac(Thread::current())) { |
81 if (!ShenandoahThreadLocalData::is_oom_during_evac(Thread::current())) { |
82 assert((OrderAccess::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) > 0, "sanity"); |
82 assert((Atomic::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) > 0, "sanity"); |
83 // NOTE: It's ok to simply decrement, even with mask set, because unmasked value is positive. |
83 // NOTE: It's ok to simply decrement, even with mask set, because unmasked value is positive. |
84 Atomic::dec(&_threads_in_evac); |
84 Atomic::dec(&_threads_in_evac); |
85 } else { |
85 } else { |
86 // If we get here, the current thread has already gone through the |
86 // If we get here, the current thread has already gone through the |
87 // OOM-during-evac protocol and has thus either never entered or successfully left |
87 // OOM-during-evac protocol and has thus either never entered or successfully left |
94 |
94 |
95 void ShenandoahEvacOOMHandler::handle_out_of_memory_during_evacuation() { |
95 void ShenandoahEvacOOMHandler::handle_out_of_memory_during_evacuation() { |
96 assert(ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "sanity"); |
96 assert(ShenandoahThreadLocalData::is_evac_allowed(Thread::current()), "sanity"); |
97 assert(!ShenandoahThreadLocalData::is_oom_during_evac(Thread::current()), "TL oom-during-evac must not be set"); |
97 assert(!ShenandoahThreadLocalData::is_oom_during_evac(Thread::current()), "TL oom-during-evac must not be set"); |
98 |
98 |
99 jint threads_in_evac = OrderAccess::load_acquire(&_threads_in_evac); |
99 jint threads_in_evac = Atomic::load_acquire(&_threads_in_evac); |
100 while (true) { |
100 while (true) { |
101 jint other = Atomic::cmpxchg((threads_in_evac - 1) | OOM_MARKER_MASK, |
101 jint other = Atomic::cmpxchg((threads_in_evac - 1) | OOM_MARKER_MASK, |
102 &_threads_in_evac, threads_in_evac); |
102 &_threads_in_evac, threads_in_evac); |
103 if (other == threads_in_evac) { |
103 if (other == threads_in_evac) { |
104 // Success: wait for other threads to get out of the protocol and return. |
104 // Success: wait for other threads to get out of the protocol and return. |
111 } |
111 } |
112 } |
112 } |
113 |
113 |
114 void ShenandoahEvacOOMHandler::clear() { |
114 void ShenandoahEvacOOMHandler::clear() { |
115 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at a safepoint"); |
115 assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at a safepoint"); |
116 assert((OrderAccess::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) == 0, "sanity"); |
116 assert((Atomic::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) == 0, "sanity"); |
117 OrderAccess::release_store_fence<jint>(&_threads_in_evac, 0); |
117 Atomic::release_store_fence<jint>(&_threads_in_evac, 0); |
118 } |
118 } |
119 |
119 |
120 ShenandoahEvacOOMScope::ShenandoahEvacOOMScope() { |
120 ShenandoahEvacOOMScope::ShenandoahEvacOOMScope() { |
121 ShenandoahHeap::heap()->enter_evacuation(); |
121 ShenandoahHeap::heap()->enter_evacuation(); |
122 } |
122 } |