SMGreenfield
SMGreenfield

Reputation: 1720

Elimininating Process.WaitForExit() / StandardOutput deadlock condition

I've read about this deadlock condition that I'm pretty certain is affecting my code (below). What I don't understand is: this code worked perfectly well running on Windows Server 2003 (.net 2.0) for the past 12 years. Now we've been trying to move it to Windows Server 2012, where it always deadlocks.

While my DLLs are built for "anyCPU" (still targeting .net 2.0), the executable process being run is absolutely 32-bit, and the move from Server 2003 to Server 2012 goes from a 32-bit to 64-bit OS.

I think I understand what to do to resolve the issue, but does anyone know why this behavior would have changed from Server 2003 to Server 2012?

public string DoMyProcess(string filenameAndPath, string arguments)
{
    string stdout="";
    int exitCode = 0;               

    try 
    {               
        ProcessStartInfo procStartInfo = new ProcessStartInfo();
        procStartInfo.FileName = filenameAndPath;
        procStartInfo.CreateNoWindow = true;
        procStartInfo.Arguments = arguments;            
        procStartInfo.RedirectStandardOutput = true;
        procStartInfo.UseShellExecute = false;

        System.Diagnostics.Process theProcess = null;
        try
        {
            theProcess = Process.Start(procStartInfo);
            theProcess.WaitForExit();

            exitCode = theProcess.ExitCode;

            // moving this ABOVE WaitForExit should eliminate deadlocks
            // But why did it always work on Server 2003 but not on Server 2012?
            stdout = theProcess.StandardOutput.ReadToEnd();

        }
        catch (System.Exception e)
        {
            string errMsg = e.Message;
            log_the_error("threw an exception: " + e.Message);
        }                   
    }           

    return stdout;
}

UPDATE:

Mystery deadlock still exists, even after changing the above code as recommended:

        try
        {
            theProcess = Process.Start(procStartInfo);
            stdout = theProcess.StandardOutput.ReadToEnd();                     
        }
        catch (System.Exception e)
        {
            string errMsg = e.Message;
            log_the_error("threw an exception: " + e.Message);
        }                   
    }           

What other conditions could cause that deadlock? If I were to examine StandardError, would it reveal anything useful?

UPDATE #2:

FWIW, we have provisioned another Windows Server 2003 (32-bit), which runs IIS 6. That was the original machine configuration this code ran on for 12 years (with only an occasional deadlock). Our same code that deadlocks on Server 2012 IIS 8 DOES NOT DEADLOCK on this Server 2003.

We now have our own minimal and complete code that reproduces the issue. However, the .exe we've licensed that is being executed by the process has confidentiality clauses that prevent us from posting. I realize that doesn't help the experts here.

THE ONE HINT we've encountered is that when run via the Visual Studio 2013 debugger installed on the actual server, the process doesn't deadlock/hang, while invoking the process from a browser OUTSIDE the server does. And oddly -- from a browser ON THE 2012 SERVER we can't connect to that test page -- the browser just says "connecting" and eventually times out (however, other sites hosted by the same server / same IIS 8 CAN BE REACHED from a browser on the server!)

Since the same command line parameters manually run from either an admin command shell or a non-admin command shell works perfectly, it's hard to believe it's a 64-bit / WOW64 problem with this 32-bit executable or it's required DLLs. We continue to search for places our permissions may be causing problems (the process needs to write to a temp folder, which we've placed at c:\temp, for now).

Upvotes: 1

Views: 1556

Answers (1)

Peter Duniho
Peter Duniho

Reputation: 70701

Without a good Minimal, Complete, and Verifiable code example, it's impossible to answer completely.

What I can tell you is that your code was always broken, and always had the potential for deadlock. You fail to read anything from the process until the process exits, but the process may not be able to exit, if it writes so much data to stdout that the buffer fills and blocks the process.

If you haven't recompiled anything, but have found that you see deadlock now when you didn't before, then the most likely explanation is that the process you're starting writes more to stdout than it used to. I.e. all of the output used to fit in the buffer before, but now it doesn't. (I guess it's also possible the buffer size was reduced in the newer OS, but that seems unlikely to me.)

You should go ahead and move the call to ReadToEnd(). In fact, you should do away with the WaitForExit() altogether. If you are calling ReadToEnd(), that won't complete until the process has in fact exited anyway, so calling WaitForExit() afterwards would be pointless.

Upvotes: 1

Related Questions