Alex Rivera | Logout

Why is the OwningThread member of CRITICAL_SECTION of type HANDLE, when it is denoting the thread ID?

Asked 2012-10-01T14:31:19.790
10

I'm trying to add some debug checking for a CRITICAL_SECTION unlocking code, and I tried the following:

...
  if (m_pCritSect) {
    ASSERT(m_pCritSect->OwningThread == GetCurrentThreadId());
    LeaveCriticalSection(m_pCritSect);
  }
}

From debugging CRITICAL_SECTIONS (With VS 2005, mostly on WindowsXP) I "know" that the value of OwningThread (member of the RTL_CRITICAL_SECTION structure defined in winnt.h) is the value of th ID of the thread holding the lock.

However thread IDs are represented by DWORD (typedef for unsigned long) values while this variable has type HANDLE (typedef for void*) requiring a reinterpret_cast for the use of the HandleToULong Macro from basetsd.h for the above code to work.

Even the MSDN docs state:

When the first thread calls the EnterCriticalSection routine, (...) OwningThread becomes the thread ID of the caller.

So why on earth is this defined as a HANDLE?


Edit Note: I found a statement where a poster suggests that the HANDLE / DWORD-Id mismatch is some known misfeature of some Windows internals. So maybe this is the case here too:

GetCurrentThreadId returns a DWORD, which I send up to the kernel in a message. PsLookupThreadByThreadId takes the thread Id in a HANDLE, ... ...

This is a known Windows API bug ("known" in that I talked to the relevant filter manager DEV about this, as it shows up in Filter Manager as well because of the I/O Manager API issue.) As long as you don't have more than a half billion

Edit
Report

1 Answer

10

Any identifier in the SDK whose name starts with RTL or Rtl is code or declarations that are part of the runtime layer, the glue that marries the well-documented Winapi to the undocumented native operating system api. The winapi is cast in stone, the native operating system changes heavily with each Windows release. Inevitably, the glue changes as well.

The winapi is the documented layer, the native operating system is undocumented. The runtime layer was undocumented as well, but over time parts of it were revealed. Either because it back-fills a missing feature in the winapi. Or, in this case, because is genuinely useful to troubleshoot problems. One core problem with doing so however is that once a declaration is revealed, Microsoft can never change it again. Because doing so will break existing programs, a great burden to its customers.

So surely, the ThreadOwner field once truly held the handle to the thread in a previous Windows version. Note how the LockSemaphore is misleading too, it is actually an auto-reset event. Too late to fix it, the cat is out of the bag.

answered 2012-10-01T16:19:49.873

Your Answer