The Labs \ Source Viewer \ SSCLI \ System \ WeakReference

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. /*============================================================
  16. **
  17. ** Class: WeakReference
  18. **
  19. ** Purpose: A wrapper for establishing a WeakReference to an Object.
  20. **
  21. ===========================================================*/
  22. namespace System
  23. {
  24.    
  25.     using System;
  26.     using System.Runtime.Remoting;
  27.     using System.Runtime.Serialization;
  28.     using System.Security.Permissions;
  29.     using System.Runtime.InteropServices;
  30.     using System.Threading;
  31.     [System.Runtime.InteropServices.ComVisible(true)]
  32.     [SecurityPermissionAttribute(SecurityAction.InheritanceDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
  33.     [Serializable()]
  34.     public class WeakReference : ISerializable
  35.     {
  36.         // Most methods using m_handle should use GC.KeepAlive(this)
  37.         // to avoid potential handle recycling attacks. The GC special
  38.         // cases the finalizer for WeakReference & only clears them
  39.         // when all threads are suspended, but you might still run into
  40.         // problems if your code is at least partially interruptible.
  41.         // It's just too much complexity to think about.
  42.         internal IntPtr m_handle;
  43.         internal bool m_IsLongReference;
  44.        
  45.         // Creates a new WeakReference that keeps track of target.
  46.         // Assumes a Short Weak Reference (ie TrackResurrection is false.)
  47.         //
  48.         public WeakReference(object target) : this(target, false)
  49.         {
  50.         }
  51.        
  52.         //Creates a new WeakReference that keeps track of target.
  53.         //
  54.         public WeakReference(object target, bool trackResurrection)
  55.         {
  56.             m_IsLongReference = trackResurrection;
  57.             m_handle = GCHandle.InternalAlloc(target, trackResurrection ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
  58.         }
  59.        
  60.        
  61.         protected WeakReference(SerializationInfo info, StreamingContext context)
  62.         {
  63.             if (info == null) {
  64.                 throw new ArgumentNullException("info");
  65.             }
  66.             object temp = info.GetValue("TrackedObject", typeof(object));
  67.             m_IsLongReference = info.GetBoolean("TrackResurrection");
  68.             m_handle = GCHandle.InternalAlloc(temp, m_IsLongReference ? GCHandleType.WeakTrackResurrection : GCHandleType.Weak);
  69.         }
  70.        
  71.         //Determines whether or not this instance of WeakReference still refers to an object
  72.         //that has not been collected.
  73.         //
  74.         public virtual bool IsAlive {
  75.             get {
  76.                 IntPtr h = m_handle;
  77.                
  78.                 // In determining whether it is valid to use this object, we need to at least expose this
  79.                 // without throwing an exception.
  80.                 if (IntPtr.Zero == h)
  81.                     return false;
  82.                
  83.                 bool result = (GCHandle.InternalGet(h) != null);
  84.                
  85.                 // This call to KeepAlive is necessary to prevent the WeakReference finalizer from being called before the result is computed
  86.                 h = Thread.VolatileRead(ref m_handle);
  87.                 GC.KeepAlive(this);
  88.                 return (h == IntPtr.Zero) ? false : result;
  89.             }
  90.         }
  91.        
  92.         //Returns a boolean indicating whether or not we're tracking objects until they're collected (true)
  93.         //or just until they're finalized (false).
  94.         //
  95.         public virtual bool TrackResurrection {
  96.             get { return m_IsLongReference; }
  97.         }
  98.        
  99.         //Gets the Object stored in the handle if it's accessible.
  100.         // Or sets it.
  101.         //
  102.         public virtual object Target {
  103.             get {
  104.                 IntPtr h = m_handle;
  105.                 // Should only happen when used illegally, like using a
  106.                 // WeakReference from a finalizer.
  107.                 if (IntPtr.Zero == h)
  108.                     return null;
  109.                
  110.                 object o = GCHandle.InternalGet(h);
  111.                
  112.                 // Ensure this WeakReference doesn't get finalized while we're
  113.                 // in this method.
  114.                 h = Thread.VolatileRead(ref m_handle);
  115.                 GC.KeepAlive(this);
  116.                 return (h == IntPtr.Zero) ? null : o;
  117.             }
  118.             set {
  119.                 IntPtr h = m_handle;
  120.                 if (h == IntPtr.Zero)
  121.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  122.                
  123.                 // There is a race w/ finalization where m_handle gets set to
  124.                 // NULL and the WeakReference becomes invalid. Here we have to
  125.                 // do the following in order:
  126.                 //
  127.                 // 1. Get the old object value
  128.                 // 2. Get m_handle
  129.                 // 3. HndInterlockedCompareExchange(m_handle, newValue, oldValue);
  130.                 //
  131.                 // If the interlocked-cmp-exchange fails, then either we lost a race
  132.                 // with another updater, or we lost a race w/ the finalizer. In
  133.                 // either case, we can just let the other guy win.
  134.                 object oldValue = GCHandle.InternalGet(h);
  135.                 h = m_handle;
  136.                 if (h == IntPtr.Zero)
  137.                     throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_HandleIsNotInitialized"));
  138.                     /* isPinned */                GCHandle.InternalCompareExchange(h, value, oldValue, false);
  139.                
  140.                 // Ensure we don't have any handle recycling attacks in this
  141.                 // method where the finalizer frees the handle.
  142.                 GC.KeepAlive(this);
  143.             }
  144.         }
  145.        
  146.         // Free all system resources associated with this reference.
  147.         //
  148.         // Note: The WeakReference finalizer is not actually run, but
  149.         // treated specially in gc.cpp's ScanForFinalization
  150.         // This is needed for subclasses deriving from WeakReference, however.
  151.         ~WeakReference()
  152.         {
  153.             IntPtr old_handle = m_handle;
  154.             if (old_handle != IntPtr.Zero) {
  155.                 if (old_handle == Interlocked.CompareExchange(ref m_handle, IntPtr.Zero, old_handle))
  156.                     GCHandle.InternalFree(old_handle);
  157.             }
  158.         }
  159.        
  160.         public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
  161.         {
  162.             if (info == null) {
  163.                 throw new ArgumentNullException("info");
  164.             }
  165.             info.AddValue("TrackedObject", Target, typeof(object));
  166.             info.AddValue("TrackResurrection", m_IsLongReference);
  167.         }
  168.        
  169.     }
  170.    
  171. }

Developer Fusion