Timer.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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. else
  54. callback (state);
  55. return true;
  56. }
  57. public void Abort ()
  58. {
  59. lock (this) {
  60. aborted = true;
  61. wait.Set ();
  62. }
  63. }
  64. public void Start ()
  65. {
  66. while (start_event.WaitOne ()) {
  67. aborted = false;
  68. if (dueTime == Timeout.Infinite)
  69. continue;
  70. if (!WaitForDueTime ())
  71. return;
  72. if (aborted || (period == Timeout.Infinite))
  73. continue;
  74. bool signaled = false;
  75. while (true) {
  76. if (disposed)
  77. return;
  78. if (aborted)
  79. break;
  80. wait.Reset ();
  81. signaled = wait.WaitOne (period, false);
  82. if (!signaled) {
  83. callback (state);
  84. } else if (!WaitForDueTime ()) {
  85. return;
  86. }
  87. }
  88. }
  89. }
  90. }
  91. Runner runner;
  92. AutoResetEvent start_event;
  93. Thread t;
  94. public Timer (TimerCallback callback, object state, int dueTime, int period)
  95. {
  96. if (dueTime < -1)
  97. throw new ArgumentOutOfRangeException ("dueTime");
  98. if (period < -1)
  99. throw new ArgumentOutOfRangeException ("period");
  100. Init (callback, state, dueTime, period);
  101. }
  102. public Timer (TimerCallback callback, object state, long dueTime, long period)
  103. {
  104. if (dueTime < -1)
  105. throw new ArgumentOutOfRangeException ("dueTime");
  106. if (period < -1)
  107. throw new ArgumentOutOfRangeException ("period");
  108. Init (callback, state, (int) dueTime, (int) period);
  109. }
  110. public Timer (TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
  111. : this (callback, state, Convert.ToInt32(dueTime.TotalMilliseconds), Convert.ToInt32(period.TotalMilliseconds))
  112. {
  113. }
  114. [CLSCompliant(false)]
  115. public Timer (TimerCallback callback, object state, uint dueTime, uint period)
  116. : this (callback, state, (long) dueTime, (long) period)
  117. {
  118. }
  119. void Init (TimerCallback callback, object state, int dueTime, int period)
  120. {
  121. start_event = new AutoResetEvent (false);
  122. runner = new Runner (callback, state, start_event);
  123. Change (dueTime, period);
  124. t = new Thread (new ThreadStart (runner.Start));
  125. t.IsBackground = true;
  126. t.Start ();
  127. }
  128. [MonoTODO("false return?")]
  129. public bool Change (int dueTime, int period)
  130. {
  131. if (dueTime < -1)
  132. throw new ArgumentOutOfRangeException ("dueTime");
  133. if (period < -1)
  134. throw new ArgumentOutOfRangeException ("period");
  135. runner.DueTime = dueTime;
  136. runner.Period = period;
  137. runner.Abort ();
  138. start_event.Set ();
  139. return true;
  140. }
  141. public bool Change (long dueTime, long period)
  142. {
  143. if(dueTime > 4294967294)
  144. throw new NotSupportedException ("Due time too large");
  145. if(period > 4294967294)
  146. throw new NotSupportedException ("Period too large");
  147. return Change ((int) dueTime, (int) period);
  148. }
  149. public bool Change (TimeSpan dueTime, TimeSpan period)
  150. {
  151. return Change (Convert.ToInt32(dueTime.TotalMilliseconds), Convert.ToInt32(period.TotalMilliseconds));
  152. }
  153. [CLSCompliant(false)]
  154. public bool Change (uint dueTime, uint period)
  155. {
  156. if (dueTime > Int32.MaxValue)
  157. throw new NotSupportedException ("Due time too large");
  158. if (period > Int32.MaxValue)
  159. throw new NotSupportedException ("Period too large");
  160. return Change ((int) dueTime, (int) period);
  161. }
  162. public void Dispose ()
  163. {
  164. if (t != null && t.IsAlive) {
  165. t.Abort ();
  166. t = null;
  167. }
  168. runner.Abort ();
  169. runner = null;
  170. GC.SuppressFinalize (this);
  171. }
  172. [MonoTODO("How do we signal the handler?")]
  173. public bool Dispose (WaitHandle notifyObject)
  174. {
  175. Dispose ();
  176. return true; //FIXME
  177. }
  178. ~Timer ()
  179. {
  180. if (t != null && t.IsAlive)
  181. t.Abort ();
  182. if (runner != null)
  183. runner.Abort ();
  184. }
  185. }
  186. }