Flutter Engine
The Flutter Engine
lockers.h
Go to the documentation of this file.
1// Copyright (c) 2012, 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#ifndef RUNTIME_VM_LOCKERS_H_
6#define RUNTIME_VM_LOCKERS_H_
7
8#include "platform/assert.h"
10#include "vm/allocation.h"
11#include "vm/globals.h"
12#include "vm/os_thread.h"
13#include "vm/thread.h"
14
15namespace dart {
16
17const bool kNoSafepointScope = true;
18const bool kDontAssertNoSafepointScope = false;
19
20/*
21 * Normal mutex locker :
22 * This locker abstraction should only be used when the enclosing code can
23 * not trigger a safepoint. In debug mode this class increments the
24 * no_safepoint_scope_depth variable for the current thread when the lock is
25 * taken and decrements it when the lock is released. NOTE: please do not use
26 * the passed in mutex object independent of the locker class, For example the
27 * code below will not assert correctly:
28 * {
29 * MutexLocker ml(m);
30 * ....
31 * m->Exit();
32 * ....
33 * m->Enter();
34 * ...
35 * }
36 * Always use the locker object even when the lock needs to be released
37 * temporarily, e.g:
38 * {
39 * MutexLocker ml(m);
40 * ....
41 * ml.Exit();
42 * ....
43 * ml.Enter();
44 * ...
45 * }
46 */
47class MutexLocker : public ValueObject {
48 public:
49 explicit MutexLocker(Mutex* mutex)
50 :
51#if defined(DEBUG)
52 no_safepoint_scope_(true),
53#endif
54 mutex_(mutex) {
55 ASSERT(mutex != nullptr);
56#if defined(DEBUG)
57 Thread* thread = Thread::Current();
58 if ((thread != nullptr) &&
61 } else {
62 no_safepoint_scope_ = false;
63 }
64#endif
65 mutex_->Lock();
66 }
67
68 virtual ~MutexLocker() {
69 mutex_->Unlock();
70#if defined(DEBUG)
71 if (no_safepoint_scope_) {
73 }
74#endif
75 }
76
77 void Lock() const {
78#if defined(DEBUG)
79 if (no_safepoint_scope_) {
81 }
82#endif
83 mutex_->Lock();
84 }
85 void Unlock() const {
86 mutex_->Unlock();
87#if defined(DEBUG)
88 if (no_safepoint_scope_) {
90 }
91#endif
92 }
93
94 private:
95 DEBUG_ONLY(bool no_safepoint_scope_;)
96 Mutex* const mutex_;
97
98 DISALLOW_COPY_AND_ASSIGN(MutexLocker);
99};
100
101/*
102 * Normal monitor locker :
103 * This locker abstraction should only be used when the enclosed code can
104 * not trigger a safepoint. In debug mode this class increments the
105 * no_safepoint_scope_depth variable for the current thread when the lock is
106 * taken and decrements it when the lock is released. NOTE: please do not use
107 * the passed in mutex object independent of the locker class, For example the
108 * code below will not assert correctly:
109 * {
110 * MonitorLocker ml(m);
111 * ....
112 * m->Exit();
113 * ....
114 * m->Enter();
115 * ...
116 * }
117 * Always use the locker object even when the lock needs to be released
118 * temporarily, e.g:
119 * {
120 * MonitorLocker ml(m);
121 * ....
122 * ml.Exit();
123 * ....
124 * ml.Enter();
125 * ...
126 * }
127 */
129 public:
130 explicit MonitorLocker(Monitor* monitor, bool no_safepoint_scope = true)
131 : monitor_(monitor), no_safepoint_scope_(no_safepoint_scope) {
132 ASSERT(monitor != nullptr);
133#if defined(DEBUG)
134 if (no_safepoint_scope_) {
135 Thread* thread = Thread::Current();
136 if (thread != nullptr) {
138 } else {
139 no_safepoint_scope_ = false;
140 }
141 }
142#endif
143 monitor_->Enter();
144 }
145
146 virtual ~MonitorLocker() {
147 monitor_->Exit();
148#if defined(DEBUG)
149 if (no_safepoint_scope_) {
151 }
152#endif
153 }
154
155 void Enter() const {
156#if defined(DEBUG)
157 if (no_safepoint_scope_) {
159 }
160#endif
161 monitor_->Enter();
162 }
163 void Exit() const {
164 monitor_->Exit();
165#if defined(DEBUG)
166 if (no_safepoint_scope_) {
168 }
169#endif
170 }
171
173 return monitor_->Wait(millis);
174 }
175
177 Thread* thread,
178 int64_t millis = Monitor::kNoTimeout);
179
181 return monitor_->WaitMicros(micros);
182 }
183
184 void Notify() { monitor_->Notify(); }
185
186 void NotifyAll() { monitor_->NotifyAll(); }
187
188 private:
189 Monitor* const monitor_;
190 bool no_safepoint_scope_;
191
192 DISALLOW_COPY_AND_ASSIGN(MonitorLocker);
193};
194
195// Leaves the given monitor during the scope of the object.
197 public:
199 : monitor_locker_(monitor) {
200 monitor_locker_->Exit();
201 }
202
203 virtual ~MonitorLeaveScope() { monitor_locker_->Enter(); }
204
205 private:
206 MonitorLocker* const monitor_locker_;
207
208 DISALLOW_COPY_AND_ASSIGN(MonitorLeaveScope);
209};
210
211/*
212 * Safepoint mutex locker :
213 * This locker abstraction should be used when the enclosing code could
214 * potentially trigger a safepoint.
215 * This locker ensures that other threads that try to acquire the same lock
216 * will be marked as being at a safepoint if they get blocked trying to
217 * acquire the lock.
218 * NOTE: please do not use the passed in mutex object independent of the locker
219 * class, For example the code below will not work correctly:
220 * {
221 * SafepointMutexLocker ml(m);
222 * ....
223 * m->Exit();
224 * ....
225 * m->Enter();
226 * ...
227 * }
228 */
230 public:
232 : SafepointMutexLocker(ThreadState::Current(), mutex) {}
234 virtual ~SafepointMutexLocker() { mutex_->Unlock(); }
235
236 private:
237 Mutex* const mutex_;
238
239 DISALLOW_COPY_AND_ASSIGN(SafepointMutexLocker);
240};
241
242/*
243 * Safepoint monitor locker :
244 * This locker abstraction should be used when the enclosing code could
245 * potentially trigger a safepoint.
246 * This locker ensures that other threads that try to acquire the same lock
247 * will be marked as being at a safepoint if they get blocked trying to
248 * acquire the lock.
249 * NOTE: please do not use the passed in monitor object independent of the
250 * locker class, For example the code below will not work correctly:
251 * {
252 * SafepointMonitorLocker ml(m);
253 * ....
254 * m->Exit();
255 * ....
256 * m->Enter();
257 * ...
258 * }
259 */
261 public:
262 explicit SafepointMonitorLocker(Monitor* monitor) : monitor_(monitor) {
263 AcquireLock();
264 }
265 virtual ~SafepointMonitorLocker() { ReleaseLock(); }
266
268
269 void NotifyAll() { monitor_->NotifyAll(); }
270
271 private:
273
274 void AcquireLock();
275 void ReleaseLock();
276
277 Monitor* const monitor_;
278
280};
281
283 public:
285 : locker_(locker) {
286 locker_->ReleaseLock();
287 }
288 ~SafepointMonitorUnlockScope() { locker_->AcquireLock(); }
289
290 private:
291 SafepointMonitorLocker* locker_;
292};
293
294class RwLock {
295 public:
298
300 return writer_id_ == OSThread::GetCurrentThreadId();
301 }
302
303 private:
304 friend class ReadRwLocker;
305 friend class WriteRwLocker;
306
307 void EnterRead() {
308 MonitorLocker ml(&monitor_);
309 while (state_ == -1) {
310 ml.Wait();
311 }
312 ++state_;
313 }
314 void LeaveRead() {
315 MonitorLocker ml(&monitor_);
316 ASSERT(state_ > 0);
317 if (--state_ == 0) {
318 ml.NotifyAll();
319 }
320 }
321
322 void EnterWrite() {
323 MonitorLocker ml(&monitor_);
324 while (state_ != 0) {
325 ml.Wait();
326 }
327 state_ = -1;
328 writer_id_ = OSThread::GetCurrentThreadId();
329 }
330
331 void LeaveWrite() {
332 MonitorLocker ml(&monitor_);
333 ASSERT(state_ == -1);
334 state_ = 0;
335 writer_id_ = OSThread::kInvalidThreadId;
336 ml.NotifyAll();
337 }
338
339 Monitor monitor_;
340 // [state_] > 0 : The lock is held by multiple readers.
341 // [state_] == 0 : The lock is free (no readers/writers).
342 // [state_] == -1: The lock is held by a single writer.
343 intptr_t state_ = 0;
345};
346
348 public:
351
352 DEBUG_ONLY(bool IsCurrentThreadReader());
353
355 return writer_id_ == OSThread::GetCurrentThreadId();
356 }
357
358 private:
361
362 // returns [true] if read lock was acquired,
363 // returns [false] if the thread didn't have to acquire read lock due
364 // to the thread already holding write lock
365 bool EnterRead();
366 bool TryEnterRead(bool can_block, bool* acquired_read_lock);
367 void LeaveRead();
368
369 void EnterWrite();
370 bool TryEnterWrite(bool can_block);
371 void LeaveWrite();
372
373 // We maintain an invariant that this monitor is never locked for long periods
374 // of time: Any thread that acquired this monitor must always be able to do
375 // it's work and release it (or wait on the monitor which will also release
376 // it).
377 //
378 // In particular we must ensure the monitor is never held and then a potential
379 // safepoint operation is triggered, since another thread could try to acquire
380 // the lock and it would deadlock.
381 Monitor monitor_;
382
383 // [state_] > 0 : The lock is held by multiple readers.
384 // [state_] == 0 : The lock is free (no readers/writers).
385 // [state_] < 0 : The lock is held by a single writer (possibly nested).
386 intptr_t state_ = 0;
387
390};
391
392/*
393 * Locks a given [RwLock] for reading purposes.
394 *
395 * It will block while the lock is held by a writer.
396 *
397 * If this locker is long'jmped over (e.g. on a background compiler thread) the
398 * lock will be freed.
399 *
400 * NOTE: If the locking operation blocks (due to a writer) it will not check
401 * for a pending safepoint operation.
402 */
404 public:
405 ReadRwLocker(ThreadState* thread_state, RwLock* rw_lock)
406 : StackResource(thread_state), rw_lock_(rw_lock) {
407 rw_lock_->EnterRead();
408 }
409 ~ReadRwLocker() { rw_lock_->LeaveRead(); }
410
411 private:
412 RwLock* rw_lock_;
413};
414
415/*
416 * In addition to what [ReadRwLocker] does, this implementation also gets into a
417 * safepoint if necessary.
418 */
420 public:
422 : StackResource(thread_state), rw_lock_(rw_lock) {
423 ASSERT(rw_lock_ != nullptr);
424 if (!rw_lock_->EnterRead()) {
425 // if lock didn't have to be acquired, it doesn't have to be released.
426 rw_lock_ = nullptr;
427 }
428 }
430 if (rw_lock_ != nullptr) {
431 rw_lock_->LeaveRead();
432 }
433 }
434
435 private:
436 SafepointRwLock* rw_lock_;
437};
438
439/*
440 * Locks a given [RwLock] for writing purposes.
441 *
442 * It will block while the lock is held by one or more readers.
443 *
444 * If this locker is long'jmped over (e.g. on a background compiler thread) the
445 * lock will be freed.
446 *
447 * NOTE: If the locking operation blocks (due to a writer) it will not check
448 * for a pending safepoint operation.
449 */
451 public:
452 WriteRwLocker(ThreadState* thread_state, RwLock* rw_lock)
453 : StackResource(thread_state), rw_lock_(rw_lock) {
454 rw_lock_->EnterWrite();
455 }
456
457 ~WriteRwLocker() { rw_lock_->LeaveWrite(); }
458
459 private:
460 RwLock* rw_lock_;
461};
462
463/*
464 * In addition to what [WriteRwLocker] does, this implementation also gets into a
465 * safepoint if necessary.
466 */
468 public:
470 : StackResource(thread_state), rw_lock_(rw_lock) {
471 rw_lock_->EnterWrite();
472 }
473
474 ~SafepointWriteRwLocker() { rw_lock_->LeaveWrite(); }
475
476 private:
477 SafepointRwLock* rw_lock_;
478};
479
480} // namespace dart
481
482#endif // RUNTIME_VM_LOCKERS_H_
virtual ~MonitorLeaveScope()
Definition: lockers.h:203
MonitorLeaveScope(MonitorLocker *monitor)
Definition: lockers.h:198
Monitor::WaitResult WaitMicros(int64_t micros=Monitor::kNoTimeout)
Definition: lockers.h:180
Monitor::WaitResult WaitWithSafepointCheck(Thread *thread, int64_t millis=Monitor::kNoTimeout)
Definition: lockers.cc:12
MonitorLocker(Monitor *monitor, bool no_safepoint_scope=true)
Definition: lockers.h:130
Monitor::WaitResult Wait(int64_t millis=Monitor::kNoTimeout)
Definition: lockers.h:172
void Enter() const
Definition: lockers.h:155
void Exit() const
Definition: lockers.h:163
virtual ~MonitorLocker()
Definition: lockers.h:146
static constexpr int64_t kNoTimeout
Definition: os_thread.h:361
virtual ~MutexLocker()
Definition: lockers.h:68
MutexLocker(Mutex *mutex)
Definition: lockers.h:49
void Unlock() const
Definition: lockers.h:85
void Lock() const
Definition: lockers.h:77
static ThreadId GetCurrentThreadId()
static const ThreadId kInvalidThreadId
Definition: os_thread.h:248
ReadRwLocker(ThreadState *thread_state, RwLock *rw_lock)
Definition: lockers.h:405
bool IsCurrentThreadWriter()
Definition: lockers.h:299
SafepointMonitorLocker(Monitor *monitor)
Definition: lockers.h:262
virtual ~SafepointMonitorLocker()
Definition: lockers.h:265
Monitor::WaitResult Wait(int64_t millis=Monitor::kNoTimeout)
Definition: lockers.cc:77
SafepointMonitorUnlockScope(SafepointMonitorLocker *locker)
Definition: lockers.h:284
virtual ~SafepointMutexLocker()
Definition: lockers.h:234
SafepointMutexLocker(Mutex *mutex)
Definition: lockers.h:231
SafepointReadRwLocker(ThreadState *thread_state, SafepointRwLock *rw_lock)
Definition: lockers.h:421
DEBUG_ONLY(bool IsCurrentThreadReader())
bool IsCurrentThreadWriter()
Definition: lockers.h:354
SafepointWriteRwLocker(ThreadState *thread_state, SafepointRwLock *rw_lock)
Definition: lockers.h:469
ThreadState * thread() const
Definition: allocation.h:33
void DecrementNoSafepointScopeDepth()
Definition: thread.h:733
static Thread * Current()
Definition: thread.h:362
ExecutionState execution_state() const
Definition: thread.h:1040
@ kThreadInNative
Definition: thread.h:1036
void IncrementNoSafepointScopeDepth()
Definition: thread.h:726
WriteRwLocker(ThreadState *thread_state, RwLock *rw_lock)
Definition: lockers.h:452
#define ASSERT(E)
if(end==-1)
Definition: dart_vm.cc:33
const bool kNoSafepointScope
Definition: lockers.h:17
const bool kDontAssertNoSafepointScope
Definition: lockers.h:18
pthread_t ThreadId
#define DEBUG_ONLY(code)
Definition: globals.h:141
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581