jdk

Форк
0
/
jvmtiRawMonitor.cpp 
432 строки · 12.6 Кб
1
/*
2
 * Copyright (c) 2003, 2023, 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 "memory/allocation.inline.hpp"
27
#include "prims/jvmtiRawMonitor.hpp"
28
#include "runtime/atomic.hpp"
29
#include "runtime/interfaceSupport.inline.hpp"
30
#include "runtime/javaThread.hpp"
31
#include "runtime/orderAccess.hpp"
32
#include "runtime/threads.hpp"
33

34
JvmtiRawMonitor::QNode::QNode(Thread* thread) : _next(nullptr), _prev(nullptr),
35
                                                _event(thread->_ParkEvent),
36
                                                _notified(0), _t_state(TS_RUN) {
37
}
38

39
GrowableArray<JvmtiRawMonitor*>* JvmtiPendingMonitors::_monitors =
40
  new (mtServiceability) GrowableArray<JvmtiRawMonitor*>(1, mtServiceability);
41

42
void JvmtiPendingMonitors::transition_raw_monitors() {
43
  assert((Threads::number_of_threads()==1),
44
         "Java thread has not been created yet or more than one java thread "
45
         "is running. Raw monitor transition will not work");
46
  JavaThread* current_java_thread = JavaThread::current();
47
  {
48
    ThreadToNativeFromVM ttnfvm(current_java_thread);
49
    for (int i = 0; i < count(); i++) {
50
      JvmtiRawMonitor* rmonitor = monitors()->at(i);
51
      rmonitor->raw_enter(current_java_thread);
52
    }
53
  }
54
  // pending monitors are converted to real monitor so delete them all.
55
  dispose();
56
}
57

58
//
59
// class JvmtiRawMonitor
60
//
61

62
JvmtiRawMonitor::JvmtiRawMonitor(const char* name) : _owner(nullptr),
63
                                                     _recursions(0),
64
                                                     _entry_list(nullptr),
65
                                                     _wait_set(nullptr),
66
                                                     _magic(JVMTI_RM_MAGIC),
67
                                                     _name(nullptr) {
68
#ifdef ASSERT
69
  _name = strcpy(NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtInternal), name);
70
#endif
71
}
72

73
JvmtiRawMonitor::~JvmtiRawMonitor() {
74
#ifdef ASSERT
75
  FreeHeap(_name);
76
#endif
77
  _magic = 0;
78
}
79

80

81
bool
82
JvmtiRawMonitor::is_valid() {
83
  jlong value = 0;
84

85
  // This object might not be a JvmtiRawMonitor so we can't assume
86
  // the _magic field is properly aligned. Get the value in a safe
87
  // way and then check against JVMTI_RM_MAGIC.
88

89
  switch (sizeof(_magic)) {
90
  case 2:
91
    value = Bytes::get_native_u2((address)&_magic);
92
    break;
93

94
  case 4:
95
    value = Bytes::get_native_u4((address)&_magic);
96
    break;
97

98
  case 8:
99
    value = Bytes::get_native_u8((address)&_magic);
100
    break;
101

102
  default:
103
    guarantee(false, "_magic field is an unexpected size");
104
  }
105

106
  return value == JVMTI_RM_MAGIC;
107
}
108

109
// -------------------------------------------------------------------------
110
// The JVMTI raw monitor subsystem is entirely distinct from normal
111
// java-synchronization or jni-synchronization.  JVMTI raw monitors are not
112
// associated with objects.  They can be implemented in any manner
113
// that makes sense.  The original implementors decided to piggy-back
114
// the raw-monitor implementation on the existing Java ObjectMonitor mechanism.
115
// Now we just use a simplified form of that ObjectMonitor code.
116
//
117
// Note that we use the single RawMonitor_lock to protect queue operations for
118
// _all_ raw monitors.  This is a scalability impediment, but since raw monitor usage
119
// is fairly rare, this is not of concern.  The RawMonitor_lock can not
120
// be held indefinitely.  The critical sections must be short and bounded.
121
//
122
// -------------------------------------------------------------------------
123

124
void JvmtiRawMonitor::simple_enter(Thread* self) {
125
  for (;;) {
126
    if (Atomic::replace_if_null(&_owner, self)) {
127
      if (self->is_Java_thread()) {
128
        Continuation::pin(JavaThread::cast(self));
129
      }
130
      return;
131
    }
132

133
    QNode node(self);
134
    self->_ParkEvent->reset();     // strictly optional
135
    node._t_state = QNode::TS_ENTER;
136

137
    RawMonitor_lock->lock_without_safepoint_check();
138
    node._next = _entry_list;
139
    _entry_list = &node;
140
    OrderAccess::fence();
141
    if (_owner == nullptr && Atomic::replace_if_null(&_owner, self)) {
142
      _entry_list = node._next;
143
      RawMonitor_lock->unlock();
144
      if (self->is_Java_thread()) {
145
        Continuation::pin(JavaThread::cast(self));
146
      }
147
      return;
148
    }
149
    RawMonitor_lock->unlock();
150
    while (node._t_state == QNode::TS_ENTER) {
151
      self->_ParkEvent->park();
152
    }
153
  }
154
}
155

156
void JvmtiRawMonitor::simple_exit(Thread* self) {
157
  guarantee(_owner == self, "invariant");
158
  Atomic::release_store(&_owner, (Thread*)nullptr);
159
  OrderAccess::fence();
160
  if (self->is_Java_thread()) {
161
    Continuation::unpin(JavaThread::cast(self));
162
  }
163
  if (_entry_list == nullptr) {
164
    return;
165
  }
166

167
  RawMonitor_lock->lock_without_safepoint_check();
168
  QNode* w = _entry_list;
169
  if (w != nullptr) {
170
    _entry_list = w->_next;
171
  }
172
  RawMonitor_lock->unlock();
173
  if (w != nullptr) {
174
    guarantee(w ->_t_state == QNode::TS_ENTER, "invariant");
175
    // Once we set _t_state to TS_RUN the waiting thread can complete
176
    // simple_enter and 'w' is pointing into random stack space. So we have
177
    // to ensure we extract the ParkEvent (which is in type-stable memory)
178
    // before we set the state, and then don't access 'w'.
179
    ParkEvent* ev = w->_event;
180
    OrderAccess::loadstore();
181
    w->_t_state = QNode::TS_RUN;
182
    OrderAccess::fence();
183
    ev->unpark();
184
  }
185
  return;
186
}
187

188
inline void JvmtiRawMonitor::enqueue_waiter(QNode& node) {
189
  node._notified = 0;
190
  node._t_state = QNode::TS_WAIT;
191
  RawMonitor_lock->lock_without_safepoint_check();
192
  node._next = _wait_set;
193
  _wait_set = &node;
194
  RawMonitor_lock->unlock();
195
}
196

197
inline void JvmtiRawMonitor::dequeue_waiter(QNode& node) {
198
  // If thread still resides on the waitset then unlink it.
199
  // Double-checked locking -- the usage is safe in this context
200
  // as _t_state is volatile and the lock-unlock operators are
201
  // serializing (barrier-equivalent).
202

203
  if (node._t_state == QNode::TS_WAIT) {
204
    RawMonitor_lock->lock_without_safepoint_check();
205
    if (node._t_state == QNode::TS_WAIT) {
206
      // Simple O(n) unlink, but performance isn't critical here.
207
      QNode* p;
208
      QNode* q = nullptr;
209
      for (p = _wait_set; p != &node; p = p->_next) {
210
        q = p;
211
      }
212
      guarantee(p == &node, "invariant");
213
      if (q == nullptr) {
214
        guarantee (p == _wait_set, "invariant");
215
        _wait_set = p->_next;
216
      } else {
217
        guarantee(p == q->_next, "invariant");
218
        q->_next = p->_next;
219
      }
220
      node._t_state = QNode::TS_RUN;
221
    }
222
    RawMonitor_lock->unlock();
223
  }
224

225
  guarantee(node._t_state == QNode::TS_RUN, "invariant");
226
}
227

228
// simple_wait is not quite so simple as we have to deal with the interaction
229
// with the Thread interrupt state, which resides in the java.lang.Thread object.
230
// That state must only be accessed while _thread_in_vm and requires proper thread-state
231
// transitions.
232
// Returns M_OK usually, but M_INTERRUPTED if the thread is a JavaThread and was
233
// interrupted.
234
// Note:
235
//  - simple_wait never reenters the monitor.
236
//  - A JavaThread must be in native.
237
int JvmtiRawMonitor::simple_wait(Thread* self, jlong millis) {
238
  guarantee(_owner == self  , "invariant");
239
  guarantee(_recursions == 0, "invariant");
240

241
  QNode node(self);
242
  enqueue_waiter(node);
243

244
  simple_exit(self);
245
  guarantee(_owner != self, "invariant");
246

247
  int ret = M_OK;
248
  if (self->is_Java_thread()) {
249
    JavaThread* jt = JavaThread::cast(self);
250
    guarantee(jt->thread_state() == _thread_in_native, "invariant");
251
    {
252
      // This transition must be after we exited the monitor.
253
      ThreadInVMfromNative tivmfn(jt);
254
      if (jt->get_and_clear_interrupted()) {
255
        ret = M_INTERRUPTED;
256
      } else {
257
        ThreadBlockInVM tbivm(jt);
258
        if (millis <= 0) {
259
          self->_ParkEvent->park();
260
        } else {
261
          self->_ParkEvent->park(millis);
262
        }
263
        // Return to VM before post-check of interrupt state
264
      }
265
      if (jt->get_and_clear_interrupted()) {
266
        ret = M_INTERRUPTED;
267
      }
268
    }
269
  } else {
270
    if (millis <= 0) {
271
      self->_ParkEvent->park();
272
    } else {
273
      self->_ParkEvent->park(millis);
274
    }
275
  }
276

277
  dequeue_waiter(node);
278

279
  return ret;
280
}
281

282
void JvmtiRawMonitor::simple_notify(Thread* self, bool all) {
283
  guarantee(_owner == self, "invariant");
284
  if (_wait_set == nullptr) {
285
    return;
286
  }
287

288
  // We have two options:
289
  // A. Transfer the threads from the _wait_set to the _entry_list
290
  // B. Remove the thread from the _wait_set and unpark() it.
291
  //
292
  // We use (B), which is crude and results in lots of futile
293
  // context switching.  In particular (B) induces lots of contention.
294

295
  ParkEvent* ev = nullptr;       // consider using a small auto array ...
296
  RawMonitor_lock->lock_without_safepoint_check();
297
  for (;;) {
298
    QNode* w = _wait_set;
299
    if (w == nullptr) break;
300
    _wait_set = w->_next;
301
    if (ev != nullptr) {
302
      ev->unpark();
303
      ev = nullptr;
304
    }
305
    ev = w->_event;
306
    OrderAccess::loadstore();
307
    w->_t_state = QNode::TS_RUN;
308
    OrderAccess::storeload();
309
    if (!all) {
310
      break;
311
    }
312
  }
313
  RawMonitor_lock->unlock();
314
  if (ev != nullptr) {
315
    ev->unpark();
316
  }
317
  return;
318
}
319

320
void JvmtiRawMonitor::ExitOnSuspend::operator()(JavaThread* current) {
321
  // We must exit the monitor in case of a safepoint.
322
  _rm->simple_exit(current);
323
  _rm_exited = true;
324
}
325

326
// JavaThreads will enter here with state _thread_in_native.
327
void JvmtiRawMonitor::raw_enter(Thread* self) {
328
  // TODO Atomic::load on _owner field
329
  if (_owner == self) {
330
    _recursions++;
331
    return;
332
  }
333

334
  self->set_current_pending_raw_monitor(this);
335

336
  if (!self->is_Java_thread()) {
337
    simple_enter(self);
338
  } else {
339
    JavaThread* jt = JavaThread::cast(self);
340
    guarantee(jt->thread_state() == _thread_in_native, "invariant");
341
    ThreadInVMfromNative tivmfn(jt);
342
    for (;;) {
343
      ExitOnSuspend eos(this);
344
      {
345
        ThreadBlockInVMPreprocess<ExitOnSuspend> tbivmp(jt, eos, true /* allow_suspend */);
