jdk

Форк
0
/
gcLocker.cpp 
170 строк · 5.9 Кб
1
/*
2
 * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
 *
5
 * This code is free software; you can redistribute it and/or modify it
6
 * under the terms of the GNU General Public License version 2 only, as
7
 * published by the Free Software Foundation.
8
 *
9
 * This code is distributed in the hope that it will be useful, but WITHOUT
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12
 * version 2 for more details (a copy is included in the LICENSE file that
13
 * accompanied this code).
14
 *
15
 * You should have received a copy of the GNU General Public License version
16
 * 2 along with this work; if not, write to the Free Software Foundation,
17
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
 *
19
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
 * or visit www.oracle.com if you need additional information or have any
21
 * questions.
22
 *
23
 */
24

25
#include "precompiled.hpp"
26
#include "gc/shared/collectedHeap.hpp"
27
#include "gc/shared/gcLocker.hpp"
28
#include "gc/shared/gcTrace.hpp"
29
#include "memory/resourceArea.hpp"
30
#include "memory/universe.hpp"
31
#include "logging/log.hpp"
32
#include "runtime/atomic.hpp"
33
#include "runtime/javaThread.inline.hpp"
34
#include "runtime/safepoint.hpp"
35
#include "runtime/threadSMR.hpp"
36

37
volatile jint GCLocker::_jni_lock_count = 0;
38
volatile bool GCLocker::_needs_gc       = false;
39
unsigned int GCLocker::_total_collections = 0;
40

41
#ifdef ASSERT
42
volatile jint GCLocker::_debug_jni_lock_count = 0;
43
#endif
44

45

46
#ifdef ASSERT
47
void GCLocker::verify_critical_count() {
48
  if (SafepointSynchronize::is_at_safepoint()) {
49
    assert(!needs_gc() || _debug_jni_lock_count == _jni_lock_count, "must agree");
50
    int count = 0;
51
    // Count the number of threads with critical operations in progress
52
    JavaThreadIteratorWithHandle jtiwh;
53
    for (; JavaThread *thr = jtiwh.next(); ) {
54
      if (thr->in_critical()) {
55
        count++;
56
      }
57
    }
58
    if (_jni_lock_count != count) {
59
      log_error(gc, verify)("critical counts don't match: %d != %d", _jni_lock_count, count);
60
      jtiwh.rewind();
61
      for (; JavaThread *thr = jtiwh.next(); ) {
62
        if (thr->in_critical()) {
63
          log_error(gc, verify)(PTR_FORMAT " in_critical %d", p2i(thr), thr->in_critical());
64
        }
65
      }
66
    }
67
    assert(_jni_lock_count == count, "must be equal");
68
  }
69
}
70

71
// In debug mode track the locking state at all times
72
void GCLocker::increment_debug_jni_lock_count() {
73
  assert(_debug_jni_lock_count >= 0, "bad value");
74
  Atomic::inc(&_debug_jni_lock_count);
75
}
76

77
void GCLocker::decrement_debug_jni_lock_count() {
78
  assert(_debug_jni_lock_count > 0, "bad value");
79
  Atomic::dec(&_debug_jni_lock_count);
80
}
81
#endif
82

83
void GCLocker::log_debug_jni(const char* msg) {
84
  Log(gc, jni) log;
85
  if (log.is_debug()) {
86
    ResourceMark rm; // JavaThread::name() allocates to convert to UTF8
87
    log.debug("%s Thread \"%s\" %d locked.", msg, Thread::current()->name(), _jni_lock_count);
88
  }
89
}
90

91
bool GCLocker::is_at_safepoint() {
92
  return SafepointSynchronize::is_at_safepoint();
93
}
94

95
bool GCLocker::check_active_before_gc() {
96
  assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint");
97
  if (is_active() && !_needs_gc) {
98
    verify_critical_count();
99
    _needs_gc = true;
100
    GCLockerTracer::start_gc_locker(_jni_lock_count);
101
    log_debug_jni("Setting _needs_gc.");
102
  }
103
  return is_active();
104
}
105

106
void GCLocker::stall_until_clear() {
107
  assert(!JavaThread::current()->in_critical(), "Would deadlock");
108
  MonitorLocker ml(JNICritical_lock);
109

110
  if (needs_gc()) {
111
    GCLockerTracer::inc_stall_count();
112
    log_debug_jni("Allocation failed. Thread stalled by JNI critical section.");
113
  }
114

115
  // Wait for _needs_gc  to be cleared
116
  while (needs_gc()) {
117
    ml.wait();
118
  }
119
}
120

121
bool GCLocker::should_discard(GCCause::Cause cause, uint total_collections) {
122
  return (cause == GCCause::_gc_locker) &&
123
         (_total_collections != total_collections);
124
}
125

126
void GCLocker::jni_lock(JavaThread* thread) {
127
  assert(!thread->in_critical(), "shouldn't currently be in a critical region");
128
  MonitorLocker ml(JNICritical_lock);
129
  // Block entering threads if there's a pending GC request.
130
  while (needs_gc()) {
131
    // There's at least one thread that has not left the critical region (CR)
132
    // completely. When that last thread (no new threads can enter CR due to the
133
    // blocking) exits CR, it calls `jni_unlock`, which sets `_needs_gc`
134
    // to false and wakes up all blocked threads.
135
    // We would like to assert #threads in CR to be > 0, `_jni_lock_count > 0`
136
    // in the code, but it's too strong; it's possible that the last thread
137
    // has called `jni_unlock`, but not yet finished the call, e.g. initiating
138
    // a GCCause::_gc_locker GC.
139
    ml.wait();
140
  }
141
  thread->enter_critical();
142
  _jni_lock_count++;
143
  increment_debug_jni_lock_count();
144
}
145

146
void GCLocker::jni_unlock(JavaThread* thread) {
147
  assert(thread->in_last_critical(), "should be exiting critical region");
148
  MutexLocker mu(JNICritical_lock);
149
  _jni_lock_count--;
150
  decrement_debug_jni_lock_count();
151
  thread->exit_critical();
152
  if (needs_gc() && !is_active_internal()) {
153
    // We're the last thread out. Request a GC.
154
    // Capture the current total collections, to allow detection of
155
    // other collections that make this one unnecessary.  The value of
156
    // total_collections() is only changed at a safepoint, so there
157
    // must not be a safepoint between the lock becoming inactive and
158
    // getting the count, else there may be unnecessary GCLocker GCs.
159
    _total_collections = Universe::heap()->total_collections();
160
    GCLockerTracer::report_gc_locker();
161
    {
162
      // Must give up the lock while at a safepoint
163
      MutexUnlocker munlock(JNICritical_lock);
164
      log_debug_jni("Performing GC after exiting critical section.");
165
      Universe::heap()->collect(GCCause::_gc_locker);
166
    }
167
    _needs_gc = false;
168
    JNICritical_lock->notify_all();
169
  }
170
}
171

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.