Merge pull request #2815 from lambdageek/dev/monoerror-mono_compile_method
[mono.git] / mcs / class / Microsoft.Build.Utilities / Microsoft.Build.Utilities / ProcessWrapper.cs
1 // created on 12/18/2004 at 16:28
2 using System;
3 using System.Threading;
4 using System.Diagnostics;
5
6 namespace Microsoft.Build.Utilities
7 {
8         internal delegate void ProcessEventHandler(object sender, string message);
9
10         internal class ProcessWrapper : Process, IProcessAsyncOperation
11         {
12                 ManualResetEvent endEventOut = new ManualResetEvent (false);
13                 ManualResetEvent endEventErr = new ManualResetEvent (false);
14                 ManualResetEvent endEventExit = new ManualResetEvent (false);
15                 bool done;
16                 bool disposed;
17                 object lockObj = new object ();
18
19                 public ProcessWrapper ()
20                 {
21                 }
22
23                 public new void Start ()
24                 {
25                         CheckDisposed ();
26
27                         base.EnableRaisingEvents = true;
28
29                         base.Exited += (s, args) => {
30                                 try {
31                                         endEventExit.Set ();
32                                         WaitHandle.WaitAll (new WaitHandle[] { endEventOut, endEventErr });
33                                 } catch (ObjectDisposedException) {
34                                         return; // we already called Dispose
35                                 }
36
37                                 OnExited (this, EventArgs.Empty);
38                         };
39
40                         base.OutputDataReceived += (s, args) => {
41                                 if (args.Data == null) {
42                                         try {
43                                                 endEventOut.Set ();
44                                         } catch (ObjectDisposedException) {
45                                                 return; // we already called Dispose
46                                         }
47                                 } else {
48                                         ProcessEventHandler handler = OutputStreamChanged;
49                                         if (handler != null)
50                                                 handler (this, args.Data + Environment.NewLine);
51                                 }
52                         };
53
54                         base.ErrorDataReceived += (s, args) => {
55                                 if (args.Data == null) {
56                                         try {
57                                                 endEventErr.Set ();
58                                         } catch (ObjectDisposedException) {
59                                                 return; // we already called Dispose
60                                         }
61                                 } else {
62                                         ProcessEventHandler handler = ErrorStreamChanged;
63                                         if (handler != null)
64                                                 handler (this, args.Data + Environment.NewLine);
65                                 }
66                         };
67
68                         base.Start ();
69
70                         base.BeginOutputReadLine ();
71                         base.BeginErrorReadLine ();
72                 }
73
74                 public void WaitForOutput (int milliseconds)
75                 {
76                         CheckDisposed ();
77                         WaitForExit (milliseconds);
78                         WaitHandle.WaitAll (new WaitHandle[] { endEventOut, endEventErr, endEventExit }, milliseconds);
79                 }
80
81                 public void WaitForOutput ()
82                 {
83                         WaitForOutput (-1);
84                 }
85
86                 protected override void Dispose (bool disposing)
87                 {
88                         if (disposed)
89                                 return;
90
91                         if (!done)
92                                 ((IAsyncOperation)this).Cancel ();
93
94                         // if we race with base.Exited, we don't want to hang on WaitAll (endEventOut, endEventErr)
95                         endEventOut.Set ();
96                         endEventErr.Set ();
97
98                         endEventOut.Close ();
99                         endEventErr.Close ();
100                         endEventExit.Close ();
101
102                         disposed = true;
103
104                         base.Dispose (disposing);
105                 }
106
107                 void CheckDisposed ()
108                 {
109                         if (disposed)
110                                 throw new ObjectDisposedException ("ProcessWrapper");
111                 }
112
113                 int IProcessAsyncOperation.ExitCode {
114                         get { return ExitCode; }
115                 }
116
117                 int IProcessAsyncOperation.ProcessId {
118                         get { return Id; }
119                 }
120
121                 void IAsyncOperation.Cancel ()
122                 {
123                         try {
124                                 if (!done) {
125                                         try {
126                                                 Kill ();
127                                         } catch {
128                                                 // Ignore
129                                         }
130                                         try {
131                                                 base.CancelOutputRead ();
132                                         } catch (InvalidOperationException) {
133                                                 // Ignore: might happen if Start wasn't called
134                                         }
135                                         try {
136                                                 base.CancelErrorRead ();
137                                         } catch (InvalidOperationException) {
138                                                 // Ignore: might happen if Start wasn't called
139                                         }
140                                 }
141                         } catch (Exception ex) {
142                                 //FIXME: Log
143                                 Console.WriteLine (ex.ToString ());
144                                 //LoggingService.LogError (ex.ToString ());
145                         }
146                 }
147
148                 void IAsyncOperation.WaitForCompleted ()
149                 {
150                         WaitForOutput ();
151                 }
152
153                 void OnExited (object sender, EventArgs args)
154                 {
155                         lock (lockObj) {
156                                 done = true;
157                                 try {
158                                         OperationHandler handler = completedEvent;
159                                         if (handler != null)
160                                                 handler (this);
161                                 } catch {
162                                         // Ignore
163                                 }
164                         }
165                 }
166
167                 event OperationHandler IAsyncOperation.Completed {
168                         add {
169                                 bool raiseNow = false;
170                                 lock (lockObj) {
171                                         if (done)
172                                                 raiseNow = true;
173                                         else
174                                                 completedEvent += value;
175                                 }
176                                 if (raiseNow)
177                                         value (this);
178                         }
179                         remove {
180                                 lock (lockObj) {
181                                         completedEvent -= value;
182                                 }
183                         }
184                 }
185
186                 bool IAsyncOperation.Success {
187                         get { return done ? ExitCode == 0 : false; }
188                 }
189
190                 bool IAsyncOperation.SuccessWithWarnings {
191                         get { return false; }
192                 }
193
194                 bool IAsyncOperation.IsCompleted {
195                         get { return done; }
196                 }
197
198                 event OperationHandler completedEvent;
199
200                 public event ProcessEventHandler OutputStreamChanged;
201                 public event ProcessEventHandler ErrorStreamChanged;
202         }
203 }