Xamarin Public Jenkins (auto-signing) e79aa3c0ed Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
2016-08-03 10:59:49 +00:00

204 lines
4.2 KiB
C#

// created on 12/18/2004 at 16:28
using System;
using System.Threading;
using System.Diagnostics;
namespace Microsoft.Build.Utilities
{
internal delegate void ProcessEventHandler(object sender, string message);
internal class ProcessWrapper : Process, IProcessAsyncOperation
{
ManualResetEvent endEventOut = new ManualResetEvent (false);
ManualResetEvent endEventErr = new ManualResetEvent (false);
ManualResetEvent endEventExit = new ManualResetEvent (false);
bool done;
bool disposed;
object lockObj = new object ();
public ProcessWrapper ()
{
}
public new void Start ()
{
CheckDisposed ();
base.EnableRaisingEvents = true;
base.Exited += (s, args) => {
try {
endEventExit.Set ();
WaitHandle.WaitAll (new WaitHandle[] { endEventOut, endEventErr });
} catch (ObjectDisposedException) {
return; // we already called Dispose
}
OnExited (this, EventArgs.Empty);
};
base.OutputDataReceived += (s, args) => {
if (args.Data == null) {
try {
endEventOut.Set ();
} catch (ObjectDisposedException) {
return; // we already called Dispose
}
} else {
ProcessEventHandler handler = OutputStreamChanged;
if (handler != null)
handler (this, args.Data + Environment.NewLine);
}
};
base.ErrorDataReceived += (s, args) => {
if (args.Data == null) {
try {
endEventErr.Set ();
} catch (ObjectDisposedException) {
return; // we already called Dispose
}
} else {
ProcessEventHandler handler = ErrorStreamChanged;
if (handler != null)
handler (this, args.Data + Environment.NewLine);
}
};
base.Start ();
base.BeginOutputReadLine ();
base.BeginErrorReadLine ();
}
public void WaitForOutput (int milliseconds)
{
CheckDisposed ();
WaitForExit (milliseconds);
WaitHandle.WaitAll (new WaitHandle[] { endEventOut, endEventErr, endEventExit }, milliseconds);
}
public void WaitForOutput ()
{
WaitForOutput (-1);
}
protected override void Dispose (bool disposing)
{
if (disposed)
return;
if (!done)
((IAsyncOperation)this).Cancel ();
// if we race with base.Exited, we don't want to hang on WaitAll (endEventOut, endEventErr)
endEventOut.Set ();
endEventErr.Set ();
endEventOut.Close ();
endEventErr.Close ();
endEventExit.Close ();
disposed = true;
base.Dispose (disposing);
}
void CheckDisposed ()
{
if (disposed)
throw new ObjectDisposedException ("ProcessWrapper");
}
int IProcessAsyncOperation.ExitCode {
get { return ExitCode; }
}
int IProcessAsyncOperation.ProcessId {
get { return Id; }
}
void IAsyncOperation.Cancel ()
{
try {
if (!done) {
try {
Kill ();
} catch {
// Ignore
}
try {
base.CancelOutputRead ();
} catch (InvalidOperationException) {
// Ignore: might happen if Start wasn't called
}
try {
base.CancelErrorRead ();
} catch (InvalidOperationException) {
// Ignore: might happen if Start wasn't called
}
}
} catch (Exception ex) {
//FIXME: Log
Console.WriteLine (ex.ToString ());
//LoggingService.LogError (ex.ToString ());
}
}
void IAsyncOperation.WaitForCompleted ()
{
WaitForOutput ();
}
void OnExited (object sender, EventArgs args)
{
lock (lockObj) {
done = true;
try {
OperationHandler handler = completedEvent;
if (handler != null)
handler (this);
} catch {
// Ignore
}
}
}
event OperationHandler IAsyncOperation.Completed {
add {
bool raiseNow = false;
lock (lockObj) {
if (done)
raiseNow = true;
else
completedEvent += value;
}
if (raiseNow)
value (this);
}
remove {
lock (lockObj) {
completedEvent -= value;
}
}
}
bool IAsyncOperation.Success {
get { return done ? ExitCode == 0 : false; }
}
bool IAsyncOperation.SuccessWithWarnings {
get { return false; }
}
bool IAsyncOperation.IsCompleted {
get { return done; }
}
event OperationHandler completedEvent;
public event ProcessEventHandler OutputStreamChanged;
public event ProcessEventHandler ErrorStreamChanged;
}
}