Merge pull request #2624 from ludovic-henry/monoerror-appdomain
[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                 object lockObj = new object ();
17
18                 public ProcessWrapper ()
19                 {
20                 }
21
22                 public new void Start ()
23                 {
24                         CheckDisposed ();
25
26                         base.EnableRaisingEvents = true;
27
28                         base.Exited += (s, args) => {
29                                 endEventExit.Set ();
30
31                                 WaitHandle.WaitAll (new WaitHandle[] { endEventOut, endEventErr });
32                                 OnExited (this, EventArgs.Empty);
33                         };
34
35                         base.OutputDataReceived += (s, args) => {
36                                 if (args.Data == null) {
37                                         endEventOut.Set ();
38                                 } else {
39                                         ProcessEventHandler handler = OutputStreamChanged;
40                                         if (handler != null)
41                                                 handler (this, args.Data);
42                                 }
43                         };
44
45                         base.ErrorDataReceived += (s, args) => {
46                                 if (args.Data == null) {
47                                         endEventErr.Set ();
48                                 } else {
49                                         ProcessEventHandler handler = ErrorStreamChanged;
50                                         if (handler != null)
51                                                 handler (this, args.Data);
52                                 }
53                         };
54
55                         base.Start ();
56
57                         base.BeginOutputReadLine ();
58                         base.BeginErrorReadLine ();
59                 }
60
61                 public void WaitForOutput (int milliseconds)
62                 {
63                         CheckDisposed ();
64                         WaitHandle.WaitAll (new WaitHandle[] { endEventOut, endEventErr, endEventExit }, milliseconds);
65                 }
66
67                 public void WaitForOutput ()
68                 {
69                         WaitForOutput (-1);
70                 }
71
72                 protected override void Dispose (bool disposing)
73                 {
74                         lock (lockObj) {
75                                 if (endEventOut == null)
76                                         return;
77                         }
78
79                         if (!done)
80                                 ((IAsyncOperation)this).Cancel ();
81
82                         endEventOut.Close ();
83                         endEventErr.Close ();
84                         endEventExit.Close ();
85
86                         base.Dispose (disposing);
87                 }
88
89                 void CheckDisposed ()
90                 {
91                         if (endEventOut == null)
92                                 throw new ObjectDisposedException ("ProcessWrapper");
93                 }
94
95                 int IProcessAsyncOperation.ExitCode {
96                         get { return ExitCode; }
97                 }
98
99                 int IProcessAsyncOperation.ProcessId {
100                         get { return Id; }
101                 }
102
103                 void IAsyncOperation.Cancel ()
104                 {
105                         try {
106                                 if (!done) {
107                                         try {
108                                                 Kill ();
109                                         } catch {
110                                                 // Ignore
111                                         }
112                                         try {
113                                                 base.CancelOutputRead ();
114                                         } catch (InvalidOperationException) {
115                                                 // Ignore: might happen if Start wasn't called
116                                         }
117                                         try {
118                                                 base.CancelErrorRead ();
119                                         } catch (InvalidOperationException) {
120                                                 // Ignore: might happen if Start wasn't called
121                                         }
122                                 }
123                         } catch (Exception ex) {
124                                 //FIXME: Log
125                                 Console.WriteLine (ex.ToString ());
126                                 //LoggingService.LogError (ex.ToString ());
127                         }
128                 }
129
130                 void IAsyncOperation.WaitForCompleted ()
131                 {
132                         WaitForOutput ();
133                 }
134
135                 void OnExited (object sender, EventArgs args)
136                 {
137                         lock (lockObj) {
138                                 done = true;
139                                 try {
140                                         OperationHandler handler = completedEvent;
141                                         if (handler != null)
142                                                 handler (this);
143                                 } catch {
144                                         // Ignore
145                                 }
146                         }
147                 }
148
149                 event OperationHandler IAsyncOperation.Completed {
150                         add {
151                                 bool raiseNow = false;
152                                 lock (lockObj) {
153                                         if (done)
154                                                 raiseNow = true;
155                                         else
156                                                 completedEvent += value;
157                                 }
158                                 if (raiseNow)
159                                         value (this);
160                         }
161                         remove {
162                                 lock (lockObj) {
163                                         completedEvent -= value;
164                                 }
165                         }
166                 }
167
168                 bool IAsyncOperation.Success {
169                         get { return done ? ExitCode == 0 : false; }
170                 }
171
172                 bool IAsyncOperation.SuccessWithWarnings {
173                         get { return false; }
174                 }
175
176                 bool IAsyncOperation.IsCompleted {
177                         get { return done; }
178                 }
179
180                 event OperationHandler completedEvent;
181
182                 public event ProcessEventHandler OutputStreamChanged;
183                 public event ProcessEventHandler ErrorStreamChanged;
184         }
185 }