views:

28

answers:

1

I am trying to integrate some new code I wrote for programmatically interacting with Exchange 2010 via Remote Powershell into an existing WinForms application. My code works in an isolated test application, but when I run the code in the context of my app the call to Runspace.Open() blocks for a very long time -- well past the OpenTimeout value of 60 seconds which I am specifying in the WSManConnectionInfo instance. To me, this suggests that there is something in our application code which is creating the issue but I'm having trouble narrowing down what those potential causes could be. The application is multithreaded and uses both BackgroundThreadWorker and the ThreadPool; in fact, my code runs via the ThreadPool in the application. But I've already tried simulating this in my test harness and the code works fine when called as a callback from the ThreadPool too.

Here's the code (with error handling removed and constant definitions put nearby):

const string EXCHANGE_PS_URI_FORMAT = "http://{0}/PowerShell/";
string uriString = string.Format(EXCHANGE_PS_URI_FORMAT, HostName);
Uri connectionUri = new Uri(uriString);

PSCredential creds = new PSCredential(username, securePwd);

const string EXCHANGE_PS_SCHEMA_URL = 
    "http://schemas.microsoft.com/powershell/Microsoft.Exchange";
WSManConnectionInfo connectionInfo = 
    new WSManConnectionInfo(connectionUri, EXCHANGE_PS_SCHEMA_URL, creds);

const int DEFAULT_OPEN_TIMEOUT = 1 * 60 * 1000; // 1 minute
connectionInfo.OpenTimeout = DEFAULT_OPEN_TIMEOUT;
const int DEFAULT_OPERATION_TIMEOUT = 4 * 60 * 1000; // 4 minutes
connectionInfo.OperationTimeout = DEFAULT_OPERATION_TIMEOUT;

using (Runspace rs = RunspaceFactory.CreateRunspace(connectionInfo))
{
    // BUGBUG: WHY IS THIS FAILING TO RETURN?
    rs.Open(); // <-- HANGS HERE

    ICollection<PSObject> newReqResults = null;
    PipelineReader<object> newReqErrors = null;
    try
    {
        using (Pipeline pipeline = rs.CreatePipeline())
        {
            // cmd instance is already instantiated with cmdlet info, params, etc.
            pipeline.Commands.Add(cmd);

            //Invoke the command and return the results and errors
            newReqResults = pipeline.Invoke();
            newReqErrors = pipeline.Error;
        }
    }

    // Code to parse results and/or errors...

The call stack when the code hangs on the Runspace.Open() seems to show that the internal .NET code is stuck on a wait call, but I'm at a loss on how to proceed. As I said earlier, this code works fine in my test app even if called as a ThreadPool callback, so I'm wondering what could be in our main app code that could be causing this (synchronization context or the thread identity or something else?) Any help would be greatly appreciated. Please let me know if I've neglected to include some relevant info and I'm happy to include it. Thanks!

[In a sleep, wait, or join] 
mscorlib.dll!System.Threading.WaitHandle.WaitOne(long timeout, bool exitContext) + 0x2f bytes   
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x25 bytes    
mscorlib.dll!System.Threading.WaitHandle.WaitOne() + 0xd bytes  
System.Management.Automation.dll!System.Management.Automation.Runspaces.AsyncResult.EndInvoke() + 0x14 bytes    
System.Management.Automation.dll!System.Management.Automation.Runspaces.Internal.RunspacePoolInternal.EndOpen(System.IAsyncResult asyncResult) + 0xb2 bytes 
System.Management.Automation.dll!System.Management.Automation.Runspaces.Internal.RemoteRunspacePoolInternal.Open() + 0x1a bytes 
System.Management.Automation.dll!System.Management.Automation.Runspaces.RunspacePool.Open() + 0x48 bytes    
System.Management.Automation.dll!System.Management.Automation.RemoteRunspace.Open() + 0x73 bytes    
+1  A: 

Is it possible that when you run the program in the threadpool, that the thread is blocked? Perhaps what you really want here is to call OpenAsync rather than Open.

Jim Mischel
It's definitely a possibility that the worker thread gets blocked due to something in how our multithreading is working. I'd still prefer to keep my app's code synchronous for now, but I might not have a choice with deadlines looming. I'll see what I can prototype around OpenAsync, but I'd really like to understand root cause here -- specifically, what is the ThreadPool.Open() call stuck waiting on?
Matt
OK, I think I understand what's going on now. You're right that the thread is blocked; it's because there's code in our app to lower the ThreadPool's max thread count and it's causing this Runspace.Open() operation to deadlock. If I increase the ThreadPool's max thread count, the call to Runspace.Open() returns and my code continues as expected. Even though I didn't have to use OpenAsync(), I'm marking this as the answer because the root cause was correct -- the thread was blocked.
Matt