SignalGate.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.Runtime
  5. {
  6. using System;
  7. using System.Threading;
  8. [Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.NonBlocking)]
  9. class SignalGate
  10. {
  11. [Fx.Tag.SynchronizationObject(Blocking = false, Kind = Fx.Tag.SynchronizationKind.InterlockedNoSpin)]
  12. int state;
  13. public SignalGate()
  14. {
  15. }
  16. internal bool IsLocked
  17. {
  18. get
  19. {
  20. return this.state == GateState.Locked;
  21. }
  22. }
  23. internal bool IsSignalled
  24. {
  25. get
  26. {
  27. return this.state == GateState.Signalled;
  28. }
  29. }
  30. // Returns true if this brings the gate to the Signalled state.
  31. // Transitions - Locked -> SignalPending | Completed before it was unlocked
  32. // Unlocked -> Signaled
  33. public bool Signal()
  34. {
  35. int lastState = this.state;
  36. if (lastState == GateState.Locked)
  37. {
  38. lastState = Interlocked.CompareExchange(ref this.state, GateState.SignalPending, GateState.Locked);
  39. }
  40. if (lastState == GateState.Unlocked)
  41. {
  42. this.state = GateState.Signalled;
  43. return true;
  44. }
  45. if (lastState != GateState.Locked)
  46. {
  47. ThrowInvalidSignalGateState();
  48. }
  49. return false;
  50. }
  51. // Returns true if this brings the gate to the Signalled state.
  52. // Transitions - SignalPending -> Signaled | return the AsyncResult since the callback already
  53. // | completed and provided the result on its thread
  54. // Locked -> Unlocked
  55. public bool Unlock()
  56. {
  57. int lastState = this.state;
  58. if (lastState == GateState.Locked)
  59. {
  60. lastState = Interlocked.CompareExchange(ref this.state, GateState.Unlocked, GateState.Locked);
  61. }
  62. if (lastState == GateState.SignalPending)
  63. {
  64. this.state = GateState.Signalled;
  65. return true;
  66. }
  67. if (lastState != GateState.Locked)
  68. {
  69. ThrowInvalidSignalGateState();
  70. }
  71. return false;
  72. }
  73. // This is factored out to allow Signal and Unlock to be inlined.
  74. void ThrowInvalidSignalGateState()
  75. {
  76. throw Fx.Exception.AsError(new InvalidOperationException(InternalSR.InvalidSemaphoreExit));
  77. }
  78. static class GateState
  79. {
  80. public const int Locked = 0;
  81. public const int SignalPending = 1;
  82. public const int Unlocked = 2;
  83. public const int Signalled = 3;
  84. }
  85. }
  86. [Fx.Tag.SynchronizationPrimitive(Fx.Tag.BlocksUsing.NonBlocking)]
  87. class SignalGate<T> : SignalGate
  88. {
  89. T result;
  90. public SignalGate()
  91. : base()
  92. {
  93. }
  94. public bool Signal(T result)
  95. {
  96. this.result = result;
  97. return Signal();
  98. }
  99. public bool Unlock(out T result)
  100. {
  101. if (Unlock())
  102. {
  103. result = this.result;
  104. return true;
  105. }
  106. result = default(T);
  107. return false;
  108. }
  109. }
  110. }