[mscorlib][System] Use PlatformNotSupportedException instead of NotSupportedException...
[mono.git] / mcs / class / System / System.Diagnostics / Process.cs
index a3147ffc72781bd4149b53ee4dbc5a7890e4fd3d..b46bc936c1df2df53242753e43da03d6a2b0aa72 100644 (file)
@@ -73,24 +73,20 @@ namespace System.Diagnostics {
                        public IntPtr Password;
                        public bool LoadUserProfile;
                };
-               
+
                IntPtr process_handle;
                int pid;
-               bool enableRaisingEvents;
-               RegisteredWaitHandle exitWaitHandle;
+               int enable_raising_events;
+               Thread background_wait_for_exit_thread;
                ISynchronizeInvoke synchronizingObject;
                EventHandler exited_event;
-               IntPtr stdout_rd;
-               IntPtr stderr_rd;
-
-               object thisLock = new Object ();
 
                /* Private constructor called from other methods */
                private Process(IntPtr handle, int id) {
-                       process_handle=handle;
+                       process_handle = handle;
                        pid=id;
                }
-               
+
                public Process ()
                {
                }
@@ -99,53 +95,19 @@ namespace System.Diagnostics {
                [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
                [MonitoringDescription ("Base process priority.")]
                public int BasePriority {
-                       get {
-                               return(0);
-                       }
-               }
-
-               void StartExitCallbackIfNeeded ()
-               {
-                       lock (thisLock) {
-                               bool start = (exitWaitHandle == null && enableRaisingEvents && exited_event != null);
-                               if (start && process_handle != IntPtr.Zero) {
-                                       WaitOrTimerCallback cb = new WaitOrTimerCallback (CBOnExit);
-                                       ProcessWaitHandle h = new ProcessWaitHandle (process_handle);
-                                       exitWaitHandle = ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
-                               }
-                       }
-               }
-
-               void UnregisterExitCallback ()
-               {
-                       lock (thisLock) {
-                               if (exitWaitHandle != null) {
-                                       exitWaitHandle.Unregister (null);
-                                       exitWaitHandle = null;
-                               }
-                       }
-               }
-
-               bool IsExitCallbackPending ()
-               {
-                       lock (thisLock) {
-                               return exitWaitHandle != null;
-                       }
+                       get { return 0; }
                }
 
                [DefaultValue (false), Browsable (false)]
                [MonitoringDescription ("Check for exiting of the process to raise the apropriate event.")]
                public bool EnableRaisingEvents {
                        get {
-                               return enableRaisingEvents;
+                               return enable_raising_events == 1;
                        }
-                       set { 
-                               bool prev = enableRaisingEvents;
-                               enableRaisingEvents = value;
-                               if (enableRaisingEvents && !prev)
-                                       StartExitCallbackIfNeeded ();
+                       set {
+                               if (value && Interlocked.Exchange (ref enable_raising_events, 1) == 0)
+                                       StartBackgroundWaitForExit ();
                        }
-
                }
 
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
@@ -160,8 +122,7 @@ namespace System.Diagnostics {
 
                                int code = ExitCode_internal (process_handle);
                                if (code == 259)
-                                       throw new InvalidOperationException ("The process must exit before " +
-                                                                       "getting the requested information.");
+                                       throw new InvalidOperationException ("The process must exit before getting the requested information.");
 
                                return code;
                        }
@@ -616,6 +577,7 @@ namespace System.Diagnostics {
                        }
                }
 
+#if MONO_FEATURE_PROCESS_START
                private StreamReader error_stream=null;
                bool error_stream_exposed;
 
@@ -687,6 +649,28 @@ namespace System.Diagnostics {
                                start_info = value;
                        }
                }
+#else
+               [Obsolete ("Process.StandardError is not supported on the current platform.", true)]
+               public StreamReader StandardError {
+                       get { throw new PlatformNotSupportedException ("Process.StandardError is not supported on the current platform."); }
+               }
+
+               [Obsolete ("Process.StandardInput is not supported on the current platform.", true)]
+               public StreamWriter StandardInput {
+                       get { throw new PlatformNotSupportedException ("Process.StandardInput is not supported on the current platform."); }
+               }
+
+               [Obsolete ("Process.StandardOutput is not supported on the current platform.", true)]
+               public StreamReader StandardOutput {
+                       get { throw new PlatformNotSupportedException ("Process.StandardOutput is not supported on the current platform."); }
+               }
+
+               [Obsolete ("Process.StartInfo is not supported on the current platform.", true)]
+               public ProcessStartInfo StartInfo {
+                       get { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
+                       set { throw new PlatformNotSupportedException ("Process.StartInfo is not supported on the current platform."); }
+               }
+#endif // MONO_FEATURE_PROCESS_START
 
                /* Returns the process start time in Windows file
                 * times (ticks from DateTime(1/1/1601 00:00 GMT))
@@ -934,6 +918,7 @@ namespace System.Diagnostics {
                        // the process (currently we have none).
                }
 
+#if MONO_FEATURE_PROCESS_START
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern static bool ShellExecuteEx_internal(ProcessStartInfo startInfo,
                                                                   ref ProcInfo proc_info);
@@ -974,7 +959,7 @@ namespace System.Diagnostics {
 
                        process.process_handle = proc_info.process_handle;
                        process.pid = proc_info.pid;
-                       process.StartExitCallbackIfNeeded ();
+                       process.StartBackgroundWaitForExit ();
                        return(ret);
                }
 
@@ -983,6 +968,8 @@ namespace System.Diagnostics {
                //
                static void CreatePipe (out IntPtr read, out IntPtr write, bool writeDirection)
                {
+                       MonoIOError error;
+
                        //
                        // Creates read/write pipe from parent -> child perspective
                        // a child process uses same descriptors after fork. That's
@@ -1003,25 +990,23 @@ namespace System.Diagnostics {
                        //
                        // It can still be tricky for predefined descriptiors http://unixwiz.net/techtips/remap-pipe-fds.html
                        //
-                       var ret = MonoIO.CreatePipe (out read, out write);
-                       if (!ret)
-                               throw new IOException ("Error creating process pipe");
+                       if (!MonoIO.CreatePipe (out read, out write, out error))
+                               throw MonoIO.GetException (error);
 
                        if (IsWindows) {
                                const int DUPLICATE_SAME_ACCESS = 0x00000002;
                                var tmp = writeDirection ? write : read;
 
-                               ret = MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp,
-                                       Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS);
-                               if (!ret)
-                                       return;
+                               if (!MonoIO.DuplicateHandle (Process.GetCurrentProcess ().Handle, tmp, Process.GetCurrentProcess ().Handle, out tmp, 0, 0, DUPLICATE_SAME_ACCESS, out error))
+                                       throw MonoIO.GetException (error);
 
-                               MonoIOError error;
                                if (writeDirection) {
-                                       MonoIO.Close (write, out error);
+                                       if (!MonoIO.Close (write, out error))
+                                               throw MonoIO.GetException (error);
                                        write = tmp;
                                } else {
-                                       MonoIO.Close (read, out error);
+                                       if (!MonoIO.Close (read, out error))
+                                               throw MonoIO.GetException (error);
                                        read = tmp;
                                }
                        }
@@ -1056,17 +1041,15 @@ namespace System.Diagnostics {
 
                                if (startInfo.RedirectStandardOutput) {
                                        CreatePipe (out stdout_read, out stdout_write, false);
-                                       process.stdout_rd = stdout_read;
                                } else {
-                                       process.stdout_rd = IntPtr.Zero;
+                                       stdout_read = IntPtr.Zero;
                                        stdout_write = MonoIO.ConsoleOutput;
                                }
 
                                if (startInfo.RedirectStandardError) {
                                        CreatePipe (out stderr_read, out stderr_write, false);
-                                       process.stderr_rd  = stderr_read;
                                } else {
-                                       process.stderr_rd = IntPtr.Zero;
+                                       stderr_read = IntPtr.Zero;
                                        stderr_write = MonoIO.ConsoleError;
                                }
 
@@ -1129,7 +1112,7 @@ namespace System.Diagnostics {
 #else
                                var stdinEncoding = Console.InputEncoding;
 #endif
-                               process.input_stream = new StreamWriter (new FileStream (new SafeFileHandle (stdin_write, false), FileAccess.Write, 8192, false), stdinEncoding) {
+                               process.input_stream = new StreamWriter (new FileStream (stdin_write, FileAccess.Write, true, 8192), stdinEncoding) {
                                        AutoFlush = true
                                };
                        }
@@ -1139,7 +1122,7 @@ namespace System.Diagnostics {
 
                                Encoding stdoutEncoding = startInfo.StandardOutputEncoding ?? Console.Out.Encoding;
 
-                               process.output_stream = new StreamReader (new FileStream (new SafeFileHandle (stdout_read, false), FileAccess.Read, 8192, false), stdoutEncoding, true, 8192);
+                               process.output_stream = new StreamReader (new FileStream (stdout_read, FileAccess.Read, true, 8192), stdoutEncoding, true);
                        }
 
                        if (startInfo.RedirectStandardError) {
@@ -1147,10 +1130,10 @@ namespace System.Diagnostics {
 
                                Encoding stderrEncoding = startInfo.StandardErrorEncoding ?? Console.Out.Encoding;
 
-                               process.error_stream = new StreamReader (new FileStream (new SafeFileHandle (stderr_read, false), FileAccess.Read, 8192, false), stderrEncoding, true, 8192);
+                               process.error_stream = new StreamReader (new FileStream (stderr_read, FileAccess.Read, true, 8192), stderrEncoding, true);
                        }
 
-                       process.StartExitCallbackIfNeeded ();
+                       process.StartBackgroundWaitForExit ();
 
                        return true;
                }
@@ -1232,6 +1215,43 @@ namespace System.Diagnostics {
                        psi.UseShellExecute = false;
                        return Start(psi);
                }
+#else
+               [Obsolete ("Process.Start is not supported on the current platform.", true)]
+               public bool Start ()
+               {
+                       throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.Start is not supported on the current platform.", true)]
+               public static Process Start (ProcessStartInfo startInfo)
+               {
+                       throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.Start is not supported on the current platform.", true)]
+               public static Process Start (string fileName)
+               {
+                       throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.Start is not supported on the current platform.", true)]
+               public static Process Start(string fileName, string arguments)
+               {
+                       throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.Start is not supported on the current platform.", true)]
+               public static Process Start(string fileName, string username, SecureString password, string domain)
+               {
+                       throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.Start is not supported on the current platform.", true)]
+               public static Process Start(string fileName, string arguments, string username, SecureString password, string domain)
+               {
+                       throw new PlatformNotSupportedException ("Process.Start is not supported on the current platform.");
+               }
+#endif // MONO_FEATURE_PROCESS_START
 
                public override string ToString()
                {
@@ -1257,38 +1277,20 @@ namespace System.Diagnostics {
                        if (process_handle == IntPtr.Zero)
                                throw new InvalidOperationException ("No process is associated with this object.");
 
+                       if (!WaitForExit_internal (process_handle, ms))
+                               return false;
 
-                       DateTime start = DateTime.UtcNow;
-                       if (async_output != null && !async_output.IsCompleted) {
-                               if (false == async_output.WaitHandle.WaitOne (ms, false))
-                                       return false; // Timed out
-
-                               if (ms >= 0) {
-                                       DateTime now = DateTime.UtcNow;
-                                       ms -= (int) (now - start).TotalMilliseconds;
-                                       if (ms <= 0)
-                                               return false;
-                                       start = now;
-                               }
-                       }
-
-                       if (async_error != null && !async_error.IsCompleted) {
-                               if (false == async_error.WaitHandle.WaitOne (ms, false))
-                                       return false; // Timed out
-
-                               if (ms >= 0) {
-                                       ms -= (int) (DateTime.UtcNow - start).TotalMilliseconds;
-                                       if (ms <= 0)
-                                               return false;
-                               }
-                       }
+#if MONO_FEATURE_PROCESS_START
+                       if (async_output != null && !async_output.IsCompleted)
+                               async_output.AsyncWaitHandle.WaitOne ();
 
-                       bool exited = WaitForExit_internal (process_handle, ms);
+                       if (async_error != null && !async_error.IsCompleted)
+                               async_error.AsyncWaitHandle.WaitOne ();
+#endif // MONO_FEATURE_PROCESS_START
 
-                       if (exited)
-                               OnExited ();
+                       OnExited ();
 
-                       return exited;
+                       return true;
                }
 
                /* Waits up to ms milliseconds for process 'handle' to 
@@ -1326,16 +1328,19 @@ namespace System.Diagnostics {
 
                void OnOutputDataReceived (string str)
                {
-                       if (OutputDataReceived != null)
-                               OutputDataReceived (this, new DataReceivedEventArgs (str));
+                       DataReceivedEventHandler cb = OutputDataReceived;
+                       if (cb != null)
+                               cb (this, new DataReceivedEventArgs (str));
                }
 
                void OnErrorDataReceived (string str)
                {
-                       if (ErrorDataReceived != null)
-                               ErrorDataReceived (this, new DataReceivedEventArgs (str));
+                       DataReceivedEventHandler cb = ErrorDataReceived;
+                       if (cb != null)
+                               cb (this, new DataReceivedEventArgs (str));
                }
 
+#if MONO_FEATURE_PROCESS_START
                [Flags]
                enum AsyncModes {
                        NoneYet = 0,
@@ -1346,159 +1351,112 @@ namespace System.Diagnostics {
                }
 
                [StructLayout (LayoutKind.Sequential)]
-               sealed class ProcessAsyncReader : IThreadPoolWorkItem
+               sealed class ProcessAsyncReader : IOAsyncResult
                {
-                       /*
-                          The following fields match those of SocketAsyncResult.
-                          This is so that changes needed in the runtime to handle
-                          asynchronous reads are trivial
-                          Keep this in sync with SocketAsyncResult in 
-                          ./System.Net.Sockets/Socket.cs and MonoSocketAsyncResult
-                          in metadata/socket-io.h.
-                       */
-                       /* DON'T shuffle fields around. DON'T remove fields */
-                       public object Sock;
-                       public IntPtr handle;
-                       public object state;
-                       public AsyncCallback callback;
-                       public ManualResetEvent wait_handle;
-
-                       public Exception delayedException;
-
-                       public object EndPoint;
-                       byte [] buffer = new byte [4196];
-                       public int Offset;
-                       public int Size;
-                       public int SockFlags;
-
-                       public object AcceptSocket;
-                       public object[] Addresses;
-                       public int port;
-                       public object Buffers;          // Reserve this slot in older profiles
-                       public bool ReuseSocket;        // Disconnect
-                       public object acc_socket;
-                       public int total;
-                       public bool completed_sync;
-                       bool completed;
-                       bool err_out; // true -> stdout, false -> stderr
-                       internal int error;
-                       public int operation = 8; // MAGIC NUMBER: see Socket.cs:AsyncOperation
-                       public AsyncResult async_result;
-                       public int EndCalled;
-
-                       // These fields are not in SocketAsyncResult
                        Process process;
+                       IntPtr handle;
                        Stream stream;
+                       bool err_out;
+
                        StringBuilder sb = new StringBuilder ();
-                       public AsyncReadHandler ReadHandler;
+                       byte[] buffer = new byte [4096];
+
+                       const int ERROR_INVALID_HANDLE = 6;
 
-                       public ProcessAsyncReader (Process process, IntPtr handle, bool err_out)
+                       public ProcessAsyncReader (Process process, FileStream stream, bool err_out)
+                               : base (null, null)
                        {
                                this.process = process;
-                               this.handle = handle;
-                               stream = new FileStream (handle, FileAccess.Read, false);
-                               this.ReadHandler = new AsyncReadHandler (AddInput);
+                               this.handle = stream.SafeFileHandle.DangerousGetHandle ();
+                               this.stream = stream;
                                this.err_out = err_out;
                        }
 
-                       public void AddInput ()
+                       public void BeginReadLine ()
                        {
-                               lock (this) {
-                                       int nread = stream.Read (buffer, 0, buffer.Length);
-                                       if (nread == 0) {
-                                               completed = true;
-                                               if (wait_handle != null)
-                                                       wait_handle.Set ();
-                                               FlushLast ();
-                                               return;
-                                       }
+                               IOSelector.Add (this.handle, new IOSelectorJob (IOOperation.Read, _ => Read (), null));
+                       }
 
-                                       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]);
-                                               }
-                                       }
+                       void Read ()
+                       {
+                               int nread = 0;
 
-                                       Flush (false);
-                                       ReadHandler.BeginInvoke (null, this);
+                               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;
                                }
