1 /*
2 * Copyright (c) 2014, 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/gc_globals.hpp"
27 #include "gc/shared/suspendibleThreadSet.hpp"
28 #include "runtime/mutexLocker.hpp"
29 #include "runtime/semaphore.hpp"
30 #include "runtime/thread.inline.hpp"
31
32 uint SuspendibleThreadSet::_nthreads = 0;
33 uint SuspendibleThreadSet::_nthreads_stopped = 0;
34 bool SuspendibleThreadSet::_suspend_all = false;
35 double SuspendibleThreadSet::_suspend_all_start = 0.0;
36
37 static Semaphore* _synchronize_wakeup = NULL;
38
SuspendibleThreadSet_init()39 void SuspendibleThreadSet_init() {
40 assert(_synchronize_wakeup == NULL, "STS already initialized");
41 _synchronize_wakeup = new Semaphore();
42 }
43
is_synchronized()44 bool SuspendibleThreadSet::is_synchronized() {
45 assert_lock_strong(STS_lock);
46 assert(_nthreads_stopped <= _nthreads, "invariant");
47 return _nthreads_stopped == _nthreads;
48 }
49
join()50 void SuspendibleThreadSet::join() {
51 assert(!Thread::current()->is_suspendible_thread(), "Thread already joined");
52 MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag);
53 while (_suspend_all) {
54 ml.wait();
55 }
56 _nthreads++;
57 DEBUG_ONLY(Thread::current()->set_suspendible_thread();)
58 }
59
leave()60 void SuspendibleThreadSet::leave() {
61 assert(Thread::current()->is_suspendible_thread(), "Thread not joined");
62 MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag);
63 assert(_nthreads > 0, "Invalid");
64 DEBUG_ONLY(Thread::current()->clear_suspendible_thread();)
65 _nthreads--;
66 if (_suspend_all && is_synchronized()) {
67 // This leave completes a request, so inform the requestor.
68 _synchronize_wakeup->signal();
69 }
70 }
71
yield()72 void SuspendibleThreadSet::yield() {
73 assert(Thread::current()->is_suspendible_thread(), "Must have joined");
74 MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag);
75 if (_suspend_all) {
76 _nthreads_stopped++;
77 if (is_synchronized()) {
78 if (ConcGCYieldTimeout > 0) {
79 double now = os::elapsedTime();
80 guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay");
81 }
82 // This yield completes the request, so inform the requestor.
83 _synchronize_wakeup->signal();
84 }
85 while (_suspend_all) {
86 ml.wait();
87 }
88 assert(_nthreads_stopped > 0, "Invalid");
89 _nthreads_stopped--;
90 }
91 }
92
synchronize()93 void SuspendibleThreadSet::synchronize() {
94 assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
95 if (ConcGCYieldTimeout > 0) {
96 _suspend_all_start = os::elapsedTime();
97 }
98 {
99 MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag);
100 assert(!_suspend_all, "Only one at a time");
101 _suspend_all = true;
102 if (is_synchronized()) {
103 return;
104 }
105 } // Release lock before semaphore wait.
106
107 // Semaphore initial count is zero. To reach here, there must be at
108 // least one not yielded thread in the set, e.g. is_synchronized()
109 // was false before the lock was released. A thread in the set will
110 // signal the semaphore iff it is the last to yield or leave while
111 // there is an active suspend request. So there will be exactly one
112 // signal, which will increment the semaphore count to one, which
113 // will then be consumed by this wait, returning it to zero. No
114 // thread can exit yield or enter the set until desynchronize is
115 // called, so there are no further opportunities for the semaphore
116 // being signaled until we get back here again for some later
117 // synchronize call. Hence, there is no need to re-check for
118 // is_synchronized after the wait; it will always be true there.
119 _synchronize_wakeup->wait();
120
121 #ifdef ASSERT
122 MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag);
123 assert(_suspend_all, "STS not synchronizing");
124 assert(is_synchronized(), "STS not synchronized");
125 #endif
126 }
127
desynchronize()128 void SuspendibleThreadSet::desynchronize() {
129 assert(Thread::current()->is_VM_thread(), "Must be the VM thread");
130 MonitorLocker ml(STS_lock, Mutex::_no_safepoint_check_flag);
131 assert(_suspend_all, "STS not synchronizing");
132 assert(is_synchronized(), "STS not synchronized");
133 _suspend_all = false;
134 ml.notify_all();
135 }
136