Timer.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. //
  2. // System.Threading.Timer.cs
  3. //
  4. // Authors:
  5. // Dick Porter ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. //
  8. // (C) 2001, 2002 Ximian, Inc. http://www.ximian.com
  9. // (C) 2004 Novell, Inc. http://www.novell.com
  10. //
  11. namespace System.Threading
  12. {
  13. public sealed class Timer : MarshalByRefObject, IDisposable
  14. {
  15. sealed class Runner : MarshalByRefObject
  16. {
  17. ManualResetEvent wait;
  18. AutoResetEvent start_event;
  19. TimerCallback callback;
  20. object state;
  21. int dueTime;
  22. int period;
  23. bool disposed;
  24. bool aborted;
  25. public Runner (TimerCallback callback, object state, AutoResetEvent start_event)
  26. {
  27. this.callback = callback;
  28. this.state = state;
  29. this.start_event = start_event;
  30. this.wait = new ManualResetEvent (false);
  31. }
  32. public int DueTime {
  33. get { return dueTime; }
  34. set { dueTime = value; }
  35. }
  36. public int Period {
  37. get { return period; }
  38. set { period = value == 0 ? Timeout.Infinite : value; }
  39. }
  40. bool WaitForDueTime ()
  41. {
  42. if (dueTime > 0) {
  43. bool signaled;
  44. do {
  45. wait.Reset ();
  46. signaled = wait.WaitOne (dueTime, false);
  47. } while (signaled == true && !disposed && !aborted);
  48. if (!signaled)
  49. callback (state);
  50. if (disposed)
  51. return false;
  52. }
  53. return true;
  54. }
  55. public void Abort ()
  56. {
  57. lock (this) {
  58. aborted = true;
  59. wait.Set ();
  60. }
  61. }
  62. public void Start ()
  63. {
  64. while (start_event.WaitOne ()) {
  65. aborted = false;
  66. if (dueTime == Timeout.Infinite)
  67. continue;
  68. if (!WaitForDueTime ())
  69. return;
  70. if (aborted || (period == Timeout.Infinite))
  71. continue;
  72. bool signaled = false;
  73. while (true) {
  74. if (disposed)
  75. return;
  76. if (aborted)
  77. break;
  78. wait.Reset ();
  79. signaled = wait.WaitOne (period, false);
  80. if (!signaled) {
  81. callback (state);
  82. } else if (!WaitForDueTime ()) {
  83. return;
  84. }
  85. }
  86. }
  87. }
  88. }
  89. Runner runner;
  90. AutoResetEvent start_event;
  91. Thread t;
  92. public Timer (TimerCallback callback, object state, int dueTime, int period)
  93. {
  94. if (dueTime < -1)
  95. throw new ArgumentOutOfRangeException ("dueTime");
  96. if (period < -1)
  97. throw new ArgumentOutOfRangeException ("period");
  98. Init (callback, state, dueTime, period);
  99. }
  100. public Timer (TimerCallback callback, object state, long dueTime, long period)
  101. {
  102. if (dueTime < -1)
  103. throw new ArgumentOutOfRangeException ("dueTime");
  104. if (period < -1)
  105. throw new ArgumentOutOfRangeException ("period");
  106. Init (callback, state, (int) dueTime, (int) period);
  107. }
  108. public Timer (TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
  109. : this (callback, state, Convert.ToInt32(dueTime.TotalMilliseconds), Convert.ToInt32(period.TotalMilliseconds))
  110. {
  111. }
  112. [CLSCompliant(false)]
  113. public Timer (TimerCallback callback, object state, uint dueTime, uint period)
  114. : this (callback, state, (long) dueTime, (long) period)
  115. {
  116. }
  117. void Init (TimerCallback callback, object state, int dueTime, int period)
  118. {
  119. start_event = new AutoResetEvent (false);
  120. runner = new Runner (callback, state, start_event);
  121. Change (dueTime, period);
  122. t = new Thread (new ThreadStart (runner.Start));
  123. t.IsBackground = true;
  124. t.Start ();
  125. }
  126. [MonoTODO("false return?")]
  127. public bool Change (int dueTime, int period)
  128. {
  129. if (dueTime < -1)
  130. throw new ArgumentOutOfRangeException ("dueTime");
  131. if (period < -1)
  132. throw new ArgumentOutOfRangeException ("period");
  133. runner.DueTime = dueTime;
  134. runner.Period = period;
  135. runner.Abort ();
  136. start_event.Set ();
  137. return true;
  138. }
  139. public bool Change (long dueTime, long period)
  140. {
  141. if(dueTime > 4294967294)
  142. throw new NotSupportedException ("Due time too large");
  143. if(period > 4294967294)
  144. throw new NotSupportedException ("Period too large");
  145. return Change ((int) dueTime, (int) period);
  146. }
  147. public bool Change (TimeSpan dueTime, TimeSpan period)
  148. {
  149. return Change (Convert.ToInt32(dueTime.TotalMilliseconds), Convert.ToInt32(period.TotalMilliseconds));
  150. }
  151. [CLSCompliant(false)]
  152. public bool Change (uint dueTime, uint period)
  153. {
  154. if (dueTime > Int32.MaxValue)
  155. throw new NotSupportedException ("Due time too large");
  156. if (period > Int32.MaxValue)
  157. throw new NotSupportedException ("Period too large");
  158. return Change ((int) dueTime, (int) period);
  159. }
  160. public void Dispose ()
  161. {
  162. if (t != null && t.IsAlive) {
  163. t.Abort ();
  164. t = null;
  165. }
  166. runner = null;
  167. GC.SuppressFinalize (this);
  168. }
  169. [MonoTODO("How do we signal the handler?")]
  170. public bool Dispose (WaitHandle notifyObject)
  171. {
  172. Dispose ();
  173. return true; //FIXME
  174. }
  175. ~Timer ()
  176. {
  177. if (t != null && t.IsAlive) {
  178. t.Abort ();
  179. t = null;
  180. }
  181. runner = null;
  182. }
  183. }
  184. }