1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef V8_HEAP_PARKED_SCOPE_H_
6 #define V8_HEAP_PARKED_SCOPE_H_
7 
8 #include "src/base/platform/mutex.h"
9 #include "src/execution/local-isolate.h"
10 #include "src/heap/local-heap.h"
11 
12 namespace v8 {
13 namespace internal {
14 
15 // Scope that explicitly parks a thread, prohibiting access to the heap and the
16 // creation of handles.
17 class V8_NODISCARD ParkedScope {
18  public:
ParkedScope(LocalIsolate * local_isolate)19   explicit ParkedScope(LocalIsolate* local_isolate)
20       : ParkedScope(local_isolate->heap()) {}
ParkedScope(LocalHeap * local_heap)21   explicit ParkedScope(LocalHeap* local_heap) : local_heap_(local_heap) {
22     local_heap_->Park();
23   }
24 
~ParkedScope()25   ~ParkedScope() { local_heap_->Unpark(); }
26 
27  private:
28   LocalHeap* const local_heap_;
29 };
30 
31 // Scope that explicitly unparks a thread, allowing access to the heap and the
32 // creation of handles.
33 class V8_NODISCARD UnparkedScope {
34  public:
UnparkedScope(LocalIsolate * local_isolate)35   explicit UnparkedScope(LocalIsolate* local_isolate)
36       : UnparkedScope(local_isolate->heap()) {}
UnparkedScope(LocalHeap * local_heap)37   explicit UnparkedScope(LocalHeap* local_heap) : local_heap_(local_heap) {
38     local_heap_->Unpark();
39   }
40 
~UnparkedScope()41   ~UnparkedScope() { local_heap_->Park(); }
42 
43  private:
44   LocalHeap* const local_heap_;
45 };
46 
47 class V8_NODISCARD ParkedMutexGuard {
48  public:
ParkedMutexGuard(LocalIsolate * local_isolate,base::Mutex * mutex)49   explicit ParkedMutexGuard(LocalIsolate* local_isolate, base::Mutex* mutex)
50       : ParkedMutexGuard(local_isolate->heap(), mutex) {}
ParkedMutexGuard(LocalHeap * local_heap,base::Mutex * mutex)51   explicit ParkedMutexGuard(LocalHeap* local_heap, base::Mutex* mutex)
52       : mutex_(mutex) {
53     DCHECK(AllowGarbageCollection::IsAllowed());
54     if (!mutex_->TryLock()) {
55       ParkedScope scope(local_heap);
56       mutex_->Lock();
57     }
58   }
59 
60   ParkedMutexGuard(const ParkedMutexGuard&) = delete;
61   ParkedMutexGuard& operator=(const ParkedMutexGuard&) = delete;
62 
~ParkedMutexGuard()63   ~ParkedMutexGuard() { mutex_->Unlock(); }
64 
65  private:
66   base::Mutex* mutex_;
67 };
68 
69 template <base::MutexSharedType kIsShared,
70           base::NullBehavior Behavior = base::NullBehavior::kRequireNotNull>
71 class V8_NODISCARD ParkedSharedMutexGuardIf final {
72  public:
ParkedSharedMutexGuardIf(LocalIsolate * local_isolate,base::SharedMutex * mutex,bool enable_mutex)73   ParkedSharedMutexGuardIf(LocalIsolate* local_isolate,
74                            base::SharedMutex* mutex, bool enable_mutex)
75       : ParkedSharedMutexGuardIf(local_isolate->heap(), mutex, enable_mutex) {}
ParkedSharedMutexGuardIf(LocalHeap * local_heap,base::SharedMutex * mutex,bool enable_mutex)76   ParkedSharedMutexGuardIf(LocalHeap* local_heap, base::SharedMutex* mutex,
77                            bool enable_mutex) {
78     DCHECK(AllowGarbageCollection::IsAllowed());
79     DCHECK_IMPLIES(Behavior == base::NullBehavior::kRequireNotNull,
80                    mutex != nullptr);
81     if (!enable_mutex) return;
82     mutex_ = mutex;
83 
84     if (kIsShared) {
85       if (!mutex_->TryLockShared()) {
86         ParkedScope scope(local_heap);
87         mutex_->LockShared();
88       }
89     } else {
90       if (!mutex_->TryLockExclusive()) {
91         ParkedScope scope(local_heap);
92         mutex_->LockExclusive();
93       }
94     }
95   }
96   ParkedSharedMutexGuardIf(const ParkedSharedMutexGuardIf&) = delete;
97   ParkedSharedMutexGuardIf& operator=(const ParkedSharedMutexGuardIf&) = delete;
98 
~ParkedSharedMutexGuardIf()99   ~ParkedSharedMutexGuardIf() {
100     if (!mutex_) return;
101 
102     if (kIsShared) {
103       mutex_->UnlockShared();
104     } else {
105       mutex_->UnlockExclusive();
106     }
107   }
108 
109  private:
110   base::SharedMutex* mutex_ = nullptr;
111 };
112 
113 }  // namespace internal
114 }  // namespace v8
115 
116 #endif  // V8_HEAP_PARKED_SCOPE_H_
117