-                       }
 
-                       void FlushLast ()
-                       {
-                               Flush (true);
-                               if (err_out) {
-                                       process.OnOutputDataReceived (null);
-                               } else {
-                                       process.OnErrorDataReceived (null);
+                               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))
+                               if (sb.Length == 0 || (err_out && process.output_canceled) || (!err_out && process.error_canceled))
                                        return;
 
-                               string total = sb.ToString ();
+                               string[] strs = sb.ToString ().Split ('\n');
+
                                sb.Length = 0;
-                               string [] strs = total.Split ('\n');
-                               int len = strs.Length;
-                               if (len == 0)
+
+                               if (strs.Length == 0)
                                        return;
 
-                               for (int i = 0; i < len - 1; i++) {
+                               for (int i = 0; i < strs.Length - 1; i++) {
                                        if (err_out)
                                                process.OnOutputDataReceived (strs [i]);
                                        else
                                                process.OnErrorDataReceived (strs [i]);
                                }
 
-                               string end = strs [len - 1];
-                               if (last || (len == 1 && end == "")) {
-                                       if (err_out) {
+                               string end = strs [strs.Length - 1];
+                               if (last || (strs.Length == 1 && end == "")) {
+                                       if (err_out)
                                                process.OnOutputDataReceived (end);
-                                       } else {
+                                       else
                                                process.OnErrorDataReceived (end);
-                                       }
                                } else {
                                        sb.Append (end);
                                }
                        }
 
-                       public bool IsCompleted {
-                               get { return completed; }
-                       }
-
-                       public WaitHandle WaitHandle {
-                               get {
-                                       lock (this) {
-                                               if (wait_handle == null)
-                                                       wait_handle = new ManualResetEvent (completed);
-                                               return wait_handle;
-                                       }
-                               }
-                       }
-
-                       public void Close () {
-                               RemoveFromIOThreadPool (handle);
-                               stream.Close ();
-                       }
-
-                       [MethodImplAttribute(MethodImplOptions.InternalCall)]
-                       extern static void RemoveFromIOThreadPool (IntPtr handle);
-
-                       void IThreadPoolWorkItem.ExecuteWorkItem()
+                       public void Close ()
                        {
-                               async_result.Invoke ();
+                               IOSelector.Remove (handle);
                        }
 
-                       void IThreadPoolWorkItem.MarkAborted(ThreadAbortException tae)
+                       internal override void CompleteDisposed ()
                        {
+                               throw new NotSupportedException ();
                        }
                }
 
