Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Henry <ludovic@xamarin.com>2015-12-17 20:10:35 +0300
committerLudovic Henry <ludovic@xamarin.com>2016-01-14 19:03:01 +0300
commit75ea2386a1f06d304bb3dc2aff854f21ecd8a41e (patch)
tree234a284d4b37ddda0c60920647d36b71a804ba55 /mcs/class/System/System.Diagnostics
parent3a9fa982ea23afcf798fb6ba4ce6abbf7b0876e4 (diff)
[Process] Use ReferenceSource process async output/error reader
By using the referencesource one, we remove a buggy part of the Process class. It will now simply use Stream.{Begin/End}Read, and not a custom implementation that introduces its own bugs.
Diffstat (limited to 'mcs/class/System/System.Diagnostics')
-rw-r--r--mcs/class/System/System.Diagnostics/Process.cs200
1 files changed, 56 insertions, 144 deletions
diff --git a/mcs/class/System/System.Diagnostics/Process.cs b/mcs/class/System/System.Diagnostics/Process.cs
index 8c6fa0dcf4f..31cc1819123 100644
--- a/mcs/class/System/System.Diagnostics/Process.cs
+++ b/mcs/class/System/System.Diagnostics/Process.cs
@@ -1281,11 +1281,11 @@ namespace System.Diagnostics {
return false;
#if MONO_FEATURE_PROCESS_START
- if (async_output != null && !async_output.IsCompleted)
- async_output.AsyncWaitHandle.WaitOne ();
+ if (async_output != null)
+ async_output.WaitUtilEOF ();
- if (async_error != null && !async_error.IsCompleted)
- async_error.AsyncWaitHandle.WaitOne ();
+ if (async_error != null)
+ async_error.WaitUtilEOF ();
#endif // MONO_FEATURE_PROCESS_START
if (EnableRaisingEvents)
@@ -1327,20 +1327,6 @@ namespace System.Diagnostics {
[MonitoringDescription ("Raised when it receives error data")]
public event DataReceivedEventHandler ErrorDataReceived;
- void OnOutputDataReceived (string str)
- {
- DataReceivedEventHandler cb = OutputDataReceived;
- if (cb != null)
- cb (this, new DataReceivedEventArgs (str));
- }
-
- void OnErrorDataReceived (string str)
- {
- DataReceivedEventHandler cb = ErrorDataReceived;
- if (cb != null)
- cb (this, new DataReceivedEventArgs (str));
- }
-
#if MONO_FEATURE_PROCESS_START
[Flags]
enum AsyncModes {
@@ -1351,121 +1337,9 @@ namespace System.Diagnostics {
AsyncError = 1 << 3
}
- [StructLayout (LayoutKind.Sequential)]
- sealed class ProcessAsyncReader : IOAsyncResult
- {
- Process process;
- IntPtr handle;
- Stream stream;
- bool err_out;
-
- StringBuilder sb = new StringBuilder ();
- byte[] buffer = new byte [4096];
-
- const int ERROR_INVALID_HANDLE = 6;
-
- public ProcessAsyncReader (Process process, FileStream stream, bool err_out)
- : base (null, null)
- {
- this.process = process;
- this.handle = stream.SafeFileHandle.DangerousGetHandle ();
- this.stream = stream;
- this.err_out = err_out;
- }
-
- public void BeginReadLine ()
- {
- IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
- }
-
- void Read ()
- {
- int nread = 0;
-
- try {
- nread = stream.Read (buffer, 0, buffer.Length);
- } catch (ObjectDisposedException) {
- } catch (IOException ex) {
- if (ex.HResult != (unchecked((int) 0x80070000) | (int) ERROR_INVALID_HANDLE))
- throw;
- } catch (NotSupportedException) {
- if (stream.CanRead)
- throw;
- }
-
- if (nread == 0) {
- Flush (true);
-
- if (err_out)
- process.OnOutputDataReceived (null);
- else
- process.OnErrorDataReceived (null);
-
- IsCompleted = true;
-
- return;
- }
-
- try {
- sb.Append (Encoding.Default.GetString (buffer, 0, nread));
- } catch {
- // Just in case the encoding fails...
- for (int i = 0; i < nread; i++) {
- sb.Append ((char) buffer [i]);
- }
- }
-
- Flush (false);
-
- IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
- }
-
- void Flush (bool last)
- {
- if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
- return;
-
- string[] strs = sb.ToString ().Split ('\n');
-
- sb.Length = 0;
-
- if (strs.Length == 0)
- return;
-
- for (int i = 0; i < strs.Length - 1; i++) {
- if (err_out)
- process.OnOutputDataReceived (strs [i]);
- else
- process.OnErrorDataReceived (strs [i]);
- }
-
- string end = strs [strs.Length - 1];
- if (last || (strs.Length == 1 && end == "")) {
- if (err_out)
- process.OnOutputDataReceived (end);
- else
- process.OnErrorDataReceived (end);
- } else {
- sb.Append (end);
- }
- }
-
- public void Close ()
- {
- IOSelector.Remove (handle);
- }
-
- internal override void CompleteDisposed ()
- {
- throw new NotSupportedException ();
- }
- }
-
AsyncModes async_mode;
- bool output_canceled;
- bool error_canceled;
- ProcessAsyncReader async_output;
- ProcessAsyncReader async_error;
+ AsyncStreamReader async_output;
+ AsyncStreamReader async_error;
[ComVisibleAttribute(false)]
public void BeginOutputReadLine ()
@@ -1477,10 +1351,22 @@ namespace System.Diagnostics {
throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
async_mode |= AsyncModes.AsyncOutput;
- output_canceled = false;
- if (async_output == null) {
- async_output = new ProcessAsyncReader (this, (FileStream) output_stream.BaseStream, true);
- async_output.BeginReadLine ();
+
+ if (async_output == null)
+ async_output = new AsyncStreamReader (this, output_stream.BaseStream, new UserCallBack(this.OutputReadNotifyUser), output_stream.CurrentEncoding);
+
+ async_output.BeginReadLine ();
+ }
+
+ void OutputReadNotifyUser (String data)
+ {
+ // To avoid ---- between remove handler and raising the event
+ DataReceivedEventHandler outputDataReceived = OutputDataReceived;
+ if (outputDataReceived != null) {
+ if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
+ SynchronizingObject.Invoke (outputDataReceived, new object[] { this, new DataReceivedEventArgs (data) });
+ else
+ outputDataReceived (this, new DataReceivedEventArgs (data)); // Call back to user informing data is available.
}
}
@@ -1496,7 +1382,9 @@ namespace System.Diagnostics {
if (async_output == null)
throw new InvalidOperationException ("No async operation in progress.");
- output_canceled = true;
+ async_output.CancelOperation ();
+
+ async_mode &= ~AsyncModes.AsyncOutput;
}
[ComVisibleAttribute(false)]
@@ -1509,10 +1397,22 @@ namespace System.Diagnostics {
throw new InvalidOperationException ("Cannot mix asynchronous and synchonous reads.");
async_mode |= AsyncModes.AsyncError;
- error_canceled = false;
- if (async_error == null) {
- async_error = new ProcessAsyncReader (this, (FileStream) error_stream.BaseStream, false);
- async_error.BeginReadLine ();
+
+ if (async_error == null)
+ async_error = new AsyncStreamReader (this, error_stream.BaseStream, new UserCallBack(this.ErrorReadNotifyUser), error_stream.CurrentEncoding);
+
+ async_error.BeginReadLine ();
+ }
+
+ void ErrorReadNotifyUser (String data)
+ {
+ // To avoid ---- between remove handler and raising the event
+ DataReceivedEventHandler errorDataReceived = ErrorDataReceived;
+ if (errorDataReceived != null) {
+ if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
+ SynchronizingObject.Invoke (errorDataReceived, new object[] { this, new DataReceivedEventArgs (data) });
+ else
+ errorDataReceived (this, new DataReceivedEventArgs (data)); // Call back to user informing data is available.
}
}
@@ -1528,7 +1428,9 @@ namespace System.Diagnostics {
if (async_error == null)
throw new InvalidOperationException ("No async operation in progress.");
- error_canceled = true;
+ async_error.CancelOperation ();
+
+ async_mode &= ~AsyncModes.AsyncError;
}
#else
[Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
@@ -1667,16 +1569,26 @@ namespace System.Diagnostics {
void StartBackgroundWaitForExit ()
{
+ IntPtr handle = process_handle;
+
if (enable_raising_events == 0)
return;
if (exited_event == null)
return;
- if (process_handle == IntPtr.Zero)
+ if (handle == IntPtr.Zero)
return;
if (background_wait_for_exit_thread != null)
return;
- Thread t = new Thread (_ => WaitForExit ()) { IsBackground = true };
+ Thread t = new Thread (_ => {
+ if (!WaitForExit_internal (handle, -1))
+ return;
+
+ if (EnableRaisingEvents)
+ OnExited ();
+ });
+
+ t.IsBackground = true;
if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
t.Start ();