3

I'm seeing a weird thing when connecting to the performance registry on 64 bit editions of Windows. The whole program stalls and callstacks becomes unreadable. After a long timeout, the connection attempts aborts and everything goes back to normal.

The only solution is to make sure that only one thread at the time queries the remote registry, unless the remote machine is a 32 bit Windows XP, 2003, 2000 , then you can use as many threads as you like.

Have anyone a technical explanation why this might be happening ? I've spent 2-3 days searching the web without coming up with anything.

Here is a test program, run it first with one thread (connecting to a 64 bit Windows), then remove the comment in tmain and run it with 4 threads. Running it with one thread works as expected, running with 4, returns ERROR_BUSY (dwRet == 170) after stalling for a while.

Remember to set a remote machine correctly in RegConnectRegistry before running the program.

#define TOTALBYTES    8192
#define BYTEINCREMENT 4096

void PerfmonThread(void *pData)
{
    DWORD BufferSize = TOTALBYTES;
    DWORD cbData;
    DWORD dwRet;

    PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) malloc( BufferSize );
    cbData = BufferSize;

    printf("\nRetrieving the data...");

    HKEY hKey;
    DWORD dwAccessRet = RegConnectRegistry(L"REMOTE_MACHINE",HKEY_PERFORMANCE_DATA,&hKey);

    dwRet = RegQueryValueEx( hKey,L"global",NULL,NULL,(LPBYTE) PerfData, &cbData );
    while( dwRet == ERROR_MORE_DATA )
    {
        // Get a buffer that is big enough.

        BufferSize += BYTEINCREMENT;
        PerfData = (PPERF_DATA_BLOCK) realloc( PerfData, BufferSize );
        cbData = BufferSize;

        printf(".");
        dwRet = RegQueryValueEx( hKey,L"global",NULL,NULL,(LPBYTE) PerfData,&cbData );
    }
    if( dwRet == ERROR_SUCCESS )
        printf("\n\nFinal buffer size is %d\n", BufferSize);
    else 
        printf("\nRegQueryValueEx failed (%d)\n", dwRet);

    RegCloseKey(hKey);
}

int _tmain(int argc, _TCHAR* argv[])
{
    _beginthread(PerfmonThread,0,NULL);
/*  _beginthread(PerfmonThread,0,NULL);
    _beginthread(PerfmonThread,0,NULL);
    _beginthread(PerfmonThread,0,NULL);
*/

    while(1)
    {

        Sleep(2000);
    }
}
ROAR
  • 1,304
  • 1
  • 11
  • 28
  • What windows? XP? Have you also tried this against a different 64-bit installation (another machine)? Are you querying from a 32-bit machine? (XP? Vista?) How about querying a 64-bit machine from another (or the same) 64-bit machine? – vladr Mar 29 '10 at 16:19
  • The problem is when a 32 bit application tries to access a 64 bit Windows edition with more then one thread at the same time. It do not matter if the program host is 64 bit or 32 bit Windows. As far as I can tell this applies to all 64 bit versions of Windows. – ROAR Mar 30 '10 at 07:31

2 Answers2

1

This is not really an answer, but a suggestion. Even though you are only querying the registry (not writing), I'm wondering if you are producing some kind of dead-lock with the multiple threads.

Lacking a Windows development or testing environment, take this suggestion for what its worth: perhaps you could use mutexes around the registry calls... that may relieve any deadlock situation, if that is indeed the problem.

Good luck.

Doug
  • 1,925
  • 3
  • 13
  • 9
  • Thats question, having simultaneous registry connections to a 32 bit machine works swell, when you point the exact same program to a 64 bit machine the application "hangs" in a undefined state. A "solution" is to make sure only one registry call at the time is executed. But the Microsoft documentation says nothing about this "limitation", thats why I opened this question in the first place, to find out if someone knows whats going on here. – ROAR Mar 30 '10 at 07:34
1

I think it must be an environmental issue. I just tried this from 32-bit Windows XP Professional to 64-bit Windows 7 Ultimate and it worked fine. Occasionally on a thread or two a call to RegQueryValueEx would fail with either ERROR_BUSY or ERROR_NOT_READY, but I never experienced any long delays. In case anybody else tries to test this, I ran into a snag; the account you are using must be a member of the Performance Monitor Users group in order to remotely access HKEY_PERFORMANCE_DATA. Also ensure the Remote Registry Service is running.

Luke
  • 11,211
  • 2
  • 27
  • 38
  • Long stalls might be subjective, but the problem is that the registry connections times out with ERROR_BUSY (like you noticed) if two is open at the same time, and thats also my question, if someone have any information on any un/documented restriction. Thanks for testing ! – ROAR Apr 01 '10 at 11:00
  • Well, it seems reasonable to receive ERROR_BUSY when dealing with operations over the network. Perhaps Microsoft tuned down the number of simultaneous remote registry operations on Vista. I didn't try with a 32-bit remote machine, but maybe I will later to see if I get similar behavior. If you are really crazy about fixing this, you could write your own remote registry service; Microsoft has published (or more likely was forced to publish) the spec - http://msdn.microsoft.com/en-us/library/cc244877.aspx – Luke Apr 01 '10 at 11:35
  • I just tried with 32-bit Windows 7 Ultimate and I had more problems than with the 64-bit edition. The data returned is MUCH larger for some reason so it takes MANY more attempts; this gives a larger opportunity for errors to occur. I don't think this issue is specific to 32-bit vs 64-bit, though. – Luke Apr 01 '10 at 12:54
  • The size of the data depends on how many performance counters the machine have installed, it can range from 20-30 KB to well over 1 MB. I'm starting to give up on this one, maybe it got something to do with the fact that the registry for 32 bit applications are virtualized on a 64 bit machine.... – ROAR Apr 01 '10 at 14:20
  • Both of these are default installs with no other software. I find it hard to believe that a default install of 32-bit Windows 7 Ultimate would have megabytes and megabytes of performance counters while a default install of 64-bit Windows 7 Ultimate would have only a fraction of that. In any case, I think you are just going to have to handle these error conditions gracefully; maybe sleep 100 ms and try again or something. – Luke Apr 01 '10 at 15:21
  • 32 bit machine produces more data since it have more counters available to a 32-bit program, so its expected that it will return more data then a 64 bit machine in this case. – ROAR Apr 02 '10 at 10:09
  • Ah, I didn't realize performance counters were architecture specific; that would explain it. – Luke Apr 02 '10 at 11:39