locked
Proper way to compare HANDLE and INVALID_HANDLE_VALUE in 64 bit (and 32 bit)? RRS feed

  • Question

  • I am porting my 32 bit system to 64 bit and I've come across some my thread class code where I was using a macro to compare a handle to INVALID_HANDLE_VALUE when terminating the thread:

    #define VH(h) (h != INVALID_HANDLE_VALUE)

    The problem is that under 64 bit this is always true.  When the thread is closed, this is done:

    void CloseThread()
    {
      if (VH(hThread)) {
          HANDLE h = (HANDLE)InterlockedExchange((LPLONG)&hThread, -1);
          CloseHandle(h);
      }
    }

    I suppose I need to use a 64 bit InterLockedExchange() consideration, but overall, I thought -1 or INVALID_HANDLE_VALUE in 64 bit is 0xFFFFFFFFFFFFFFFF and not 0x00000000FFFFFFFF?

    I suppose I could use 0 here but this is widely used thread class code for a big platform and I need compatibility here.  Why is the VH macro not working?  What i am missing here?

    Thanks







    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com





    Monday, March 18, 2019 3:49 PM

Answers

  • This worked for me without changing the VH macro -

    #define VH(h) (h != INVALID_HANDLE_VALUE)
    
    int _tmain()
    {
    	HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
    
    	printf("hThread is %p\n", hThread);
    
    	if (VH(hThread))
    	{
    		HANDLE h = InterlockedExchangePointer(&hThread, INVALID_HANDLE_VALUE);
    		CloseHandle(h);
    	}
    	else
    		printf("hThread is invalid\n");
    
    	printf("hThread is %p\n", hThread);
    
    	if (VH(hThread))
    	{
    		HANDLE h = InterlockedExchangePointer(&hThread, INVALID_HANDLE_VALUE);
    		CloseHandle(h);
    	}
    	else
    		printf("hThread is invalid\n");
    
    	return 0;
    

    • Marked as answer by hector santos Monday, March 18, 2019 9:19 PM
    Monday, March 18, 2019 5:02 PM
  • I believe I resolved this by comparing the handle to three values; INVALID_HANDLE_VALUE, 0 and -1.

    // 454.8
    //#define VH(h) (h != INVALID_HANDLE_VALUE)
    #define VH(h) ((h != INVALID_HANDLE_VALUE) && ((int)h != 0) && ((int)h != -1))

    That allowed the threads to properly and gracefully shutdown without forced termination.


    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    • Marked as answer by hector santos Monday, March 18, 2019 4:52 PM
    Monday, March 18, 2019 4:52 PM

All replies

  • I believe I resolved this by comparing the handle to three values; INVALID_HANDLE_VALUE, 0 and -1.

    // 454.8
    //#define VH(h) (h != INVALID_HANDLE_VALUE)
    #define VH(h) ((h != INVALID_HANDLE_VALUE) && ((int)h != 0) && ((int)h != -1))

    That allowed the threads to properly and gracefully shutdown without forced termination.


    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    • Marked as answer by hector santos Monday, March 18, 2019 4:52 PM
    Monday, March 18, 2019 4:52 PM
  • This worked for me without changing the VH macro -

    #define VH(h) (h != INVALID_HANDLE_VALUE)
    
    int _tmain()
    {
    	HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId());
    
    	printf("hThread is %p\n", hThread);
    
    	if (VH(hThread))
    	{
    		HANDLE h = InterlockedExchangePointer(&hThread, INVALID_HANDLE_VALUE);
    		CloseHandle(h);
    	}
    	else
    		printf("hThread is invalid\n");
    
    	printf("hThread is %p\n", hThread);
    
    	if (VH(hThread))
    	{
    		HANDLE h = InterlockedExchangePointer(&hThread, INVALID_HANDLE_VALUE);
    		CloseHandle(h);
    	}
    	else
    		printf("hThread is invalid\n");
    
    	return 0;
    

    • Marked as answer by hector santos Monday, March 18, 2019 9:19 PM
    Monday, March 18, 2019 5:02 PM

  •  I thought -1 or INVALID_HANDLE_VALUE in 64 bit is 0xFFFFFFFFFFFFFFFF and not 0x00000000FFFFFFFF?


    Sounds like a reasonable expectation to me. Given that this is the definition:

    #define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
    

    Then this code:

    __int64 i64 = (__int64)INVALID_HANDLE_VALUE;
    HANDLE h1 = INVALID_HANDLE_VALUE;
    

    will produce values of

    i64 == 0x00000000ffffffff
    h1 == 0xffffffff

    in a 32-bit build, and:

    i64 == 0xffffffffffffffff
    h1 == 0xffffffffffffffff

    in a 64-bit build.

    - Wayne

    Monday, March 18, 2019 5:28 PM
  • The InterlockedExchange is killing this. This is because, as you should see with the (PLONG) cast, this works only on 32 bit values.

    For 64 bit values, including pointers/handles, you would want InterlockedExchange64, and as you should see from the parameters, there are LONG64 values, or 64 bit values. This won't truncate the HANDLE to 32 bit.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, March 18, 2019 5:40 PM
  • Darran,

    Since a HANDLE is just a typedef for void * then InterLockedExchangePointer seems to conveniently handle both 32 and 64 bit code.  Am I missing something?


    • Edited by RLWA32 Monday, March 18, 2019 5:45 PM
    Monday, March 18, 2019 5:45 PM
  • Unless I am missing something here, this is a pointer to a 32 bit value. Since this is a pointer to a handle (not the handle itself) then this would be a pointer to the lower 32 bits of the handle.

    The return of InterlockedExchange is also a long, so even if the pointer was somehow copied correctly, only a 32 bit value would be expected on output.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, March 18, 2019 6:06 PM
  • Unless I am missing something here, this is a pointer to a 32 bit value.

    I'm not sure if you are referring to code posted by the OP or the snippet in my earlier post.

    If you don't mind, could you take a look at that snippet?   If I remember correctly it produced the correct results for both 32 and 64 bit code when I tested it.

    Monday, March 18, 2019 6:21 PM
  • I'm not sure if you are referring to code posted by the OP or the snippet in my earlier post.

    I was referring to the OPs post not yours, I guess since I use the indented forum view, that was more obvious since my post wasn't attached to yours.

    But yes, your InterlockedExchangePointer would actually be a better fit since it changes size based on the platform.


    This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

    Monday, March 18, 2019 6:40 PM
  • Going to try using InterlockedExchangePointer() with the INVALID_HANDLE_VALUE exchange. 

    Thanks.


    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    Monday, March 18, 2019 9:03 PM
  • But yes, your InterlockedExchangePointer would actually be a better fit since it changes size based on the platform.

    Agree. The original VH macro worked as expected using the InterlockedExchangedPointer() in both 32/64 bit.

    Thanks for your input.


    Hector Santos, CTO Santronics Software, Inc. http://www.santronics.com

    Monday, March 18, 2019 9:15 PM