| // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights |
| // reserved. Use of this source code is governed by a BSD-style license that |
| // can be found in the LICENSE file. |
| |
| #ifndef CEF_LIBCEF_COMMON_VALUE_BASE_H_ |
| #define CEF_LIBCEF_COMMON_VALUE_BASE_H_ |
| #pragma once |
| |
| #include <map> |
| #include <set> |
| #include "include/cef_base.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/synchronization/lock.h" |
| #include "base/thread_annotations.h" |
| #include "base/threading/platform_thread.h" |
| |
| // Controller implementation base class. |
| class CefValueController |
| : public base::RefCountedThreadSafe<CefValueController> { |
| public: |
| // Implemented by a class controlled using the access controller. |
| class Object { |
| public: |
| virtual ~Object() {} |
| |
| // Called when the value has been removed. |
| virtual void OnControlRemoved() = 0; |
| }; |
| |
| // Encapsulates context locking and verification logic. |
| class AutoLock { |
| public: |
| explicit AutoLock(CefValueController* impl) |
| : impl_(impl), verified_(impl && impl->VerifyThread()) { |
| DCHECK(impl); |
| if (verified_) |
| impl_->lock(); |
| } |
| ~AutoLock() { |
| if (verified_) |
| impl_->unlock(); |
| } |
| |
| inline bool verified() { return verified_; } |
| |
| private: |
| scoped_refptr<CefValueController> impl_; |
| bool verified_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutoLock); |
| }; |
| |
| CefValueController(); |
| |
| // Returns true if this controller is thread safe. |
| virtual bool thread_safe() = 0; |
| |
| // Returns true if the current thread is allowed to access this controller. |
| virtual bool on_correct_thread() = 0; |
| |
| // Lock the controller. |
| virtual void lock() = 0; |
| |
| // Unlock the controller. |
| virtual void unlock() = 0; |
| |
| // Returns true if the controller is locked on the current thread. |
| virtual bool locked() = 0; |
| |
| // Assert that the lock has been acquired. |
| virtual void AssertLockAcquired() = 0; |
| |
| // Verify that the current thread is correct for accessing the controller. |
| inline bool VerifyThread() { |
| if (!thread_safe() && !on_correct_thread()) { |
| // This object should only be accessed from the thread that created it. |
| NOTREACHED() << "object accessed from incorrect thread."; |
| return false; |
| } |
| return true; |
| } |
| |
| // The controller must already be locked before calling the below methods. |
| |
| // Set the owner for this controller. |
| void SetOwner(void* value, Object* object); |
| |
| // Add a reference value and associated object. |
| void AddReference(void* value, Object* object); |
| |
| // Remove the value. If |notify_object| is true the removed object will be |
| // notified. If |value| is the owner all reference objects will be removed. |
| // If |value| has dependencies those objects will also be removed. |
| void Remove(void* value, bool notify_object); |
| |
| // Returns the object for the specified value. |
| Object* Get(void* value); |
| |
| // Add a dependency between |parent| and |child|. |
| void AddDependency(void* parent, void* child); |
| |
| // Recursively removes any dependent values. |
| void RemoveDependencies(void* value); |
| |
| // Takes ownership of all references and dependencies currently controlled by |
| // |other|. The |other| controller must already be locked. |
| void TakeFrom(CefValueController* other); |
| |
| // Replace all instances of |old_value| with |new_value|. Used in cases where |
| // move semantics may move the contents of an object without retaining the |
| // object pointer itself. |
| void Swap(void* old_value, void* new_value); |
| |
| protected: |
| friend class base::RefCountedThreadSafe<CefValueController>; |
| |
| virtual ~CefValueController(); |
| |
| private: |
| // Owner object. |
| void* owner_value_; |
| Object* owner_object_; |
| |
| // Map of reference objects. |
| typedef std::map<void*, Object*> ReferenceMap; |
| ReferenceMap reference_map_; |
| |
| // Map of dependency objects. |
| typedef std::set<void*> DependencySet; |
| typedef std::map<void*, DependencySet> DependencyMap; |
| DependencyMap dependency_map_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CefValueController); |
| }; |
| |
| // Thread-safe access control implementation. |
| class CefValueControllerThreadSafe : public CefValueController { |
| public: |
| explicit CefValueControllerThreadSafe() : locked_thread_id_(0) {} |
| |
| // CefValueController methods. |
| bool thread_safe() override { return true; } |
| bool on_correct_thread() override { return true; } |
| void lock() override NO_THREAD_SAFETY_ANALYSIS { |
| lock_.Acquire(); |
| locked_thread_id_ = base::PlatformThread::CurrentId(); |
| } |
| void unlock() override NO_THREAD_SAFETY_ANALYSIS { |
| locked_thread_id_ = 0; |
| lock_.Release(); |
| } |
| bool locked() override { |
| return (locked_thread_id_ == base::PlatformThread::CurrentId()); |
| } |
| void AssertLockAcquired() override { lock_.AssertAcquired(); } |
| |
| private: |
| base::Lock lock_; |
| base::PlatformThreadId locked_thread_id_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CefValueControllerThreadSafe); |
| }; |
| |
| // Non-thread-safe access control implementation. |
| class CefValueControllerNonThreadSafe : public CefValueController { |
| public: |
| explicit CefValueControllerNonThreadSafe() |
| : thread_id_(base::PlatformThread::CurrentId()) {} |
| |
| // CefValueController methods. |
| bool thread_safe() override { return false; } |
| bool on_correct_thread() override { |
| return (thread_id_ == base::PlatformThread::CurrentId()); |
| } |
| void lock() override {} |
| void unlock() override {} |
| bool locked() override { return on_correct_thread(); } |
| void AssertLockAcquired() override { DCHECK(locked()); } |
| |
| private: |
| base::PlatformThreadId thread_id_; |
| |
| DISALLOW_COPY_AND_ASSIGN(CefValueControllerNonThreadSafe); |
| }; |
| |
| // Helper macros for verifying context. |
| |
| #define CEF_VALUE_VERIFY_RETURN_VOID_EX(object, modify) \ |
| if (!VerifyAttached()) \ |
| return; \ |
| AutoLock auto_lock(object, modify); \ |
| if (!auto_lock.verified()) \ |
| return; |
| |
| #define CEF_VALUE_VERIFY_RETURN_VOID(modify) \ |
| CEF_VALUE_VERIFY_RETURN_VOID_EX(this, modify) |
| |
| #define CEF_VALUE_VERIFY_RETURN_EX(object, modify, error_val) \ |
| if (!VerifyAttached()) \ |
| return error_val; \ |
| AutoLock auto_lock(object, modify); \ |
| if (!auto_lock.verified()) \ |
| return error_val; |
| |
| #define CEF_VALUE_VERIFY_RETURN(modify, error_val) \ |
| CEF_VALUE_VERIFY_RETURN_EX(this, modify, error_val) |
| |
| // Template class for implementing CEF wrappers of other types. |
| template <class CefType, class ValueType> |
| class CefValueBase : public CefType, public CefValueController::Object { |
| public: |
| // Specifies how the value will be used. |
| enum ValueMode { |
| // A reference to a value managed by an existing controller. These values |
| // can be safely detached but ownership should not be transferred (make a |
| // copy of the value instead). |
| kReference, |
| |
| // The value has its own controller and will be deleted on destruction. |
| // These values can only be detached to another controller otherwise any |
| // references will not be properly managed. |
| kOwnerWillDelete, |
| |
| // The value has its own controller and will not be deleted on destruction. |
| // This should only be used for global values or scope-limited values that |
| // will be explicitly detached. |
| kOwnerNoDelete, |
| }; |
| |
| // Create a new object. |
| // If |read_only| is true mutable access will not be allowed. |
| // If |parent_value| is non-NULL and the value mode is kReference a dependency |
| // will be added. |
| CefValueBase(ValueType* value, |
| void* parent_value, |
| ValueMode value_mode, |
| bool read_only, |
| CefValueController* controller) |
| : value_(value), |
| value_mode_(value_mode), |
| read_only_(read_only), |
| controller_(controller) { |
| DCHECK(value_); |
| |
| // Specifying a parent value for a non-reference doesn't make sense. |
| DCHECK(!(!reference() && parent_value)); |
| |
| if (!reference() && !controller_.get()) { |
| // For owned values default to using a new multi-threaded controller. |
| controller_ = new CefValueControllerThreadSafe(); |
| SetOwnsController(); |
| } |
| |
| // A controller is required. |
| DCHECK(controller_.get()); |
| |
| if (reference()) { |
| // Register the reference with the controller. |
| controller_->AddReference(value_, this); |
| |
| // Add a dependency on the parent value. |
| if (parent_value) |
| controller_->AddDependency(parent_value, value_); |
| } |
| } |
| |
| ~CefValueBase() override { |
| if (controller_.get() && value_) |
| Delete(); |
| } |
| |
| // True if the underlying value is referenced instead of owned. |
| inline bool reference() const { return (value_mode_ == kReference); } |
| |
| // True if the underlying value will be deleted. |
| inline bool will_delete() const { return (value_mode_ == kOwnerWillDelete); } |
| |
| // True if access to the underlying value is read-only. |
| inline bool read_only() const { return read_only_; } |
| |
| // True if the underlying value has been detached. |
| inline bool detached() { return !controller_.get(); } |
| |
| // Returns the controller. |
| inline CefValueController* controller() { return controller_.get(); } |
| |
| // Deletes the underlying value. |
| void Delete() { |
| CEF_VALUE_VERIFY_RETURN_VOID(false); |
| |
| // Remove the object from the controller. If this is the owner object any |
| // references will be detached. |
| controller()->Remove(value_, false); |
| |
| if (will_delete()) { |
| // Remove any dependencies. |
| controller()->RemoveDependencies(value_); |
| |
| // Delete the value. |
| DeleteValue(value_); |
| } |
| |
| controller_ = nullptr; |
| value_ = nullptr; |
| } |
| |
| // Detaches the underlying value and returns a pointer to it. If this is an |
| // owner and a |new_controller| value is specified any existing references |
| // will be passed to the new controller. |
| ValueType* Detach(CefValueController* new_controller) { |
| CEF_VALUE_VERIFY_RETURN(false, nullptr); |
| |
| // A |new_controller| value is required for mode kOwnerWillDelete. |
| DCHECK(!will_delete() || new_controller); |
| |
| if (new_controller && !reference()) { |
| // Pass any existing references and dependencies to the new controller. |
| // They will be removed from this controller. |
| new_controller->TakeFrom(controller()); |
| } |
| |
| // Remove the object from the controller. If this is the owner object any |
| // references will be detached. |
| controller()->Remove(value_, false); |
| controller_ = nullptr; |
| |
| // Return the old value. |
| ValueType* old_val = value_; |
| value_ = nullptr; |
| return old_val; |
| } |
| |
| // Verify that the value is attached. |
| inline bool VerifyAttached() { |
| if (detached()) { |
| // This object should not be accessed after being detached. |
| NOTREACHED() << "object accessed after being detached."; |
| return false; |
| } |
| return true; |
| } |
| |
| protected: |
| // CefValueController::Object methods. |
| void OnControlRemoved() override { |
| DCHECK(controller()->locked()); |
| |
| // Only references should be removed in this manner. |
| DCHECK(reference()); |
| |
| controller_ = nullptr; |
| value_ = nullptr; |
| } |
| |
| // Override to customize value deletion. |
| virtual void DeleteValue(ValueType* value) { delete value; } |
| |
| // Returns a mutable reference to the value. |
| inline ValueType* mutable_value() { |
| DCHECK(value_); |
| DCHECK(!read_only_); |
| DCHECK(controller()->locked()); |
| return value_; |
| } |
| // Returns a const reference to the value. |
| inline const ValueType& const_value() { |
| DCHECK(value_); |
| DCHECK(controller()->locked()); |
| return *value_; |
| } |
| |
| // Verify that the value can be accessed. |
| inline bool VerifyAccess(bool modify) { |
| // The controller must already be locked. |
| DCHECK(controller()->locked()); |
| |
| if (read_only() && modify) { |
| // This object cannot be modified. |
| NOTREACHED() << "mutation attempted on read-only object."; |
| return false; |
| } |
| |
| return true; |
| } |
| |
| // Used to indicate that this object owns the controller. |
| inline void SetOwnsController() { |
| CefValueController::AutoLock lock_scope(controller_.get()); |
| if (lock_scope.verified()) |
| controller_->SetOwner(value_, this); |
| } |
| |
| // Encapsulates value locking and verification logic. |
| class AutoLock { |
| public: |
| explicit AutoLock(CefValueBase* impl, bool modify) |
| : auto_lock_(impl->controller()) { |
| verified_ = (auto_lock_.verified() && impl->VerifyAccess(modify)); |
| } |
| |
| inline bool verified() { return verified_; } |
| |
| private: |
| CefValueController::AutoLock auto_lock_; |
| bool verified_; |
| |
| DISALLOW_COPY_AND_ASSIGN(AutoLock); |
| }; |
| |
| private: |
| ValueType* value_; |
| ValueMode value_mode_; |
| bool read_only_; |
| scoped_refptr<CefValueController> controller_; |
| |
| IMPLEMENT_REFCOUNTING(CefValueBase); |
| |
| DISALLOW_COPY_AND_ASSIGN(CefValueBase); |
| }; |
| |
| #endif // CEF_LIBCEF_COMMON_VALUE_BASE_H_ |