ThreadBehavior.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Dispatcher
  5. {
  6. using System;
  7. using System.Runtime;
  8. using System.ServiceModel;
  9. using System.ServiceModel.Activation;
  10. using System.Threading;
  11. class ThreadBehavior
  12. {
  13. SendOrPostCallback threadAffinityStartCallback;
  14. SendOrPostCallback threadAffinityEndCallback;
  15. static Action<object> cleanThreadCallback;
  16. readonly SynchronizationContext context;
  17. internal ThreadBehavior(DispatchRuntime dispatch)
  18. {
  19. this.context = dispatch.SynchronizationContext;
  20. }
  21. SendOrPostCallback ThreadAffinityStartCallbackDelegate
  22. {
  23. get
  24. {
  25. if (this.threadAffinityStartCallback == null)
  26. {
  27. this.threadAffinityStartCallback = new SendOrPostCallback(this.SynchronizationContextStartCallback);
  28. }
  29. return this.threadAffinityStartCallback;
  30. }
  31. }
  32. SendOrPostCallback ThreadAffinityEndCallbackDelegate
  33. {
  34. get
  35. {
  36. if (this.threadAffinityEndCallback == null)
  37. {
  38. this.threadAffinityEndCallback = new SendOrPostCallback(this.SynchronizationContextEndCallback);
  39. }
  40. return this.threadAffinityEndCallback;
  41. }
  42. }
  43. static Action<object> CleanThreadCallbackDelegate
  44. {
  45. get
  46. {
  47. if (ThreadBehavior.cleanThreadCallback == null)
  48. {
  49. ThreadBehavior.cleanThreadCallback = new Action<object>(ThreadBehavior.CleanThreadCallback);
  50. }
  51. return ThreadBehavior.cleanThreadCallback;
  52. }
  53. }
  54. internal void BindThread(ref MessageRpc rpc)
  55. {
  56. this.BindCore(ref rpc, true);
  57. }
  58. internal void BindEndThread(ref MessageRpc rpc)
  59. {
  60. this.BindCore(ref rpc, false);
  61. }
  62. void BindCore(ref MessageRpc rpc, bool startOperation)
  63. {
  64. SynchronizationContext syncContext = GetSyncContext(rpc.InstanceContext);
  65. if (syncContext != null)
  66. {
  67. IResumeMessageRpc resume = rpc.Pause();
  68. if (startOperation)
  69. {
  70. syncContext.OperationStarted();
  71. syncContext.Post(this.ThreadAffinityStartCallbackDelegate, resume);
  72. }
  73. else
  74. {
  75. syncContext.Post(this.ThreadAffinityEndCallbackDelegate, resume);
  76. }
  77. }
  78. else if (rpc.SwitchedThreads)
  79. {
  80. IResumeMessageRpc resume = rpc.Pause();
  81. ActionItem.Schedule(ThreadBehavior.CleanThreadCallbackDelegate, resume);
  82. }
  83. }
  84. SynchronizationContext GetSyncContext(InstanceContext instanceContext)
  85. {
  86. Fx.Assert(instanceContext != null, "instanceContext is null !");
  87. SynchronizationContext syncContext = instanceContext.SynchronizationContext ?? this.context;
  88. return syncContext;
  89. }
  90. void SynchronizationContextStartCallback(object state)
  91. {
  92. ResumeProcessing((IResumeMessageRpc)state);
  93. }
  94. void SynchronizationContextEndCallback(object state)
  95. {
  96. IResumeMessageRpc resume = (IResumeMessageRpc)state;
  97. ResumeProcessing(resume);
  98. SynchronizationContext syncContext = GetSyncContext(resume.GetMessageInstanceContext());
  99. Fx.Assert(syncContext != null, "syncContext is null !?");
  100. syncContext.OperationCompleted();
  101. }
  102. void ResumeProcessing(IResumeMessageRpc resume)
  103. {
  104. bool alreadyResumedNoLock;
  105. resume.Resume(out alreadyResumedNoLock);
  106. if (alreadyResumedNoLock)
  107. {
  108. string text = SR.GetString(SR.SFxMultipleCallbackFromSynchronizationContext, context.GetType().ToString());
  109. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(text));
  110. }
  111. }
  112. static void CleanThreadCallback(object state)
  113. {
  114. bool alreadyResumedNoLock;
  115. ((IResumeMessageRpc)state).Resume(out alreadyResumedNoLock);
  116. if (alreadyResumedNoLock)
  117. {
  118. Fx.Assert("IOThreadScheduler called back twice");
  119. }
  120. }
  121. internal static SynchronizationContext GetCurrentSynchronizationContext()
  122. {
  123. if (AspNetEnvironment.IsApplicationDomainHosted())
  124. {
  125. return null;
  126. }
  127. return SynchronizationContext.Current;
  128. }
  129. }
  130. }