0

This was a manual dump. Some people claim that there was a deadlock.

1) !locks says that the OwningThread of my critical section is 19a0, but that thread doesnt even exist? (look at ~ output)

2) EntryCount is 0, so the only thread that ever called EnterCriticalSection was 19a0. ContentionCount is cd(205), which would mean mean that other threads did try to EnterCriticalSection? Are these 2 things not contradictory?

3) RecursionCount is 1, meaning that the thread 19a0 called EnterCriticalSection once initialy, leading to LockCount:0 and RecursionCount:1. How did LockCount reach 8, if RecursionCount is still 1? It would have to be 8 and 9, since i know that EntryCount is 0, which means that only the thread 19a0 called EnterCriticalSection those 8 times?

4) 8 different threads show in their kb output:

02 00007ff8`500af83f : 00000146`**ed3502a0** 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlpWaitOnAddress+0xb2. 

So how can EntryCount be 0 here? Does WaitOnAdress matter? Or only EnterCriticalSection/EnterCriticalSectionContended?

5) A general explanation of what might have happened in this critical section would be helpful.

0:021> !locks
CritSec +ed3502a0 at 00000146ed3502a0
WaiterWoken        No
LockCount          8
RecursionCount     1
OwningThread       19a0
EntryCount         0
ContentionCount    cd
*** Locked

0:021> ~
#  0  Id: 10f40.ca10 Suspend: 0 Teb: 00000031`d9312000 Unfrozen
1  Id: 10f40.bcc4 Suspend: 0 Teb: 00000031`d931a000 Unfrozen
2  Id: 10f40.4de4 Suspend: 0 Teb: 00000031`d931c000 Unfrozen
3  Id: 10f40.4b9c Suspend: 0 Teb: 00000031`d931e000 Unfrozen
4  Id: 10f40.b34 Suspend: 0 Teb: 00000031`d9320000 Unfrozen
5  Id: 10f40.12680 Suspend: 0 Teb: 00000031`d9328000 Unfrozen
6  Id: 10f40.f420 Suspend: 0 Teb: 00000031`d932a000 Unfrozen
7  Id: 10f40.7d5c Suspend: 0 Teb: 00000031`d932c000 Unfrozen
8  Id: 10f40.f544 Suspend: 0 Teb: 00000031`d932e000 Unfrozen
9  Id: 10f40.7774 Suspend: 0 Teb: 00000031`d9330000 Unfrozen
10  Id: 10f40.101a0 Suspend: 0 Teb: 00000031`d9332000 Unfrozen
11  Id: 10f40.104e8 Suspend: 0 Teb: 00000031`d9336000 Unfrozen
12  Id: 10f40.135e8 Suspend: 0 Teb: 00000031`d9338000 Unfrozen
13  Id: 10f40.7ad0 Suspend: 0 Teb: 00000031`d9342000 Unfrozen
14  Id: 10f40.113ec Suspend: 0 Teb: 00000031`d9344000 Unfrozen
15  Id: 10f40.7a7c Suspend: 0 Teb: 00000031`d9346000 Unfrozen
16  Id: 10f40.6b18 Suspend: 0 Teb: 00000031`d9354000 Unfrozen
17  Id: 10f40.a414 Suspend: 0 Teb: 00000031`d9356000 Unfrozen
18  Id: 10f40.133b4 Suspend: 0 Teb: 00000031`d935a000 Unfrozen
19  Id: 10f40.11794 Suspend: 0 Teb: 00000031`d935c000 Unfrozen
20  Id: 10f40.4e40 Suspend: 0 Teb: 00000031`d935e000 Unfrozen
. 21  Id: 10f40.8b5c Suspend: 0 Teb: 00000031`d9360000 Unfrozen
22  Id: 10f40.115b4 Suspend: 0 Teb: 00000031`d9362000 Unfrozen
23  Id: 10f40.1f38 Suspend: 0 Teb: 00000031`d9364000 Unfrozen
24  Id: 10f40.e560 Suspend: 0 Teb: 00000031`d9368000 Unfrozen
25  Id: 10f40.1047c Suspend: 0 Teb: 00000031`d92c2000 Unfrozen
26  Id: 10f40.ad40 Suspend: 0 Teb: 00000031`d9214000 Unfrozen
27  Id: 10f40.8e00 Suspend: 0 Teb: 00000031`d9208000 Unfrozen
28  Id: 10f40.af38 Suspend: 0 Teb: 00000031`d9220000 Unfrozen
29  Id: 10f40.c6a4 Suspend: 0 Teb: 00000031`d9222000 Unfrozen
30  Id: 10f40.14114 Suspend: 0 Teb: 00000031`d9224000 Unfrozen
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
Milan
  • 616
  • 5
  • 11

