IntPtr process_handle;
int pid;
bool enableRaisingEvents;
- bool already_waiting;
+ RegisteredWaitHandle exitWaitHandle;
ISynchronizeInvoke synchronizingObject;
EventHandler exited_event;
IntPtr stdout_rd;
void StartExitCallbackIfNeeded ()
{
- bool start = (!already_waiting && enableRaisingEvents && exited_event != null);
+ 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);
- ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
- already_waiting = true;
+ exitWaitHandle = ThreadPool.RegisterWaitForSingleObject (h, cb, this, -1, true);
}
}
return false;
}
}
- return WaitForExit_internal (process_handle, ms);
+
+ bool exited = WaitForExit_internal (process_handle, ms);
+
+ if (exited)
+ OnExited ();
+
+ return exited;
}
/* Waits up to ms milliseconds for process 'handle' to
static void CBOnExit (object state, bool unused)
{
Process p = (Process) state;
- p.already_waiting = false;
+
+ if (!p.HasExited) {
+ if (p.exitWaitHandle != null) {
+ p.exitWaitHandle.Unregister (null);
+ p.exitWaitHandle = null;
+ }
+ p.StartExitCallbackIfNeeded ();
+ return;
+ }
+
p.OnExited ();
}
if (exited_event == null)
return;
+ if (exitWaitHandle != null) {
+ exitWaitHandle.Unregister (null);
+ exitWaitHandle = null;
+ }
+
if (synchronizingObject == null) {
foreach (EventHandler d in exited_event.GetInvocationList ()) {
try {
Assert.AreEqual (true, r, "Null Argument Events Raised");
}
+
+ [Test]
+ [NUnit.Framework.Category ("MobileNotWorking")]
+ public void TestEnableEventsAfterExitedEvent ()
+ {
+ Process p = new Process ();
+
+ p.StartInfo = GetCrossPlatformStartInfo ();
+ p.StartInfo.UseShellExecute = false;
+ p.StartInfo.RedirectStandardOutput = true;
+ p.StartInfo.RedirectStandardError = true;
+
+ var exitedCalledCounter = 0;
+ p.Exited += (object sender, EventArgs e) => {
+ exitedCalledCounter++;
+ Assert.IsTrue (p.HasExited);
+ };
+
+ p.EnableRaisingEvents = true;
+
+ p.Start ();
+ p.BeginErrorReadLine ();
+ p.BeginOutputReadLine ();
+ p.WaitForExit ();
+
+ Assert.AreEqual (1, exitedCalledCounter);
+ Thread.Sleep (50);
+ Assert.AreEqual (1, exitedCalledCounter);
+ }
+
+ [Test]
+ [NUnit.Framework.Category ("MobileNotWorking")]
+ public void TestEnableEventsBeforeExitedEvent ()
+ {
+ Process p = new Process ();
+
+ p.StartInfo = GetCrossPlatformStartInfo ();
+ p.StartInfo.UseShellExecute = false;
+ p.StartInfo.RedirectStandardOutput = true;
+ p.StartInfo.RedirectStandardError = true;
+
+ p.EnableRaisingEvents = true;
+
+ var exitedCalledCounter = 0;
+ p.Exited += (object sender, EventArgs e) => {
+ exitedCalledCounter++;
+ Assert.IsTrue (p.HasExited);
+ };
+
+ p.Start ();
+ p.BeginErrorReadLine ();
+ p.BeginOutputReadLine ();
+ p.WaitForExit ();
+
+ Assert.AreEqual (1, exitedCalledCounter);
+ Thread.Sleep (50);
+ Assert.AreEqual (1, exitedCalledCounter);
+ }
+
private ProcessStartInfo GetCrossPlatformStartInfo ()
{
return RunningOnUnix ? new ProcessStartInfo ("/bin/ls", "/") : new ProcessStartInfo ("help", "");
}
+
+ [Test] // Covers #26362
+ public void TestExitedEvent ()
+ {
+ var falseExitedEvents = 0;
+ var cp = Process.GetCurrentProcess ();
+ foreach (var p in Process.GetProcesses ()) {
+ if (p.Id != cp.Id && !p.HasExited) {
+ p.EnableRaisingEvents = true;
+ p.Exited += (s, e) => {
+ if (!p.HasExited)
+ falseExitedEvents++;
+ };
+ }
+ }
+ Assert.AreEqual (0, falseExitedEvents);
+ }
[Test]
public void ProcessName_NotStarted ()