195 lines
6.0 KiB
C#
195 lines
6.0 KiB
C#
/*******************************************************************/
|
|
/* WARNING */
|
|
/* This file should be identical in the Bartok and Singularity */
|
|
/* depots. Master copy resides in Bartok Depot. Changes should be */
|
|
/* made to Bartok Depot and propagated to Singularity Depot. */
|
|
/*******************************************************************/
|
|
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
|
|
namespace System {
|
|
|
|
using Microsoft.Bartok.Runtime;
|
|
using System.Threading;
|
|
using System.Runtime.CompilerServices;
|
|
using System.GCs;
|
|
|
|
/// <summary>
|
|
/// This class implements weak references.
|
|
///
|
|
/// When a new weak references is allocated it is atomically linked
|
|
/// onto a singly linked list of weak references.
|
|
///
|
|
/// During a garbage collection this chain is traversed and references
|
|
/// are updated or cleared.
|
|
///
|
|
/// There are two modes of processing weak references.
|
|
///
|
|
/// 1. Ignoring 'Long' References that track resurrection and
|
|
/// only updating references that should be cleared when the
|
|
/// object is finalized.
|
|
/// 2. Updating all reference types.
|
|
///
|
|
/// In any collection at least the second method must be called to
|
|
/// ensure no dangling pointers are created.
|
|
///
|
|
/// BUGBUG: At the moment it is possible to have a weak reference that
|
|
/// is unlinked from the chain and then resurrected as reachable from
|
|
/// a finalizable object!
|
|
/// </summary>
|
|
[CCtorIsRunDuringStartup]
|
|
#if !SINGULARITY
|
|
[Serializable]
|
|
#endif
|
|
public unsafe class WeakReference {
|
|
|
|
/// <summary>
|
|
/// The dummy head reference to simplify traversal logic.
|
|
/// </summary>
|
|
private static readonly WeakReference headRef;
|
|
|
|
/// <summary>
|
|
/// The weak reference to the object
|
|
/// </summary>
|
|
private UIntPtr objPtr;
|
|
|
|
/// <summary>
|
|
/// The next reference on the chain.
|
|
/// </summary>
|
|
private UIntPtr nextRef;
|
|
|
|
/// <summary>
|
|
/// Does this reference stay alive during finalization of the target?
|
|
/// </summary>
|
|
private bool trackResurrection;
|
|
|
|
private WeakReference() {}
|
|
|
|
/// <summary>
|
|
/// Construct a 'Short' weak reference.
|
|
/// </summary>
|
|
public WeakReference(Object target) : this(target, false) {}
|
|
|
|
/// <summary>
|
|
/// Construct a weak reference and link it onto the chain,
|
|
/// specifying if it is to track an object through finalization.
|
|
/// </summary>
|
|
public WeakReference(Object target, bool trackResurrection) {
|
|
this.Target = target;
|
|
this.trackResurrection = trackResurrection;
|
|
|
|
UIntPtr thisPtr = Magic.addressOf(this);
|
|
do {
|
|
this.nextRef = headRef.nextRef;
|
|
} while (this.nextRef != Interlocked.CompareExchange(
|
|
ref headRef.nextRef,
|
|
thisPtr,
|
|
this.nextRef));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is the object alive?
|
|
/// </summary>
|
|
public virtual bool IsAlive {
|
|
get {
|
|
return this.objPtr != UIntPtr.Zero;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get or set target of the object. Null if the object has been
|
|
/// collected.
|
|
/// </summary>
|
|
public virtual Object Target {
|
|
get {
|
|
return Magic.fromAddress(objPtr);
|
|
}
|
|
set {
|
|
this.objPtr = Magic.addressOf(value);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should this reference track objects through finalization?
|
|
/// </summary>
|
|
public virtual bool TrackResurrection {
|
|
get {
|
|
return trackResurrection;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// This method performs the processing of weak references for GC.
|
|
///
|
|
/// It essentially walks a list unlinking weak reference objects
|
|
/// that are not live and updating references as necessary.
|
|
/// </summary>
|
|
internal static
|
|
void Process(NonNullReferenceVisitor updateReferenceVisitor,
|
|
bool copyFirst, bool ignoreLong)
|
|
{
|
|
|
|
// Head ref is a dummy ref object.
|
|
WeakReference wr = headRef;
|
|
|
|
while (wr.nextRef != UIntPtr.Zero) {
|
|
if (ignoreLong) {
|
|
WeakReference tmp =
|
|
Magic.toWeakReference(Magic.fromAddress(wr.nextRef));
|
|
|
|
if (tmp.trackResurrection) {
|
|
wr = tmp;
|
|
continue;
|
|
}
|
|
|
|
}
|
|
|
|
UIntPtr nextPtr = wr.nextRef;
|
|
|
|
fixed (UIntPtr * loc = &wr.nextRef) {
|
|
// update the reference
|
|
updateReferenceVisitor.Visit(loc);
|
|
}
|
|
|
|
WeakReference next;
|
|
|
|
if (wr.nextRef == UIntPtr.Zero) {
|
|
// remove next from the chain and continue
|
|
next =
|
|
Magic.toWeakReference(Magic.fromAddress(nextPtr));
|
|
wr.nextRef = next.nextRef;
|
|
continue;
|
|
}
|
|
|
|
// Updating old or new location?
|
|
if (copyFirst) {
|
|
next =
|
|
Magic.toWeakReference(Magic.fromAddress(wr.nextRef));
|
|
} else {
|
|
next =
|
|
Magic.toWeakReference(Magic.fromAddress(nextPtr));
|
|
}
|
|
|
|
fixed (UIntPtr * loc = &next.objPtr) {
|
|
if (*loc != UIntPtr.Zero) {
|
|
// Update Reference
|
|
updateReferenceVisitor.Visit(loc);
|
|
}
|
|
}
|
|
|
|
// Continue
|
|
wr = next;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Class constructor, set up dummy head.
|
|
/// </summary>
|
|
static WeakReference() {
|
|
headRef = new WeakReference();
|
|
}
|
|
}
|
|
}
|