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 // Scope that automatically parks the thread while blocking on the given 48 // base::Mutex. 49 class V8_NODISCARD ParkedMutexGuard { 50 public: ParkedMutexGuard(LocalIsolate * local_isolate,base::Mutex * mutex)51 explicit ParkedMutexGuard(LocalIsolate* local_isolate, base::Mutex* mutex) 52 : ParkedMutexGuard(local_isolate->heap(), mutex) {} ParkedMutexGuard(LocalHeap * local_heap,base::Mutex * mutex)53 explicit ParkedMutexGuard(LocalHeap* local_heap, base::Mutex* mutex) 54 : mutex_(mutex) { 55 DCHECK(AllowGarbageCollection::IsAllowed()); 56 if (!mutex_->TryLock()) { 57 ParkedScope scope(local_heap); 58 mutex_->Lock(); 59 } 60 } 61 62 ParkedMutexGuard(const ParkedMutexGuard&) = delete; 63 ParkedMutexGuard& operator=(const ParkedMutexGuard&) = delete; 64 ~ParkedMutexGuard()65 ~ParkedMutexGuard() { mutex_->Unlock(); } 66 67 private: 68 base::Mutex* mutex_; 69 }; 70 71 template <base::MutexSharedType kIsShared, 72 base::NullBehavior Behavior = base::NullBehavior::kRequireNotNull> 73 class V8_NODISCARD ParkedSharedMutexGuardIf final { 74 public: ParkedSharedMutexGuardIf(LocalIsolate * local_isolate,base::SharedMutex * mutex,bool enable_mutex)75 ParkedSharedMutexGuardIf(LocalIsolate* local_isolate, 76 base::SharedMutex* mutex, bool enable_mutex) 77 : ParkedSharedMutexGuardIf(local_isolate->heap(), mutex, enable_mutex) {} ParkedSharedMutexGuardIf(LocalHeap * local_heap,base::SharedMutex * mutex,bool enable_mutex)78 ParkedSharedMutexGuardIf(LocalHeap* local_heap, base::SharedMutex* mutex, 79 bool enable_mutex) { 80 DCHECK(AllowGarbageCollection::IsAllowed()); 81 DCHECK_IMPLIES(Behavior == base::NullBehavior::kRequireNotNull, 82 mutex != nullptr); 83 if (!enable_mutex) return; 84 mutex_ = mutex; 85 86 if (kIsShared) { 87 if (!mutex_->TryLockShared()) { 88 ParkedScope scope(local_heap); 89 mutex_->LockShared(); 90 } 91 } else { 92 if (!mutex_->TryLockExclusive()) { 93 ParkedScope scope(local_heap); 94 mutex_->LockExclusive(); 95 } 96 } 97 } 98 ParkedSharedMutexGuardIf(const ParkedSharedMutexGuardIf&) = delete; 99 ParkedSharedMutexGuardIf& operator=(const ParkedSharedMutexGuardIf&) = delete; 100 ~ParkedSharedMutexGuardIf()101 ~ParkedSharedMutexGuardIf() { 102 if (!mutex_) return; 103 104 if (kIsShared) { 105 mutex_->UnlockShared(); 106 } else { 107 mutex_->UnlockExclusive(); 108 } 109 } 110 111 private: 112 base::SharedMutex* mutex_ = nullptr; 113 }; 114 115 } // namespace internal 116 } // namespace v8 117 118 #endif // V8_HEAP_PARKED_SCOPE_H_ 119