//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
/*******************************************************************/
/* 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. */
/*******************************************************************/
namespace System {
using Microsoft.Bartok.Runtime;
using System.Threading;
using System.Runtime.CompilerServices;
using System.GCs;
///
/// 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!
///
[CCtorIsRunDuringStartup]
#if !SINGULARITY
[Serializable]
#endif
public unsafe class WeakReference {
///
/// The dummy head reference to simplify traversal logic.
///
private static readonly WeakReference headRef;
///
/// The weak reference to the object
///
private UIntPtr objPtr;
///
/// The next reference on the chain.
///
private UIntPtr nextRef;
///
/// Does this reference stay alive during finalization of the target?
///
private bool trackResurrection;
private WeakReference() {}
///
/// Construct a 'Short' weak reference.
///
public WeakReference(Object target) : this(target, false) {}
///
/// Construct a weak reference and link it onto the chain,
/// specifying if it is to track an object through finalization.
///
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));
}
///
/// Is the object alive?
///
public virtual bool IsAlive {
get {
return this.objPtr != UIntPtr.Zero;
}
}
///
/// Get or set target of the object. Null if the object has been
/// collected.
///
public virtual Object Target {
get {
return Barrier.WeakRefRead(this.objPtr, 0);
}
set {
this.objPtr = Barrier.WeakRefWrite(value, 0);
}
}
///
/// Should this reference track objects through finalization?
///
public virtual bool TrackResurrection {
get {
return trackResurrection;
}
}
///
/// 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.
///
internal static
void Process(DirectReferenceVisitor 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;
}
}
///
/// Class constructor, set up dummy head.
///
static WeakReference() {
headRef = new WeakReference();
}
}
}