1 Answers1

2

For 1): that thread may have been terminated by an exception or finished normally and someone forgot to implement LeaveCriticalSection.

For 2): EntryCount is incremented when other threads call EnterCriticalSection()

EntryCount and ContentionCount are never decremented

as documented.

For 3):

The field LockCount is not a true lock count any more, as explained in this answer. Relevant part:

In Microsoft Windows Server 2003 Service Pack 1 and later versions of Windows, the LockCount field is parsed as follows:

  • The lowest bit shows the lock status. If this bit is 0, the critical section is locked; if it is 1, the critical section is not locked.
  • The next bit shows whether a thread has been woken for this lock. If this bit is 0, then a thread has been woken for this lock; if it is 1, no thread has been woken.
  • The remaining bits are the ones-complement of the number of threads waiting for the lock.

For 4): RtlpWaitOnAddress IMHO is not so useful. There should be some RtlpEnterCriticalSection on the call stack as well. The argument there can be used for the !cs command.

For 5): One of my demos is the following code. It uses an event instead of a critical section, but the result is the same:

#include "stdafx.h"
#include <Windows.h>
#include <process.h>
#include <stdio.h>
#include <iostream>


HANDLE threadA;
HANDLE threadB;
HANDLE eventB;

class WorkItem
{
public:
    virtual void Initialize()
    {
    }
};

unsigned int __stdcall initializeWorkitems(void* param) 
{
    try
    {
        // Initialize workitems
        WorkItem **items = new WorkItem*[2];
        items[0] = new WorkItem();
        items[1] = NULL;
    
        for (int i = 0; i<2; i++)
        {
                items[i]->Initialize();
        }

        // Signal event for second thread to work on work items
        SetEvent(eventB);
    }
    catch(...)
    {
        // Don't do this
    }
    return 0;
}

unsigned int __stdcall processWorkitems(void* param) 
{
    // Wait for work item initialization to complete
    WaitForSingleObject(eventB, INFINITE);
    
    // Work on workitems
    Sleep(100);

    return 0;
}


int _tmain(int argc, _TCHAR* argv[])
{
    eventB = CreateEvent(0, 0, 0, 0);

    threadA = (HANDLE)_beginthreadex(0, 0, &initializeWorkitems, (void*)0, 0, 0);
    threadB = (HANDLE)_beginthreadex(0, 0, &processWorkitems, (void*)0, 0, 0);

    WaitForSingleObject(threadA, INFINITE);
    WaitForSingleObject(threadB, INFINITE);

    CloseHandle(threadA);
    CloseHandle(threadB);

    CloseHandle(eventB);

    return 0;
}
Community
  • 1
  • 1
Thomas Weller
  • 55,411
  • 20
  • 125
  • 222
  • 1) this means the critical section is still taken, and no other thread can enter it, even tho the original owning thread died due to an exception? 3) from what i have read, the !locks command interprets this already... even if not, lock count 8 is 00001000, still 8. – Milan Dec 15 '17 at 08:41
  • 1
    @Milan. 1) yes, that's my opinion 3) 8 is 0b1000. Removing the lowest 2 bits gives 0b10, which is 2 – Thomas Weller Dec 15 '17 at 09:03
  • ohh. you remove the 2 bits, not just subtract. right. thankies. i do think that windbg interprets this already though. i find 8 threads that call the critsection mentioned above. also WaiterWoken is No, meaning LockCount must have already been interpreted... 3) still confuses me: if it were LockCount: 2 (owningthread + 2 other threads), then the EntryCount should be 2 and not 0 :/ or if the owningthread locked it multiple times the RecursionCount should go to 3. i just cannot imagine a situation where LockCount is 2 while RecursionCount is 1 and EntryCount is 0. – Milan Dec 15 '17 at 11:19