346
        simple_enter(jt);
347
      }
348
      if (!eos.monitor_exited()) {
349
        break;
350
      }
351
    }
352
  }
353

354
  self->set_current_pending_raw_monitor(nullptr);
355

356
  guarantee(_owner == self, "invariant");
357
  guarantee(_recursions == 0, "invariant");
358
}
359

360
int JvmtiRawMonitor::raw_exit(Thread* self) {
361
  if (self != _owner) {
362
    return M_ILLEGAL_MONITOR_STATE;
363
  }
364
  if (_recursions > 0) {
365
    _recursions--;
366
  } else {
367
    simple_exit(self);
368
  }
369

370
  return M_OK;
371
}
372

373
int JvmtiRawMonitor::raw_wait(jlong millis, Thread* self) {
374
  if (self != _owner) {
375
    return M_ILLEGAL_MONITOR_STATE;
376
  }
377

378
  int ret = M_OK;
379

380
  // To avoid spurious wakeups we reset the parkevent. This is strictly optional.
381
  // The caller must be able to tolerate spurious returns from raw_wait().
382
  self->_ParkEvent->reset();
383
  OrderAccess::fence();
384

385
  int save = _recursions;
386
  _recursions = 0;
387
  ret = simple_wait(self, millis);
388

389
  // Now we need to re-enter the monitor. For JavaThreads
390
  // we need to manage suspend requests.
391
  if (self->is_Java_thread()) { // JavaThread re-enter
392
    JavaThread* jt = JavaThread::cast(self);
393
    ThreadInVMfromNative tivmfn(jt);
394
    for (;;) {
395
      ExitOnSuspend eos(this);
396
      {
397
        ThreadBlockInVMPreprocess<ExitOnSuspend> tbivmp(jt, eos, true /* allow_suspend */);
398
        simple_enter(jt);
399
      }
400
      if (!eos.monitor_exited()) {
401
        break;
402
      }
403
    }
404
    if (jt->get_and_clear_interrupted()) {
405
      ret = M_INTERRUPTED;
406
    }
407
  } else { // Non-JavaThread re-enter
408
    assert(ret != M_INTERRUPTED, "Only JavaThreads can be interrupted");
409
    simple_enter(self);
410
  }
411

412
  _recursions = save;
413

414
  guarantee(self == _owner, "invariant");
415
  return ret;
416
}
417

418
int JvmtiRawMonitor::raw_notify(Thread* self) {
419
  if (self != _owner) {
420
    return M_ILLEGAL_MONITOR_STATE;
421
  }
422
  simple_notify(self, false);
423
  return M_OK;
424
}
425

426
int JvmtiRawMonitor::raw_notifyAll(Thread* self) {
427
  if (self != _owner) {
428
    return M_ILLEGAL_MONITOR_STATE;
429
  }
430
  simple_notify(self, true);
431
  return M_OK;
432
}
433

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

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

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

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