internal RealOletxTransaction(OletxTransactionManager transactionManager, ITransactionShim transactionShim, OutcomeEnlistment outcomeEnlistment, Guid identifier, OletxTransactionIsolationLevel oletxIsoLevel, bool isRoot) { bool flag = false; try { this.oletxTransactionManager = transactionManager; this.transactionShim = transactionShim; this.outcomeEnlistment = outcomeEnlistment; this.txGuid = identifier; this.isolationLevel = OletxTransactionManager.ConvertIsolationLevelFromProxyValue(oletxIsoLevel); this.status = TransactionStatus.Active; this.undisposedOletxTransactionCount = 0; this.phase0EnlistVolatilementContainerList = null; this.phase1EnlistVolatilementContainer = null; this.tooLateForEnlistments = false; this.internalTransaction = null; this.creationTime = DateTime.UtcNow; this.lastStateChangeTime = this.creationTime; this.internalClone = new OletxTransaction(this); if (this.outcomeEnlistment != null) { this.outcomeEnlistment.SetRealTransaction(this); } else { this.status = TransactionStatus.InDoubt; } if (DiagnosticTrace.HaveListeners) { DiagnosticTrace.TraceTransfer(this.txGuid); } flag = true; } finally { if (!flag && (this.outcomeEnlistment != null)) { this.outcomeEnlistment.UnregisterOutcomeCallback(); this.outcomeEnlistment = null; } } }
internal static void ShimNotificationCallback(object state, bool timeout) { IntPtr zero = IntPtr.Zero; ShimNotificationType none = ShimNotificationType.None; bool isSinglePhase = false; bool abortingHint = false; uint prepareInfoSize = 0; CoTaskMemHandle prepareInfo = null; bool releaseRequired = false; bool flag3 = false; IDtcProxyShimFactory factory = null; if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransactionManager.ShimNotificationCallback"); } Thread.BeginCriticalRegion(); try { Label_003D: factory = proxyShimFactory; try { object obj2; OletxResourceManager manager2; byte[] buffer; Thread.BeginThreadAffinity(); RuntimeHelpers.PrepareConstrainedRegions(); try { factory.GetNotification(out zero, out none, out isSinglePhase, out abortingHint, out releaseRequired, out prepareInfoSize, out prepareInfo); } finally { if (releaseRequired) { if (HandleTable.FindHandle(zero) is OletxInternalResourceManager) { processingTmDown = true; Monitor.Enter(proxyShimFactory); } else { releaseRequired = false; } factory.ReleaseNotificationLock(); } Thread.EndThreadAffinity(); } if (processingTmDown) { lock (proxyShimFactory) { } } if (none != ShimNotificationType.None) { obj2 = HandleTable.FindHandle(zero); switch (none) { case ShimNotificationType.Phase0RequestNotify: try { OletxPhase0VolatileEnlistmentContainer container5 = obj2 as OletxPhase0VolatileEnlistmentContainer; if (container5 != null) { DiagnosticTrace.SetActivityId(container5.TransactionIdentifier); container5.Phase0Request(abortingHint); } else { OletxEnlistment enlistment8 = obj2 as OletxEnlistment; if (enlistment8 != null) { DiagnosticTrace.SetActivityId(enlistment8.TransactionIdentifier); enlistment8.Phase0Request(abortingHint); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } break; case ShimNotificationType.VoteRequestNotify: break; case ShimNotificationType.PrepareRequestNotify: goto Label_02B0; case ShimNotificationType.CommitRequestNotify: goto Label_031A; case ShimNotificationType.AbortRequestNotify: goto Label_0358; case ShimNotificationType.CommittedNotify: try { OutcomeEnlistment enlistment7 = obj2 as OutcomeEnlistment; if (enlistment7 != null) { DiagnosticTrace.SetActivityId(enlistment7.TransactionIdentifier); enlistment7.Committed(); } else { OletxPhase1VolatileEnlistmentContainer container3 = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container3 != null) { DiagnosticTrace.SetActivityId(container3.TransactionIdentifier); container3.Committed(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } goto Label_0203; case ShimNotificationType.AbortedNotify: goto Label_0203; case ShimNotificationType.InDoubtNotify: goto Label_0251; case ShimNotificationType.EnlistmentTmDownNotify: goto Label_0396; case ShimNotificationType.ResourceManagerTmDownNotify: goto Label_03CD; default: goto Label_0410; } OletxPhase1VolatileEnlistmentContainer container4 = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container4 != null) { DiagnosticTrace.SetActivityId(container4.TransactionIdentifier); container4.VoteRequest(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; Label_0203 :; try { OutcomeEnlistment enlistment6 = obj2 as OutcomeEnlistment; if (enlistment6 != null) { DiagnosticTrace.SetActivityId(enlistment6.TransactionIdentifier); enlistment6.Aborted(); } else { OletxPhase1VolatileEnlistmentContainer container2 = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container2 != null) { DiagnosticTrace.SetActivityId(container2.TransactionIdentifier); container2.Aborted(); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0251 :; try { OutcomeEnlistment enlistment5 = obj2 as OutcomeEnlistment; if (enlistment5 != null) { DiagnosticTrace.SetActivityId(enlistment5.TransactionIdentifier); enlistment5.InDoubt(); } else { OletxPhase1VolatileEnlistmentContainer container = obj2 as OletxPhase1VolatileEnlistmentContainer; if (container != null) { DiagnosticTrace.SetActivityId(container.TransactionIdentifier); container.InDoubt(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_02B0: buffer = new byte[prepareInfoSize]; Marshal.Copy(prepareInfo.DangerousGetHandle(), buffer, 0, Convert.ToInt32(prepareInfoSize)); bool flag2 = true; try { OletxEnlistment enlistment4 = obj2 as OletxEnlistment; if (enlistment4 != null) { DiagnosticTrace.SetActivityId(enlistment4.TransactionIdentifier); flag2 = enlistment4.PrepareRequest(isSinglePhase, buffer); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { if (flag2) { HandleTable.FreeHandle(zero); } } Label_031A :; try { OletxEnlistment enlistment3 = obj2 as OletxEnlistment; if (enlistment3 != null) { DiagnosticTrace.SetActivityId(enlistment3.TransactionIdentifier); enlistment3.CommitRequest(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0358 :; try { OletxEnlistment enlistment2 = obj2 as OletxEnlistment; if (enlistment2 != null) { DiagnosticTrace.SetActivityId(enlistment2.TransactionIdentifier); enlistment2.AbortRequest(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0396 :; try { OletxEnlistment enlistment = obj2 as OletxEnlistment; if (enlistment != null) { DiagnosticTrace.SetActivityId(enlistment.TransactionIdentifier); enlistment.TMDown(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_03CD: manager2 = obj2 as OletxResourceManager; try { if (manager2 != null) { manager2.TMDown(); } else { OletxInternalResourceManager manager = obj2 as OletxInternalResourceManager; if (manager != null) { manager.TMDown(); } else { Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } } goto Label_0444; } finally { HandleTable.FreeHandle(zero); } Label_0410: Environment.FailFast(System.Transactions.SR.GetString("InternalError")); } finally { if (prepareInfo != null) { prepareInfo.Close(); } if (releaseRequired) { releaseRequired = false; processingTmDown = false; Monitor.Exit(proxyShimFactory); } } Label_0444: if (none != ShimNotificationType.None) { goto Label_003D; } flag3 = true; } finally { if (releaseRequired) { releaseRequired = false; processingTmDown = false; Monitor.Exit(proxyShimFactory); } if (!flag3 && (zero != IntPtr.Zero)) { HandleTable.FreeHandle(zero); } Thread.EndCriticalRegion(); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(System.Transactions.SR.GetString("TraceSourceOletx"), "OletxTransactionManager.ShimNotificationCallback"); } }
internal OletxVolatileEnlistmentContainer AddDependentClone(bool delayCommit) { IVoterBallotShim voterBallotShim = null; IPhase0EnlistmentShim shim2 = null; bool flag2 = false; bool flag = false; OletxVolatileEnlistmentContainer container3 = null; OletxPhase0VolatileEnlistmentContainer container = null; OletxPhase1VolatileEnlistmentContainer target = null; bool flag3 = false; bool flag5 = false; IntPtr zero = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { lock (this) { if (delayCommit) { if (this.phase0EnlistVolatilementContainerList == null) { this.phase0EnlistVolatilementContainerList = new ArrayList(1); } if (this.phase0EnlistVolatilementContainerList.Count == 0) { container = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { container = this.phase0EnlistVolatilementContainerList[this.phase0EnlistVolatilementContainerList.Count - 1] as OletxPhase0VolatileEnlistmentContainer; if (container != null) { this.TakeContainerLock(container, ref flag5); } if (!container.NewEnlistmentsAllowed) { this.ReleaseContainerLock(container, ref flag5); container = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { flag = false; } } if (flag) { zero = HandleTable.AllocHandle(container); } } else if (this.phase1EnlistVolatilementContainer == null) { target = new OletxPhase1VolatileEnlistmentContainer(this); flag2 = true; target.voterHandle = HandleTable.AllocHandle(target); } else { flag2 = false; target = this.phase1EnlistVolatilementContainer; } try { if (container != null) { this.TakeContainerLock(container, ref flag5); } if (flag) { this.transactionShim.Phase0Enlist(zero, out shim2); container.Phase0EnlistmentShim = shim2; } if (flag2) { this.OletxTransactionManagerInstance.dtcTransactionManagerLock.AcquireReaderLock(-1); try { this.transactionShim.CreateVoter(target.voterHandle, out voterBallotShim); flag3 = true; } finally { this.OletxTransactionManagerInstance.dtcTransactionManagerLock.ReleaseReaderLock(); } target.VoterBallotShim = voterBallotShim; } if (delayCommit) { if (flag) { this.phase0EnlistVolatilementContainerList.Add(container); } container.AddDependentClone(); return container; } if (flag2) { this.phase1EnlistVolatilementContainer = target; } target.AddDependentClone(); return target; } catch (COMException exception) { OletxTransactionManager.ProxyException(exception); throw; } return container3; } } finally { if (container != null) { this.ReleaseContainerLock(container, ref flag5); } if ((zero != IntPtr.Zero) && (container.Phase0EnlistmentShim == null)) { HandleTable.FreeHandle(zero); } if ((!flag3 && (target != null)) && ((target.voterHandle != IntPtr.Zero) && flag2)) { HandleTable.FreeHandle(target.voterHandle); } } return container3; }
internal IPromotedEnlistment CommonEnlistVolatile(IEnlistmentNotificationInternal enlistmentNotification, EnlistmentOptions enlistmentOptions, OletxTransaction oletxTransaction) { OletxVolatileEnlistment enlistment = null; bool flag2 = false; bool flag = false; OletxPhase0VolatileEnlistmentContainer target = null; OletxPhase1VolatileEnlistmentContainer container = null; IntPtr zero = IntPtr.Zero; IVoterBallotShim voterBallotShim = null; IPhase0EnlistmentShim shim = null; bool flag3 = false; RuntimeHelpers.PrepareConstrainedRegions(); try { lock (this) { enlistment = new OletxVolatileEnlistment(enlistmentNotification, enlistmentOptions, oletxTransaction); if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None) { if (this.phase0EnlistVolatilementContainerList == null) { this.phase0EnlistVolatilementContainerList = new ArrayList(1); } if (this.phase0EnlistVolatilementContainerList.Count == 0) { target = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { target = this.phase0EnlistVolatilementContainerList[this.phase0EnlistVolatilementContainerList.Count - 1] as OletxPhase0VolatileEnlistmentContainer; if (!target.NewEnlistmentsAllowed) { target = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { flag = false; } } if (flag) { zero = HandleTable.AllocHandle(target); } } else if (this.phase1EnlistVolatilementContainer == null) { flag2 = true; container = new OletxPhase1VolatileEnlistmentContainer(this) { voterHandle = HandleTable.AllocHandle(container) }; } else { flag2 = false; container = this.phase1EnlistVolatilementContainer; } try { if (flag) { lock (target) { this.transactionShim.Phase0Enlist(zero, out shim); target.Phase0EnlistmentShim = shim; } } if (flag2) { this.transactionShim.CreateVoter(container.voterHandle, out voterBallotShim); flag3 = true; container.VoterBallotShim = voterBallotShim; } if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None) { target.AddEnlistment(enlistment); if (flag) { this.phase0EnlistVolatilementContainerList.Add(target); } return enlistment; } container.AddEnlistment(enlistment); if (flag2) { this.phase1EnlistVolatilementContainer = container; } return enlistment; } catch (COMException exception) { OletxTransactionManager.ProxyException(exception); throw; } return enlistment; } } finally { if ((zero != IntPtr.Zero) && (target.Phase0EnlistmentShim == null)) { HandleTable.FreeHandle(zero); } if ((!flag3 && (container != null)) && ((container.voterHandle != IntPtr.Zero) && flag2)) { HandleTable.FreeHandle(container.voterHandle); } } return enlistment; }
internal OletxVolatileEnlistmentContainer AddDependentClone( bool delayCommit ) { IPhase0EnlistmentShim phase0Shim = null; IVoterBallotShim voterShim = null; bool needVoterEnlistment = false; bool needPhase0Enlistment = false; OletxVolatileEnlistmentContainer returnValue = null; OletxPhase0VolatileEnlistmentContainer localPhase0VolatileContainer = null; OletxPhase1VolatileEnlistmentContainer localPhase1VolatileContainer = null; bool enlistmentSucceeded = false; bool phase0ContainerLockAcquired = false; IntPtr phase0Handle = IntPtr.Zero; // Yes, we are talking to the proxy while holding the lock on the RealOletxTransaction. // If we don't then things get real sticky with other threads allocating containers. // We only do this the first time we get a depenent clone of a given type (delay vs. non-delay). // After that, we don't create a new container, except for Phase0 if we need to create one // for a second wave. RuntimeHelpers.PrepareConstrainedRegions(); try { lock ( this ) { if ( delayCommit ) { if ( null == this.phase0EnlistVolatilementContainerList ) { // Not using a MemoryBarrier because all access to this member variable is under a lock of the // object. this.phase0EnlistVolatilementContainerList = new ArrayList(1); } // We may have failed the proxy enlistment for the first container, but we would have // allocated the list. That is why we have this check here. if ( 0 == this.phase0EnlistVolatilementContainerList.Count ) { localPhase0VolatileContainer = new OletxPhase0VolatileEnlistmentContainer( this ); needPhase0Enlistment = true; } else { localPhase0VolatileContainer = this.phase0EnlistVolatilementContainerList[this.phase0EnlistVolatilementContainerList.Count - 1] as OletxPhase0VolatileEnlistmentContainer; if (localPhase0VolatileContainer != null) { //CSDMain 91509 - We now synchronize this call with the shim notification trying to call Phase0Request on this container TakeContainerLock(localPhase0VolatileContainer, ref phase0ContainerLockAcquired); } if ( ! localPhase0VolatileContainer.NewEnlistmentsAllowed ) { //It is OK to release the lock at this time because we are creating a new container that has not yet //been enlisted with DTC. So there is no ---- to worry about ReleaseContainerLock(localPhase0VolatileContainer, ref phase0ContainerLockAcquired); localPhase0VolatileContainer = new OletxPhase0VolatileEnlistmentContainer( this ); needPhase0Enlistment = true; } else { needPhase0Enlistment = false; } } if ( needPhase0Enlistment ) { // We need to create a VoterNotifyShim if native threads are not allowed to enter managed code. phase0Handle = HandleTable.AllocHandle( localPhase0VolatileContainer ); } } else // ! delayCommit { if ( null == this.phase1EnlistVolatilementContainer ) { localPhase1VolatileContainer = new OletxPhase1VolatileEnlistmentContainer( this ); needVoterEnlistment = true; // We need to create a VoterNotifyShim. localPhase1VolatileContainer.voterHandle = HandleTable.AllocHandle( localPhase1VolatileContainer ); } else { needVoterEnlistment = false; localPhase1VolatileContainer = this.phase1EnlistVolatilementContainer; } } try { //At this point, we definitely need the lock on the phase0 container so that it doesnt ---- with shim notifications from unmanaged code //corrupting state while we are in the middle of an AddDependentClone processing if (localPhase0VolatileContainer != null) { TakeContainerLock(localPhase0VolatileContainer, ref phase0ContainerLockAcquired); } // If enlistDuringPrepareRequired is true, we need to ask the proxy to create a Phase0 enlistment. if ( needPhase0Enlistment ) { // We need to use shims if native threads are not allowed to enter managed code. this.transactionShim.Phase0Enlist( phase0Handle, out phase0Shim ); localPhase0VolatileContainer.Phase0EnlistmentShim = phase0Shim; } if ( needVoterEnlistment ) { // We need to use shims if native threads are not allowed to enter managed code. OletxTransactionManagerInstance.dtcTransactionManagerLock.AcquireReaderLock( -1 ); try { this.transactionShim.CreateVoter( localPhase1VolatileContainer.voterHandle, out voterShim ); enlistmentSucceeded = true; } finally { OletxTransactionManagerInstance.dtcTransactionManagerLock.ReleaseReaderLock(); } localPhase1VolatileContainer.VoterBallotShim = voterShim; } if ( delayCommit ) { // if we needed a Phase0 enlistment, we need to add the container to the // list. if ( needPhase0Enlistment ) { this.phase0EnlistVolatilementContainerList.Add( localPhase0VolatileContainer ); } localPhase0VolatileContainer.AddDependentClone(); returnValue = localPhase0VolatileContainer; } else { // If we needed a voter enlistment, we need to save the container as THE // phase1 container for this transaction. if ( needVoterEnlistment ) { Debug.Assert( ( null == this.phase1EnlistVolatilementContainer ), "RealOletxTransaction.AddDependentClone - phase1VolContainer not null when expected" ); this.phase1EnlistVolatilementContainer = localPhase1VolatileContainer; } localPhase1VolatileContainer.AddDependentClone(); returnValue = localPhase1VolatileContainer; } } catch (COMException comException) { OletxTransactionManager.ProxyException( comException ); throw; } } } finally { //First release the lock on the phase 0 container if it was acquired. Any work on localPhase0VolatileContainer //that needs its state to be consistent while processing should do so before this statement is executed. if (localPhase0VolatileContainer != null) { ReleaseContainerLock(localPhase0VolatileContainer, ref phase0ContainerLockAcquired); } if ( phase0Handle != IntPtr.Zero && localPhase0VolatileContainer.Phase0EnlistmentShim == null ) { HandleTable.FreeHandle( phase0Handle ); } if ( !enlistmentSucceeded && null != localPhase1VolatileContainer && localPhase1VolatileContainer.voterHandle != IntPtr.Zero && needVoterEnlistment ) { HandleTable.FreeHandle( localPhase1VolatileContainer.voterHandle ); } } return returnValue; }
// Common constructor used by all types of constructors // Create a clean and fresh transaction. internal RealOletxTransaction(OletxTransactionManager transactionManager, ITransactionShim transactionShim, OutcomeEnlistment outcomeEnlistment, Guid identifier, OletxTransactionIsolationLevel oletxIsoLevel, bool isRoot ) { bool successful = false; try { // initialize the member fields this.oletxTransactionManager = transactionManager; this.transactionShim = transactionShim; this.outcomeEnlistment = outcomeEnlistment; this.txGuid = identifier; this.isolationLevel = OletxTransactionManager.ConvertIsolationLevelFromProxyValue( oletxIsoLevel ); this.status = TransactionStatus.Active; this.undisposedOletxTransactionCount = 0; this.phase0EnlistVolatilementContainerList = null; this.phase1EnlistVolatilementContainer = null; this.tooLateForEnlistments = false; this.internalTransaction = null; this.creationTime = DateTime.UtcNow; this.lastStateChangeTime = this.creationTime; // Connect this object with the OutcomeEnlistment. this.internalClone = new OletxTransaction( this ); // We have have been created without an outcome enlistment if it was too late to create // a clone from the ITransactionNative that we were created from. if ( null != this.outcomeEnlistment ) { this.outcomeEnlistment.SetRealTransaction( this ); } else { this.status = TransactionStatus.InDoubt; } if ( DiagnosticTrace.HaveListeners ) { DiagnosticTrace.TraceTransfer(this.txGuid); } successful = true; } finally { if (!successful) { if (this.outcomeEnlistment != null) { this.outcomeEnlistment.UnregisterOutcomeCallback(); this.outcomeEnlistment = null; } } } }
internal IPromotedEnlistment CommonEnlistVolatile( IEnlistmentNotificationInternal enlistmentNotification, EnlistmentOptions enlistmentOptions, OletxTransaction oletxTransaction ) { OletxVolatileEnlistment enlistment = null; bool needVoterEnlistment = false; bool needPhase0Enlistment = false; OletxPhase0VolatileEnlistmentContainer localPhase0VolatileContainer = null; OletxPhase1VolatileEnlistmentContainer localPhase1VolatileContainer = null; IntPtr phase0Handle = IntPtr.Zero; IVoterBallotShim voterShim = null; IPhase0EnlistmentShim phase0Shim = null; bool enlistmentSucceeded = false; // Yes, we are talking to the proxy while holding the lock on the RealOletxTransaction. // If we don't then things get real sticky with other threads allocating containers. // We only do this the first time we get a depenent clone of a given type (delay vs. non-delay). // After that, we don't create a new container, except for Phase0 if we need to create one // for a second wave. RuntimeHelpers.PrepareConstrainedRegions(); try { lock ( this ) { enlistment = new OletxVolatileEnlistment( enlistmentNotification, enlistmentOptions, oletxTransaction ); if ( (enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0 ) { if ( null == this.phase0EnlistVolatilementContainerList ) { // Not using a MemoryBarrier because all access to this member variable is done when holding // a lock on the object. this.phase0EnlistVolatilementContainerList = new ArrayList(1); } // We may have failed the proxy enlistment for the first container, but we would have // allocated the list. That is why we have this check here. if ( 0 == this.phase0EnlistVolatilementContainerList.Count ) { localPhase0VolatileContainer = new OletxPhase0VolatileEnlistmentContainer( this ); needPhase0Enlistment = true; } else { localPhase0VolatileContainer = this.phase0EnlistVolatilementContainerList[this.phase0EnlistVolatilementContainerList.Count - 1] as OletxPhase0VolatileEnlistmentContainer; if ( ! localPhase0VolatileContainer.NewEnlistmentsAllowed ) { localPhase0VolatileContainer = new OletxPhase0VolatileEnlistmentContainer( this ); needPhase0Enlistment = true; } else { needPhase0Enlistment = false; } } if ( needPhase0Enlistment ) { // We need to create a VoterNotifyShim if native threads are not allowed to enter managed code. phase0Handle = HandleTable.AllocHandle( localPhase0VolatileContainer ); } } else // not EDPR = TRUE - may need a voter... { if ( null == this.phase1EnlistVolatilementContainer ) { needVoterEnlistment = true; localPhase1VolatileContainer = new OletxPhase1VolatileEnlistmentContainer( this ); // We need to create a VoterNotifyShim. localPhase1VolatileContainer.voterHandle = HandleTable.AllocHandle( localPhase1VolatileContainer ); } else { needVoterEnlistment = false; localPhase1VolatileContainer = this.phase1EnlistVolatilementContainer; } } try { // If enlistDuringPrepareRequired is true, we need to ask the proxy to create a Phase0 enlistment. if ( needPhase0Enlistment ) { lock ( localPhase0VolatileContainer ) { transactionShim.Phase0Enlist( phase0Handle, out phase0Shim ); localPhase0VolatileContainer.Phase0EnlistmentShim = phase0Shim; } } if ( needVoterEnlistment ) { this.transactionShim.CreateVoter( localPhase1VolatileContainer.voterHandle, out voterShim ); enlistmentSucceeded = true; localPhase1VolatileContainer.VoterBallotShim = voterShim; } if ( (enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != 0 ) { localPhase0VolatileContainer.AddEnlistment( enlistment ); if ( needPhase0Enlistment ) { this.phase0EnlistVolatilementContainerList.Add( localPhase0VolatileContainer ); } } else { localPhase1VolatileContainer.AddEnlistment( enlistment ); if ( needVoterEnlistment ) { Debug.Assert( ( null == this.phase1EnlistVolatilementContainer ), "RealOletxTransaction.CommonEnlistVolatile - phase1VolContainer not null when expected." ); this.phase1EnlistVolatilementContainer = localPhase1VolatileContainer; } } } catch (COMException comException) { OletxTransactionManager.ProxyException( comException ); throw; } } } finally { if ( phase0Handle != IntPtr.Zero && localPhase0VolatileContainer.Phase0EnlistmentShim == null ) { HandleTable.FreeHandle( phase0Handle ); } if ( !enlistmentSucceeded && null != localPhase1VolatileContainer && localPhase1VolatileContainer.voterHandle != IntPtr.Zero && needVoterEnlistment ) { HandleTable.FreeHandle( localPhase1VolatileContainer.voterHandle ); } } return enlistment; }
internal OletxVolatileEnlistmentContainer AddDependentClone(bool delayCommit) { IVoterBallotShim voterBallotShim = null; IPhase0EnlistmentShim shim2 = null; bool flag2 = false; bool flag = false; OletxVolatileEnlistmentContainer container3 = null; OletxPhase0VolatileEnlistmentContainer container = null; OletxPhase1VolatileEnlistmentContainer target = null; bool flag3 = false; bool flag5 = false; IntPtr zero = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { lock (this) { if (delayCommit) { if (this.phase0EnlistVolatilementContainerList == null) { this.phase0EnlistVolatilementContainerList = new ArrayList(1); } if (this.phase0EnlistVolatilementContainerList.Count == 0) { container = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { container = this.phase0EnlistVolatilementContainerList[this.phase0EnlistVolatilementContainerList.Count - 1] as OletxPhase0VolatileEnlistmentContainer; if (container != null) { this.TakeContainerLock(container, ref flag5); } if (!container.NewEnlistmentsAllowed) { this.ReleaseContainerLock(container, ref flag5); container = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { flag = false; } } if (flag) { zero = HandleTable.AllocHandle(container); } } else if (this.phase1EnlistVolatilementContainer == null) { target = new OletxPhase1VolatileEnlistmentContainer(this); flag2 = true; target.voterHandle = HandleTable.AllocHandle(target); } else { flag2 = false; target = this.phase1EnlistVolatilementContainer; } try { if (container != null) { this.TakeContainerLock(container, ref flag5); } if (flag) { this.transactionShim.Phase0Enlist(zero, out shim2); container.Phase0EnlistmentShim = shim2; } if (flag2) { this.OletxTransactionManagerInstance.dtcTransactionManagerLock.AcquireReaderLock(-1); try { this.transactionShim.CreateVoter(target.voterHandle, out voterBallotShim); flag3 = true; } finally { this.OletxTransactionManagerInstance.dtcTransactionManagerLock.ReleaseReaderLock(); } target.VoterBallotShim = voterBallotShim; } if (delayCommit) { if (flag) { this.phase0EnlistVolatilementContainerList.Add(container); } container.AddDependentClone(); return(container); } if (flag2) { this.phase1EnlistVolatilementContainer = target; } target.AddDependentClone(); return(target); } catch (COMException exception) { OletxTransactionManager.ProxyException(exception); throw; } return(container3); } } finally { if (container != null) { this.ReleaseContainerLock(container, ref flag5); } if ((zero != IntPtr.Zero) && (container.Phase0EnlistmentShim == null)) { HandleTable.FreeHandle(zero); } if ((!flag3 && (target != null)) && ((target.voterHandle != IntPtr.Zero) && flag2)) { HandleTable.FreeHandle(target.voterHandle); } } return(container3); }
internal IPromotedEnlistment CommonEnlistVolatile(IEnlistmentNotificationInternal enlistmentNotification, EnlistmentOptions enlistmentOptions, OletxTransaction oletxTransaction) { OletxVolatileEnlistment enlistment = null; bool flag2 = false; bool flag = false; OletxPhase0VolatileEnlistmentContainer target = null; OletxPhase1VolatileEnlistmentContainer container = null; IntPtr zero = IntPtr.Zero; IVoterBallotShim voterBallotShim = null; IPhase0EnlistmentShim shim = null; bool flag3 = false; RuntimeHelpers.PrepareConstrainedRegions(); try { lock (this) { enlistment = new OletxVolatileEnlistment(enlistmentNotification, enlistmentOptions, oletxTransaction); if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None) { if (this.phase0EnlistVolatilementContainerList == null) { this.phase0EnlistVolatilementContainerList = new ArrayList(1); } if (this.phase0EnlistVolatilementContainerList.Count == 0) { target = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { target = this.phase0EnlistVolatilementContainerList[this.phase0EnlistVolatilementContainerList.Count - 1] as OletxPhase0VolatileEnlistmentContainer; if (!target.NewEnlistmentsAllowed) { target = new OletxPhase0VolatileEnlistmentContainer(this); flag = true; } else { flag = false; } } if (flag) { zero = HandleTable.AllocHandle(target); } } else if (this.phase1EnlistVolatilementContainer == null) { flag2 = true; container = new OletxPhase1VolatileEnlistmentContainer(this) { voterHandle = HandleTable.AllocHandle(container) }; } else { flag2 = false; container = this.phase1EnlistVolatilementContainer; } try { if (flag) { lock (target) { this.transactionShim.Phase0Enlist(zero, out shim); target.Phase0EnlistmentShim = shim; } } if (flag2) { this.transactionShim.CreateVoter(container.voterHandle, out voterBallotShim); flag3 = true; container.VoterBallotShim = voterBallotShim; } if ((enlistmentOptions & EnlistmentOptions.EnlistDuringPrepareRequired) != EnlistmentOptions.None) { target.AddEnlistment(enlistment); if (flag) { this.phase0EnlistVolatilementContainerList.Add(target); } return(enlistment); } container.AddEnlistment(enlistment); if (flag2) { this.phase1EnlistVolatilementContainer = container; } return(enlistment); } catch (COMException exception) { OletxTransactionManager.ProxyException(exception); throw; } return(enlistment); } } finally { if ((zero != IntPtr.Zero) && (target.Phase0EnlistmentShim == null)) { HandleTable.FreeHandle(zero); } if ((!flag3 && (container != null)) && ((container.voterHandle != IntPtr.Zero) && flag2)) { HandleTable.FreeHandle(container.voterHandle); } } return(enlistment); }
internal static void ShimNotificationCallback(object state, bool timeout) { // First we need to get the notification from the shim factory. IntPtr enlistmentHandleIntPtr = IntPtr.Zero; ShimNotificationType shimNotificationType = ShimNotificationType.None; bool isSinglePhase = false; bool abortingHint = false; UInt32 prepareInfoSize = 0; CoTaskMemHandle prepareInfoBuffer = null; bool holdingNotificationLock = false; bool cleanExit = false; IDtcProxyShimFactory localProxyShimFactory = null; if (DiagnosticTrace.Verbose) { MethodEnteredTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx), "OletxTransactionManager.ShimNotificationCallback" ); } // This lock doesn't really protect any of our data. It is here so that if an exception occurs // while calling out to the app, we get an escalation to AppDomainUnload. Thread.BeginCriticalRegion(); try { do { // Take a local copy of the proxyShimFactory because if we get an RM TMDown notification, // we will still hold the critical section in that factory, but processing of the TMDown will // cause replacement of the OletxTransactionManager.proxyShimFactory. localProxyShimFactory = OletxTransactionManager.proxyShimFactory; try { Thread.BeginThreadAffinity(); RuntimeHelpers.PrepareConstrainedRegions(); try { localProxyShimFactory.GetNotification( out enlistmentHandleIntPtr, out shimNotificationType, out isSinglePhase, out abortingHint, out holdingNotificationLock, out prepareInfoSize, out prepareInfoBuffer ); } finally { if (holdingNotificationLock) { if ((HandleTable.FindHandle(enlistmentHandleIntPtr)) is OletxInternalResourceManager) { // In this case we know that the TM has gone down and we need to exchange // the native lock for a managed lock. processingTmDown = true; #pragma warning disable 0618 //@ System.Threading.Monitor.Enter(OletxTransactionManager.proxyShimFactory); #pragma warning restore 0618 } else { holdingNotificationLock = false; } localProxyShimFactory.ReleaseNotificationLock(); } Thread.EndThreadAffinity(); } // If a TM down is being processed it is possible that the native lock // has been exchanged for a managed lock. In that case we need to attempt // to take a lock to hold up processing more events until the TM down // processing is complete. if (processingTmDown) { lock (OletxTransactionManager.proxyShimFactory) { // We don't do any work under this lock just make sure that we // can take it. } } if (ShimNotificationType.None != shimNotificationType) { Object target = HandleTable.FindHandle(enlistmentHandleIntPtr); // Next, based on the notification type, cast the Handle accordingly and make // the appropriate call on the enlistment. switch (shimNotificationType) { case ShimNotificationType.Phase0RequestNotify: { try { OletxPhase0VolatileEnlistmentContainer ph0VolEnlistContainer = target as OletxPhase0VolatileEnlistmentContainer; if (null != ph0VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph0VolEnlistContainer.TransactionIdentifier); //CSDMain 91509 - We now synchronize this call with the AddDependentClone call in RealOleTxTransaction ph0VolEnlistContainer.Phase0Request(abortingHint); } else { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.Phase0Request(abortingHint); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.VoteRequestNotify: { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.VoteRequest(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } break; } case ShimNotificationType.CommittedNotify: { try { OutcomeEnlistment outcomeEnlistment = target as OutcomeEnlistment; if (null != outcomeEnlistment) { DiagnosticTrace.SetActivityId( outcomeEnlistment.TransactionIdentifier); outcomeEnlistment.Committed(); } else { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.Committed(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.AbortedNotify: { try { OutcomeEnlistment outcomeEnlistment = target as OutcomeEnlistment; if (null != outcomeEnlistment) { DiagnosticTrace.SetActivityId( outcomeEnlistment.TransactionIdentifier); outcomeEnlistment.Aborted(); } else { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.Aborted(); } // else // Voters may receive notifications even // in cases where they therwise respond // negatively to the vote request. It is // also not guaranteed that we will get a // notification if we do respond negatively. // The only safe thing to do is to free the // Handle when we abort the transaction // with a voter. These two things together // mean that we cannot guarantee that this // Handle will be alive when we get this // notification. } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.InDoubtNotify: { try { OutcomeEnlistment outcomeEnlistment = target as OutcomeEnlistment; if (null != outcomeEnlistment) { DiagnosticTrace.SetActivityId( outcomeEnlistment.TransactionIdentifier); outcomeEnlistment.InDoubt(); } else { OletxPhase1VolatileEnlistmentContainer ph1VolEnlistContainer = target as OletxPhase1VolatileEnlistmentContainer; if (null != ph1VolEnlistContainer) { DiagnosticTrace.SetActivityId( ph1VolEnlistContainer.TransactionIdentifier); ph1VolEnlistContainer.InDoubt(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.PrepareRequestNotify: { byte[] prepareInfo = new byte[prepareInfoSize]; Marshal.Copy(prepareInfoBuffer.DangerousGetHandle(), prepareInfo, 0, Convert.ToInt32(prepareInfoSize)); bool enlistmentDone = true; try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistmentDone = enlistment.PrepareRequest( isSinglePhase, prepareInfo ); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { if (enlistmentDone) { HandleTable.FreeHandle(enlistmentHandleIntPtr); } } break; } case ShimNotificationType.CommitRequestNotify: { try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.CommitRequest(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.AbortRequestNotify: { try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.AbortRequest(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.EnlistmentTmDownNotify: { try { OletxEnlistment enlistment = target as OletxEnlistment; if (null != enlistment) { DiagnosticTrace.SetActivityId( enlistment.TransactionIdentifier); enlistment.TMDown(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } finally { // We aren't going to get any more notifications on this. HandleTable.FreeHandle(enlistmentHandleIntPtr); } break; } case ShimNotificationType.ResourceManagerTmDownNotify: { OletxResourceManager resourceManager = target as OletxResourceManager; try { if (null != resourceManager) { resourceManager.TMDown(); } else { OletxInternalResourceManager internalResourceManager = target as OletxInternalResourceManager; if (null != internalResourceManager) { internalResourceManager.TMDown(); } else { Environment.FailFast(SR.GetString(SR.InternalError)); } } } finally { HandleTable.FreeHandle(enlistmentHandleIntPtr); } // Note that we don't free the gchandle on the OletxResourceManager. These objects // are not going to go away. break; } default: { Environment.FailFast(SR.GetString(SR.InternalError)); break; } } } } finally { if (null != prepareInfoBuffer) { prepareInfoBuffer.Close(); } if (holdingNotificationLock) { holdingNotificationLock = false; processingTmDown = false; System.Threading.Monitor.Exit(OletxTransactionManager.proxyShimFactory); } } }while (ShimNotificationType.None != shimNotificationType); cleanExit = true; } finally { if (holdingNotificationLock) { holdingNotificationLock = false; processingTmDown = false; System.Threading.Monitor.Exit(OletxTransactionManager.proxyShimFactory); } if (!cleanExit && enlistmentHandleIntPtr != IntPtr.Zero) { HandleTable.FreeHandle(enlistmentHandleIntPtr); } Thread.EndCriticalRegion(); } if (DiagnosticTrace.Verbose) { MethodExitedTraceRecord.Trace(SR.GetString(SR.TraceSourceOletx), "OletxTransactionManager.ShimNotificationCallback" ); } }