@@ -1507,7 +1465,6 @@ namespace System.Diagnostics {
                bool error_canceled;
                ProcessAsyncReader async_output;
                ProcessAsyncReader async_error;
-               delegate void AsyncReadHandler ();
 
                [ComVisibleAttribute(false)] 
                public void BeginOutputReadLine ()
@@ -1521,8 +1478,8 @@ namespace System.Diagnostics {
                        async_mode |= AsyncModes.AsyncOutput;
                        output_canceled = false;
                        if (async_output == null) {
-                               async_output = new ProcessAsyncReader (this, stdout_rd, true);
-                               async_output.ReadHandler.BeginInvoke (null, async_output);
+                               async_output = new ProcessAsyncReader (this, (FileStream) output_stream.BaseStream, true);
+                               async_output.BeginReadLine ();
                        }
                }
 
@@ -1553,8 +1510,8 @@ namespace System.Diagnostics {
                        async_mode |= AsyncModes.AsyncError;
                        error_canceled = false;
                        if (async_error == null) {
-                               async_error = new ProcessAsyncReader (this, stderr_rd, false);
-                               async_error.ReadHandler.BeginInvoke (null, async_error);
+                               async_error = new ProcessAsyncReader (this, (FileStream) error_stream.BaseStream, false);
+                               async_error.BeginReadLine ();
                        }
                }
 
@@ -1572,6 +1529,31 @@ namespace System.Diagnostics {
 
                        error_canceled = true;
                }
+#else
+               [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
+               public void BeginOutputReadLine ()
+               {
+                       throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
+               public void CancelOutputRead ()
+               {
+                       throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
+               public void BeginErrorReadLine ()
+               {
+                       throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
+               }
+
+               [Obsolete ("Process.BeginOutputReadLine is not supported on the current platform.", true)]
+               public void CancelErrorRead ()
+               {
+                       throw new PlatformNotSupportedException ("Process.BeginOutputReadLine is not supported on the current platform.");
+               }
+#endif // MONO_FEATURE_PROCESS_START
 
                [Category ("Behavior")]
                [MonitoringDescription ("Raised when this process exits.")]
@@ -1580,64 +1562,62 @@ namespace System.Diagnostics {
                                if (process_handle != IntPtr.Zero && HasExited) {
                                        value.BeginInvoke (null, null, null, null);
                                } else {
-                                       exited_event = (EventHandler) Delegate.Combine (exited_event, value);
+                                       exited_event += value;
                                        if (exited_event != null)
-                                               StartExitCallbackIfNeeded ();
+                                               StartBackgroundWaitForExit ();
                                }
                        }
                        remove {
-                               exited_event = (EventHandler) Delegate.Remove (exited_event, value);
+                               exited_event -= value;
                        }
                }
 
                // Closes the system process handle
                [MethodImplAttribute(MethodImplOptions.InternalCall)]
                private extern void Process_free_internal(IntPtr handle);
-               
-               private bool disposed = false;
-               
+
+               int disposed;
+
                protected override void Dispose(bool disposing) {
                        // Check to see if Dispose has already been called.
-                       if(this.disposed == false) {
-                               this.disposed=true;
-                               // If this is a call to Dispose,
-                               // dispose all managed resources.
-                               if(disposing) {
-                                       // Do stuff here
-                                       lock (thisLock) {
-                                               /* These have open FileStreams on the pipes we are about to close */
-                                               if (async_output != null)
-                                                       async_output.Close ();
-                                               if (async_error != null)
-                                                       async_error.Close ();
-
-                                               if (input_stream != null) {
-                                                       if (!input_stream_exposed)
-                                                               input_stream.Close ();
-                                                       input_stream = null;
-                                               }
-                                               if (output_stream != null) {
-                                                       if (!output_stream_exposed)
-                                                               output_stream.Close ();
-                                                       output_stream = null;
-                                               }
-                                               if (error_stream != null) {
-                                                       if (!error_stream_exposed)
-                                                               error_stream.Close ();
-                                                       error_stream = null;
-                                               }
-                                       }
-                               }
-                               
-                               // Release unmanaged resources
+                       if (disposed != 0 || Interlocked.CompareExchange (ref disposed, 1, 0) != 0)
+                               return;
 
-                               lock (thisLock) {
-                                       if(process_handle!=IntPtr.Zero) {
-                                               Process_free_internal(process_handle);
-                                               process_handle=IntPtr.Zero;
-                                       }
+                       // If this is a call to Dispose,
+                       // dispose all managed resources.
+                       if (disposing) {
+#if MONO_FEATURE_PROCESS_START
+                               /* These have open FileStreams on the pipes we are about to close */
+                               if (async_output != null)
+                                       async_output.Close ();
+                               if (async_error != null)
+                                       async_error.Close ();
+
+                               if (input_stream != null) {
+                                       if (!input_stream_exposed)
+                                               input_stream.Close ();
+                                       input_stream = null;
+                               }
+                               if (output_stream != null) {
+                                       if (!output_stream_exposed)
+                                               output_stream.Close ();
+                                       output_stream = null;
                                }
+                               if (error_stream != null) {
+                                       if (!error_stream_exposed)
+                                               error_stream.Close ();
+                                       error_stream = null;
+                               }
+#endif // MONO_FEATURE_PROCESS_START
+                       }
+
+                       // Release unmanaged resources
+
+                       if (process_handle!=IntPtr.Zero) {
+                               Process_free_internal (process_handle);
+                               process_handle = IntPtr.Zero;
                        }
+
                        base.Dispose (disposing);
                }
 
@@ -1646,45 +1626,27 @@ namespace System.Diagnostics {
                        Dispose (false);
                }
 
-               static void CBOnExit (object state, bool unused)
-               {
-                       Process p = (Process) state;
-
-                       if (!p.IsExitCallbackPending ())
-                               return;
-
-                       if (!p.HasExited) {
-                               p.UnregisterExitCallback ();
-                               p.StartExitCallbackIfNeeded ();
-                               return;
-                       }
-
-                       p.OnExited ();
-               }
-
                int on_exited_called = 0;
 
-               protected void OnExited() 
+               protected void OnExited()
                {
-                       if (exited_event == null)
-                               return;
-
                        if (on_exited_called != 0 || Interlocked.CompareExchange (ref on_exited_called, 1, 0) != 0)
                                return;
 
-                       UnregisterExitCallback ();
+                       var cb = exited_event;
+                       if (cb == null)
+                               return;
 
-                       if (synchronizingObject == null) {
-                               foreach (EventHandler d in exited_event.GetInvocationList ()) {
+                       if (synchronizingObject != null) {
+                               synchronizingObject.BeginInvoke (cb, new object [] { this, EventArgs.Empty });
+                       } else {
+                               foreach (EventHandler d in cb.GetInvocationList ()) {
                                        try {
                                                d (this, EventArgs.Empty);
-                                       } catch {}
+                                       } catch {
+                                       }
                                }
-                               return;
                        }
-                       
-                       object [] args = new object [] {this, EventArgs.Empty};
-                       synchronizingObject.BeginInvoke (exited_event, args);
                }
 
                static bool IsWindows
@@ -1702,11 +1664,28 @@ namespace System.Diagnostics {
                        }
                }
 
+               void StartBackgroundWaitForExit ()
+               {
+                       if (enable_raising_events == 0)
+                               return;
+                       if (exited_event == null)
+                               return;
+                       if (process_handle == IntPtr.Zero)
+                               return;
+                       if (background_wait_for_exit_thread != null)
+                               return;
+
+                       Thread t = new Thread (_ => WaitForExit ()) { IsBackground = true };
+
+                       if (Interlocked.CompareExchange (ref background_wait_for_exit_thread, t, null) == null)
+                               t.Start ();
+               }
+
                class ProcessWaitHandle : WaitHandle
                {
                        [MethodImplAttribute (MethodImplOptions.InternalCall)]
                        private extern static IntPtr ProcessHandle_duplicate (IntPtr handle);
-                       
+
                        public ProcessWaitHandle (IntPtr handle)
                        {
                                // Need to keep a reference to this handle,