unsafe int PeekLockCore(MsmqQueueHandle handle, MsmqInputMessage message, TimeSpan timeout) { int retCode = 0; ITransaction internalTrans; TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); IntPtr nativePropertiesPointer = message.Pin(); try { bool receivedMessage = false; while (!receivedMessage) { retCode = UnsafeNativeMethods.MQBeginTransaction(out internalTrans); if (retCode != 0) { return retCode; } int timeoutInMilliseconds = TimeoutHelper.ToMilliseconds(timeoutHelper.RemainingTime()); // no timeout interval if timeout has been set to 0 otherwise a minimum of 100 int timeoutIntervalInMilliseconds = (timeoutInMilliseconds == 0) ? 0 : 100; // receive until timeout but let go of receive lock for other contenders periodically while (true) { lock (this.receiveLock) { retCode = UnsafeNativeMethods.MQReceiveMessage(handle.DangerousGetHandle(), timeoutIntervalInMilliseconds, UnsafeNativeMethods.MQ_ACTION_RECEIVE, nativePropertiesPointer, null, IntPtr.Zero, IntPtr.Zero, internalTrans); if (retCode == UnsafeNativeMethods.MQ_ERROR_IO_TIMEOUT) { // keep trying until we timeout timeoutInMilliseconds = TimeoutHelper.ToMilliseconds(timeoutHelper.RemainingTime()); if (timeoutInMilliseconds == 0) { return retCode; } } else if (retCode != 0) { BOID boid = new BOID(); internalTrans.Abort( ref boid, // pboidReason 0, // fRetaining 0 // fAsync ); return retCode; // we don't need to release the ITransaction as MSMQ does not increment the ref counter // in MQBeginTransaction } else { // we got a message within the specified time out break; } } } TransactionLookupEntry entry; lock (this.internalStateLock) { if (!this.lockMap.TryGetValue(message.LookupId.Value, out entry)) { this.lockMap.Add(message.LookupId.Value, new TransactionLookupEntry(message.LookupId.Value, internalTrans)); receivedMessage = true; } else { // this was a message that was in the process of being handed off // from some app trans to some internal MSMQ transaction // and we grabbed it before the Abort() could finish // need to be a good citizen and finish that Abort() job for it entry.MsmqInternalTransaction = internalTrans; } } } } finally { message.Unpin(); } return retCode; }
// The demand is not added now (in 4.5), to avoid a breaking change. To be considered in the next version. /* // We demand full trust because we call code from a non-APTCA assembly. // MSMQ is not enabled in partial trust, so this demand should not break customers. [PermissionSet(SecurityAction.Demand, Unrestricted = true)] */ public void UnlockMessage(long lookupId, TimeSpan timeout) { TransactionLookupEntry entry; lock (this.internalStateLock) { if (this.lockMap.TryGetValue(lookupId, out entry)) { if (entry.MsmqInternalTransaction != null) { BOID boid = new BOID(); entry.MsmqInternalTransaction.Abort( ref boid, // pboidReason 0, // fRetaining 0 // fAsync ); } this.lockMap.Remove(lookupId); } } }
unsafe int TryRelockMessage(long lookupId) { int retCode = 0; ITransaction internalTrans; using (MsmqEmptyMessage message = new MsmqEmptyMessage()) { IntPtr nativePropertiesPointer = message.Pin(); try { // don't want other threads receiving the message we want to relock lock (this.receiveLock) { MsmqQueueHandle handle = GetHandle(); TransactionLookupEntry entry; lock (this.internalStateLock) { if (!this.lockMap.TryGetValue(lookupId, out entry)) { // should never get here return retCode; } if (entry.MsmqInternalTransaction == null) { retCode = UnsafeNativeMethods.MQBeginTransaction(out internalTrans); if (retCode != 0) { return retCode; } retCode = UnsafeNativeMethods.MQReceiveMessageByLookupId(handle, lookupId, UnsafeNativeMethods.MQ_LOOKUP_RECEIVE_CURRENT, nativePropertiesPointer, null, IntPtr.Zero, internalTrans); if (retCode != 0) { BOID boid = new BOID(); internalTrans.Abort( ref boid, // pboidReason 0, // fRetaining 0 // fAsync ); return retCode; } entry.MsmqInternalTransaction = internalTrans; } } } } finally { message.Unpin(); } } return retCode; }
// The demand is not added now (in 4.5), to avoid a breaking change. To be considered in the next version. /* // We demand full trust because we call code from a non-APTCA assembly. // MSMQ is not enabled in partial trust, so this demand should not break customers. [PermissionSet(SecurityAction.Demand, Unrestricted = true)] */ public void DeleteMessage(long lookupId, TimeSpan timeout) { TransactionLookupEntry entry; if (Transaction.Current != null && Transaction.Current.TransactionInformation.Status != System.Transactions.TransactionStatus.Active) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqAmbientTransactionInactive))); } lock (this.internalStateLock) { if (!this.lockMap.TryGetValue(lookupId, out entry)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MessageNotInLockedState, lookupId))); } // a failed relock is the same as not having a lock if (entry.MsmqInternalTransaction == null) { this.lockMap.Remove(entry.LookupId); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MessageNotInLockedState, lookupId))); } } if (Transaction.Current == null) { entry.MsmqInternalTransaction.Commit( 0, // fRetaining 0, // grfTC 0 // grfRM ); lock (this.internalStateLock) { this.lockMap.Remove(lookupId); } } else { // we don't want any thread receiving the message we are trying to re-receive in a new transaction lock (this.receiveLock) { MsmqQueueHandle handle = GetHandle(); // abort internal transaction and re-receive in the ambient transaction BOID boid = new BOID(); entry.MsmqInternalTransaction.Abort( ref boid, // pboidReason 0, // fRetaining 0 // fAsync ); // null indicates that the associated internal tx was aborted and the message is now // unlocked as far as the native queue manager is concerned entry.MsmqInternalTransaction = null; using (MsmqEmptyMessage emptyMessage = new MsmqEmptyMessage()) { int error = 0; try { error = base.ReceiveByLookupIdCoreDtcTransacted(handle, lookupId, emptyMessage, MsmqTransactionMode.CurrentOrThrow, UnsafeNativeMethods.MQ_LOOKUP_RECEIVE_CURRENT); } catch (ObjectDisposedException ex) { // ---- with Close MsmqDiagnostics.ExpectedException(ex); } if (error != 0) { if (IsErrorDueToStaleHandle(error)) { HandleIsStale(handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MsmqCannotReacquireLock), error)); } } } List<long> transMsgs; lock (this.internalStateLock) { if (!this.dtcTransMap.TryGetValue(Transaction.Current.TransactionInformation.DistributedIdentifier, out transMsgs)) { transMsgs = new List<long>(); this.dtcTransMap.Add(Transaction.Current.TransactionInformation.DistributedIdentifier, transMsgs); // only need to attach the tx complete handler once per transaction Transaction.Current.TransactionCompleted += this.transactionCompletedHandler; } transMsgs.Add(lookupId); } } }
public void DeleteMessage(long lookupId, TimeSpan timeout) { TransactionLookupEntry entry; if ((Transaction.Current != null) && (Transaction.Current.TransactionInformation.Status != System.Transactions.TransactionStatus.Active)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MsmqAmbientTransactionInactive"))); } lock (this.internalStateLock) { if (!this.lockMap.TryGetValue(lookupId, out entry)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MessageNotInLockedState", new object[] { lookupId }))); } if (entry.MsmqInternalTransaction == null) { this.lockMap.Remove(entry.LookupId); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MessageNotInLockedState", new object[] { lookupId }))); } } if (Transaction.Current == null) { entry.MsmqInternalTransaction.Commit(0, 0, 0); lock (this.internalStateLock) { this.lockMap.Remove(lookupId); return; } } lock (this.receiveLock) { MsmqQueueHandle handle = base.GetHandle(); BOID pboidReason = new BOID(); entry.MsmqInternalTransaction.Abort(ref pboidReason, 0, 0); entry.MsmqInternalTransaction = null; using (MsmqEmptyMessage message = new MsmqEmptyMessage()) { int error = 0; try { error = base.ReceiveByLookupIdCoreDtcTransacted(handle, lookupId, message, MsmqTransactionMode.CurrentOrThrow, 0x40000020); } catch (ObjectDisposedException exception) { MsmqDiagnostics.ExpectedException(exception); } if (error != 0) { if (MsmqQueue.IsErrorDueToStaleHandle(error)) { base.HandleIsStale(handle); } throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MsmqCannotReacquireLock"), error)); } } } lock (this.internalStateLock) { List<long> list; if (!this.dtcTransMap.TryGetValue(Transaction.Current.TransactionInformation.DistributedIdentifier, out list)) { list = new List<long>(); this.dtcTransMap.Add(Transaction.Current.TransactionInformation.DistributedIdentifier, list); Transaction.Current.TransactionCompleted += this.transactionCompletedHandler; } list.Add(lookupId); } }
public void UnlockMessage(long lookupId, TimeSpan timeout) { lock (this.internalStateLock) { TransactionLookupEntry entry; if (this.lockMap.TryGetValue(lookupId, out entry)) { if (entry.MsmqInternalTransaction != null) { BOID pboidReason = new BOID(); entry.MsmqInternalTransaction.Abort(ref pboidReason, 0, 0); } this.lockMap.Remove(lookupId); } } }
private int TryRelockMessage(long lookupId) { int num = 0; using (MsmqEmptyMessage message = new MsmqEmptyMessage()) { IntPtr properties = message.Pin(); try { lock (this.receiveLock) { MsmqQueueHandle handle = base.GetHandle(); lock (this.internalStateLock) { TransactionLookupEntry entry; if (this.lockMap.TryGetValue(lookupId, out entry)) { ITransaction transaction; if (entry.MsmqInternalTransaction != null) { return num; } num = UnsafeNativeMethods.MQBeginTransaction(out transaction); if (num != 0) { return num; } num = UnsafeNativeMethods.MQReceiveMessageByLookupId(handle, lookupId, 0x40000020, properties, null, IntPtr.Zero, transaction); if (num != 0) { BOID pboidReason = new BOID(); transaction.Abort(ref pboidReason, 0, 0); return num; } entry.MsmqInternalTransaction = transaction; } return num; } return num; } return num; } finally { message.Unpin(); } } return num; }
private int PeekLockCore(MsmqQueueHandle handle, MsmqInputMessage message, TimeSpan timeout) { int num = 0; TimeoutHelper helper = new TimeoutHelper(timeout); IntPtr properties = message.Pin(); try { bool flag = false; while (!flag) { ITransaction transaction; bool flag2; object obj2; num = UnsafeNativeMethods.MQBeginTransaction(out transaction); if (num != 0) { return num; } int num3 = (TimeoutHelper.ToMilliseconds(helper.RemainingTime()) == 0) ? 0 : 100; Label_0045: flag2 = false; try { Monitor.Enter(obj2 = this.receiveLock, ref flag2); num = UnsafeNativeMethods.MQReceiveMessage(handle.DangerousGetHandle(), num3, 0, properties, null, IntPtr.Zero, IntPtr.Zero, transaction); if (num == -1072824293) { if (TimeoutHelper.ToMilliseconds(helper.RemainingTime()) == 0) { return num; } goto Label_0045; } if (num != 0) { BOID pboidReason = new BOID(); transaction.Abort(ref pboidReason, 0, 0); return num; } } finally { if (flag2) { Monitor.Exit(obj2); } } lock (this.internalStateLock) { TransactionLookupEntry entry; if (!this.lockMap.TryGetValue(message.LookupId.Value, out entry)) { this.lockMap.Add(message.LookupId.Value, new TransactionLookupEntry(message.LookupId.Value, transaction)); flag = true; } else { entry.MsmqInternalTransaction = transaction; } continue; } } } finally { message.Unpin(); } return num; }