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