* Timer.cs: The timer thread must be a background thread.
[mono.git] / mcs / class / System / System.Timers / Timer.cs
1 //
2 // System.Timers.Timer
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
6 //
7 // (C) 2002 Ximian, Inc (http://www.ximian.com)
8 //
9 // The docs talk about server timers and such...
10
11 using System;
12 using System.ComponentModel;
13 using System.Threading;
14
15 namespace System.Timers
16 {
17         [DefaultEventAttribute("Elapsed")]
18         [DefaultProperty("Interval")]
19         public class Timer : Component, ISupportInitialize
20         {
21                 bool autoReset;
22                 bool enabled;
23                 double interval;
24                 ISynchronizeInvoke so;
25                 ManualResetEvent wait;
26
27                 [Category("Behavior")]
28                 [TimersDescription("Occurs when the Interval has elapsed.")]
29                 public event ElapsedEventHandler Elapsed;
30
31                 public Timer () : this (100)
32                 {
33                 }
34
35                 public Timer (double interval)
36                 {
37                         autoReset = true;
38                         enabled = false;
39                         Interval = interval;
40                         so = null;
41                         wait = null;
42                 }
43
44
45                 [Category("Behavior")]
46                 [DefaultValue(true)]
47                 [TimersDescription("Indicates whether the timer will be restarted when it is enabled.")]
48                 public bool AutoReset
49                 {
50                         get { return autoReset; }
51                         set { autoReset = value; }
52                 }
53
54                 [Category("Behavior")]
55                 [DefaultValue(false)]
56                 [TimersDescription("Indicates whether the timer is enabled to fire events at a defined interval.")]
57                 public bool Enabled
58                 {
59                         get { return enabled; }
60                         set {
61                                 if (enabled == value)
62                                         return;
63
64                                 enabled = value;
65                                 if (value) {
66                                         Thread t = new Thread (new ThreadStart (StartTimer));
67                                         t.IsBackground = true;
68                                         t.Start ();
69                                 } else {
70                                         StopTimer ();
71                                 }
72                         }
73                 }
74
75                 [Category("Behavior")]
76                 [DefaultValue(100)]
77                 [RecommendedAsConfigurable(true)]
78                 [TimersDescription( "The number of milliseconds between timer events.")]
79                 public double Interval
80                 {
81                         get { return interval; }
82                         set { 
83                                 // The doc says 'less than 0', but 0 also throws the exception
84                                 if (value <= 0)
85                                         throw new ArgumentException ("Invalid value: " + interval, "interval");
86
87                                 interval = value;
88                         }
89                 }
90
91                 public override ISite Site
92                 {
93                         get { return base.Site; }
94                         set { base.Site = value; }
95                 }
96
97                 [DefaultValue(null)]
98                 [TimersDescriptionAttribute("The object used to marshal the event handler calls issued " +
99                                             "when an interval has elapsed.")]
100                 public ISynchronizeInvoke SynchronizingObject
101                 {
102                         get { return so; }
103                         set { so = value; }
104                 }
105
106                 public void BeginInit ()
107                 {
108                         // Nothing to do
109                 }
110
111                 public void Close ()
112                 {
113                         StopTimer ();
114                 }
115
116                 public void EndInit ()
117                 {
118                         // Nothing to do
119                 }
120
121                 public void Start ()
122                 {
123                         Enabled = true;
124                 }
125
126                 public void Stop ()
127                 {
128                         Enabled = false;
129                 }
130
131                 protected override void Dispose (bool disposing)
132                 {
133                         Close ();
134                         base.Dispose (disposing);
135                 }
136
137                 static void Callback (object state)
138                 {
139                         Timer timer = (Timer) state;
140                         if (timer.Elapsed == null)
141                                 return;
142
143                         ElapsedEventArgs arg = new ElapsedEventArgs (DateTime.Now);
144
145                         if (timer.so != null && timer.so.InvokeRequired) {
146                                 timer.so.BeginInvoke (timer.Elapsed, new object [2] {timer, arg});
147                         } else {
148                                 timer.Elapsed (timer, arg);
149                         }
150                 }
151
152                 void StartTimer ()
153                 {
154                         wait = new ManualResetEvent (false);
155
156                         WaitCallback wc = new WaitCallback (Callback);
157                         while (enabled && wait.WaitOne ((int) interval, false) == false) {
158                                 if (autoReset == false)
159                                         enabled = false;
160
161                                 ThreadPool.QueueUserWorkItem (wc, this);
162                         }
163                         
164                         wc = null;
165                         ((IDisposable) wait).Dispose ();
166                         wait = null;
167                 }
168
169                 void StopTimer ()
170                 {
171                         if (wait != null)
172                                 wait.Set ();
173                 }
174         }
175 }
176