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 12namespace v8 { 13namespace internal { 14 15// Scope that explicitly parks a thread, prohibiting access to the heap and the 16// creation of handles. 17class V8_NODISCARD ParkedScope { 18 public: 19 explicit ParkedScope(LocalIsolate* local_isolate) 20 : ParkedScope(local_isolate->heap()) {} 21 explicit ParkedScope(LocalHeap* local_heap) : local_heap_(local_heap) { 22 local_heap_->Park(); 23 } 24 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. 33class V8_NODISCARD UnparkedScope { 34 public: 35 explicit UnparkedScope(LocalIsolate* local_isolate) 36 : UnparkedScope(local_isolate->heap()) {} 37 explicit UnparkedScope(LocalHeap* local_heap) : local_heap_(local_heap) { 38 local_heap_->Unpark(); 39 } 40 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. 49class V8_NODISCARD ParkedMutexGuard { 50 public: 51 explicit ParkedMutexGuard(LocalIsolate* local_isolate, base::Mutex* mutex) 52 : ParkedMutexGuard(local_isolate->heap(), 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 65 ~ParkedMutexGuard() { mutex_->Unlock(); } 66 67 private: 68 base::Mutex* mutex_; 69}; 70 71template <base::MutexSharedType kIsShared, 72 base::NullBehavior Behavior = base::NullBehavior::kRequireNotNull> 73class V8_NODISCARD ParkedSharedMutexGuardIf final { 74 public: 75 ParkedSharedMutexGuardIf(LocalIsolate* local_isolate, 76 base::SharedMutex* mutex, bool enable_mutex) 77 : ParkedSharedMutexGuardIf(local_isolate->heap(), mutex, 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 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