Flutter Engine
The Flutter Engine
lockers.cc
Go to the documentation of this file.
1// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/lockers.h"
6#include "platform/assert.h"
7#include "vm/heap/safepoint.h"
8#include "vm/isolate.h"
9
10namespace dart {
11
13 int64_t millis) {
14 ASSERT(thread == Thread::Current());
16#if defined(DEBUG)
17 if (no_safepoint_scope_) {
19 }
20#endif
22 thread->EnterSafepoint();
23 Monitor::WaitResult result = monitor_->Wait(millis);
24 // First try a fast update of the thread state to indicate it is not at a
25 // safepoint anymore.
26 if (!thread->TryExitSafepoint()) {
27 // Fast update failed which means we could potentially be in the middle
28 // of a safepoint operation and need to block for it.
29 monitor_->Exit();
30 thread->ExitSafepointUsingLock();
31 monitor_->Enter();
32 }
34#if defined(DEBUG)
35 if (no_safepoint_scope_) {
37 }
38#endif
39 return result;
40}
41
43 : StackResource(thread), mutex_(mutex) {
44 ASSERT(mutex != nullptr);
45 if (!mutex_->TryLock()) {
46 // We did not get the lock and could potentially block, so transition
47 // accordingly.
49 if (thread != nullptr) {
50 TransitionVMToBlocked transition(thread);
51 mutex->Lock();
52 } else {
53 mutex->Lock();
54 }
55 }
56}
57
58void SafepointMonitorLocker::AcquireLock() {
59 ASSERT(monitor_ != nullptr);
60 if (!monitor_->TryEnter()) {
61 // We did not get the lock and could potentially block, so transition
62 // accordingly.
63 Thread* thread = Thread::Current();
64 if (thread != nullptr) {
65 TransitionVMToBlocked transition(thread);
66 monitor_->Enter();
67 } else {
68 monitor_->Enter();
69 }
70 }
71}
72
73void SafepointMonitorLocker::ReleaseLock() {
74 monitor_->Exit();
75}
76
78 Thread* thread = Thread::Current();
79 if (thread != nullptr) {
81 {
82 TransitionVMToBlocked transition(thread);
83 result = monitor_->Wait(millis);
84 }
85 return result;
86 } else {
87 return monitor_->Wait(millis);
88 }
89}
90
91#if defined(DEBUG)
92bool SafepointRwLock::IsCurrentThreadReader() {
95 return true;
96 }
97 MonitorLocker ml(&monitor_);
98 for (intptr_t i = readers_ids_.length() - 1; i >= 0; i--) {
99 if (readers_ids_.At(i) == id) {
100 return true;
101 }
102 }
103 return false;
104}
105#endif // defined(DEBUG)
106
107bool SafepointRwLock::EnterRead() {
108 // No need to safepoint if the current thread is not attached.
109 auto thread = Thread::Current();
110 // Attempt to acquire a lock while owning a safepoint could lead to a deadlock
111 // (some other thread might be forced to a safepoint while holding this lock).
112 //
113 // Though if the lock was already acquired by this thread before entering a
114 // safepoint, we do allow the nested acquire (which is a NOP).
115 DEBUG_ASSERT(thread == nullptr || thread->CanAcquireSafepointLocks() ||
116 IsCurrentThreadReader());
117
118 const bool can_block_without_safepoint = thread == nullptr;
119
120 bool acquired_read_lock = false;
121 if (!TryEnterRead(can_block_without_safepoint, &acquired_read_lock)) {
122 // Important: must never hold monitor_ when blocking for safepoint.
123 TransitionVMToBlocked transition(thread);
124 const bool ok = TryEnterRead(/*can_block=*/true, &acquired_read_lock);
126 RELEASE_ASSERT(acquired_read_lock);
127 }
128 return acquired_read_lock;
129}
130
131bool SafepointRwLock::TryEnterRead(bool can_block, bool* acquired_read_lock) {
132 MonitorLocker ml(&monitor_);
133 if (IsCurrentThreadWriter()) {
134 *acquired_read_lock = false;
135 return true;
136 }
137 if (can_block) {
138 while (state_ < 0) {
139 ml.Wait();
140 }
141 }
142 if (state_ >= 0) {
143 ++state_;
144 DEBUG_ONLY(readers_ids_.Add(OSThread::GetCurrentThreadId()));
145 *acquired_read_lock = true;
146 return true;
147 }
148 return false;
149}
150
151void SafepointRwLock::LeaveRead() {
152 MonitorLocker ml(&monitor_);
153 ASSERT(state_ > 0);
154#if defined(DEBUG)
155 {
156 intptr_t i = readers_ids_.length() - 1;
158 while (i >= 0) {
159 if (readers_ids_.At(i) == id) {
160 readers_ids_.RemoveAt(i);
161 break;
162 }
163 i--;
164 }
165 ASSERT(i >= 0);
166 }
167#endif
168 if (--state_ == 0) {
169 ml.NotifyAll();
170 }
171}
172
173void SafepointRwLock::EnterWrite() {
174 // No need to safepoint if the current thread is not attached.
175 auto thread = Thread::Current();
176 // Attempt to acquire a lock while owning a safepoint could lead to a deadlock
177 // (some other thread might be forced to a safepoint while holding this lock).
178 //
179 // Though if the lock was already acquired by this thread before entering a
180 // safepoint, we do allow the nested acquire (which is a NOP).
181 DEBUG_ASSERT(thread == nullptr || thread->CanAcquireSafepointLocks() ||
183
184 const bool can_block_without_safepoint = thread == nullptr;
185
186 if (!TryEnterWrite(can_block_without_safepoint)) {
187 // Important: must never hold monitor_ when blocking for safepoint.
188 TransitionVMToBlocked transition(thread);
189 const bool ok = TryEnterWrite(/*can_block=*/true);
191 }
192}
193
194bool SafepointRwLock::TryEnterWrite(bool can_block) {
195 MonitorLocker ml(&monitor_);
196 if (IsCurrentThreadWriter()) {
197 state_--;
198 return true;
199 }
200 if (can_block) {
201 while (state_ != 0) {
202 ml.Wait();
203 }
204 }
205 if (state_ == 0) {
206 writer_id_ = OSThread::GetCurrentThreadId();
207 state_ = -1;
208 return true;
209 }
210 return false;
211}
212
213void SafepointRwLock::LeaveWrite() {
214 MonitorLocker ml(&monitor_);
215 ASSERT(state_ < 0);
216 if (++state_ < 0) {
217 return;
218 }
219 writer_id_ = OSThread::kInvalidThreadId;
220 ml.NotifyAll();
221}
222
223} // namespace dart
static bool ok(int result)
#define DEBUG_ASSERT(cond)
Definition: assert.h:321
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
Monitor::WaitResult WaitWithSafepointCheck(Thread *thread, int64_t millis=Monitor::kNoTimeout)
Definition: lockers.cc:12
static ThreadId GetCurrentThreadId()
static const ThreadId kInvalidThreadId
Definition: os_thread.h:248
Monitor::WaitResult Wait(int64_t millis=Monitor::kNoTimeout)
Definition: lockers.cc:77
SafepointMutexLocker(Mutex *mutex)
Definition: lockers.h:231
DEBUG_ONLY(bool IsCurrentThreadReader())
bool IsCurrentThreadWriter()
Definition: lockers.h:354
ThreadState * thread() const
Definition: allocation.h:33
void set_execution_state(ExecutionState state)
Definition: thread.h:1048
bool CanAcquireSafepointLocks() const
Definition: thread.cc:1372
void DecrementNoSafepointScopeDepth()
Definition: thread.h:733
static Thread * Current()
Definition: thread.h:362
void EnterSafepoint()
Definition: thread.h:1076
ExecutionState execution_state() const
Definition: thread.h:1040
@ kThreadInBlockedState
Definition: thread.h:1037
bool TryExitSafepoint()
Definition: thread.h:1087
void IncrementNoSafepointScopeDepth()
Definition: thread.h:726
#define ASSERT(E)
GAsyncResult * result
Definition: dart_vm.cc:33
pthread_t ThreadId