mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			423 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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/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 {
 | |
|     lock_.Acquire();
 | |
|     locked_thread_id_ = base::PlatformThread::CurrentId();
 | |
|   }
 | |
|   void unlock() override {
 | |
|     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_ = NULL;
 | |
|     value_ = NULL;
 | |
|   }
 | |
| 
 | |
|   // 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, NULL);
 | |
| 
 | |
|     // 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_ = NULL;
 | |
| 
 | |
|     // Return the old value.
 | |
|     ValueType* old_val = value_;
 | |
|     value_ = NULL;
 | |
|     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_ = NULL;
 | |
|     value_ = NULL;
 | |
|   }
 | |
| 
 | |
|   // 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_
 |