1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
// Copyright (c) Microsoft Corp., 2004. All rights reserved.
#region Using directives
using System;
using System.Threading;
#endregion
namespace System.Workflow.Runtime.DebugEngine
{
//
// IMPORTANT: Do not edit this file without consulting Break Safe Synchronization.doc!
//
internal abstract class BreakSafeBase<T> where T : ICloneable, new()
{
#region Data members
private volatile object currentData; // object because type parameters instances cannot be volatile.
private T nonEEDataClone;
private volatile bool nonEEDataConsistent;
private volatile bool nonEEIgnoreUpdate;
private Mutex nonEELock;
private object controllerUpdateObject;
private int controllerManagedThreadId;
#endregion
#region Methods and properties
protected BreakSafeBase(int controllerManagedThreadId)
{
this.currentData = new T();
this.nonEEDataClone = default(T);
this.nonEEDataConsistent = false;
this.nonEEIgnoreUpdate = false;
this.nonEELock = new Mutex(false);
this.controllerManagedThreadId = controllerManagedThreadId;
}
private bool IsEECall
{
get
{
return Thread.CurrentThread.ManagedThreadId == this.controllerManagedThreadId;
}
}
protected object GetControllerUpdateObject()
{
return this.controllerUpdateObject;
}
protected void SetControllerUpdateObject(object updateObject)
{
// Ensure that the access to the variable this.controllerUpdateObject is exactly one instruction - StFld in this case.
this.controllerUpdateObject = updateObject;
}
protected T GetReaderData()
{
// Ensure that the access to the variable this.currentData is exactly one instruction - LdFld in this case.
object data = this.currentData;
return (T)data;
}
protected T GetWriterData()
{
if (IsEECall)
{
if (this.nonEEDataConsistent && this.nonEEIgnoreUpdate == false)
{
// Modify the object referred to by this.currentData directly.
return (T)this.currentData;
}
else
{
// Clone and discard any non-EE update.
this.nonEEIgnoreUpdate = true;
return (T)((T)this.currentData).Clone();
}
}
else
{
// Reset the flag so that we can keep track of any concurrent EE updates.
this.nonEEIgnoreUpdate = false;
// Ensure that the access to the variable this.currentData is exactly one instruction - LdFld in this case.
object data = this.currentData;
return (T)((T)data).Clone();
}
}
protected void SaveData(T data)
{
if (IsEECall)
this.currentData = data;
else
{
// The non-EE clone is now in a consistent state.
this.nonEEDataClone = data;
this.nonEEDataConsistent = true;
this.controllerUpdateObject = null;
// If an EE call has already modified the data, it would have also performed current non-EE update
// when the debugger entered break mode. So discard the update. Asl ensure that the access to the
// variable this.currentData is exactly one instruction - StFld in this case.
if (this.nonEEIgnoreUpdate == false)
this.currentData = data;
// Clear the flag because we will clear the this.nonEEDataClone.
this.nonEEDataConsistent = false;
this.nonEEDataClone = default(T);
}
}
protected void Lock()
{
// Serialize non-EE calls and do not invoke synchronization primitives during FuncEval.
if (!IsEECall)
this.nonEELock.WaitOne();
}
protected void Unlock()
{
// Serialize non-EE calls and do not invoke synchronization primitives during FuncEval.
if (!IsEECall)
this.nonEELock.ReleaseMutex();
}
#endregion
}
}
|