I have been running into deadlock problems in the direct sound
dll and have been playing with the debug part of critical
sections. I added a lock name to Spare[1] to give the critical
sections names that will show up in the error messages just
like wine's ntdll does. After looking at the ntdll code, it
looks like this causes a leak because ntdll statically initializes
it's locks and doesn't delete the debug part when it finds
Spare[1] used.
I also tried adding a linked list of critical section debug structs
just like real windows does. Because ntdll statically initializes
it's locks, they don't get added to the list. I manually stuff
the critical section list lock into the list so it shows up and
user locks show up but not the other internal ntdll locks.
Is there a good reason to statically initialize ntdll locks or
can they be initialized like normal locks?
Here is a patch that adds the linked list of debug info:
Index: dlls/ntdll/critsection.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/critsection.c,v
retrieving revision 1.27
diff -u -r1.27 critsection.c
--- dlls/ntdll/critsection.c 6 Sep 2004 20:26:23 -0000 1.27
+++ dlls/ntdll/critsection.c 10 Sep 2004 16:29:14 -0000
@@ -36,6 +36,51 @@
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
WINE_DECLARE_DEBUG_CHANNEL(relay);
+static LIST_ENTRY RtlCriticalSectionList;
+static CRITICAL_SECTION RtlCriticalSectionLock;
+static CRITICAL_SECTION_DEBUG RtlCriticalSectionDebug =
+{
+ 0, 0, &RtlCriticalSectionLock,
+ { &RtlCriticalSectionDebug.ProcessLocksList,
+ &RtlCriticalSectionDebug.ProcessLocksList },
+ 0, 0, { 0, (DWORD)(__FILE__ ": RtlCriticalSectionLock") }
+};
+static CRITICAL_SECTION RtlCriticalSectionLock = { &RtlCriticalSectionDebug, -1, 0, 0, 0, 0 };
+
+void critsection_init()
+{
+ InitializeListHead( &RtlCriticalSectionList );
+ InsertHeadList( &RtlCriticalSectionList, &RtlCriticalSectionDebug.ProcessLocksList );
+}
+
+static void CRIT_Dump()
+{
+ int i = 0;
+ PLIST_ENTRY mark, entry;
+ PCRITICAL_SECTION_DEBUG debug;
+
+ RtlEnterCriticalSection( &RtlCriticalSectionLock );
+
+ mark = &RtlCriticalSectionList;
+ for (entry = mark->Flink; entry != mark; entry = entry->Flink)
+ {
+ debug = CONTAINING_RECORD(entry, CRITICAL_SECTION_DEBUG, ProcessLocksList);
+
+ TRACE("RtlCriticalSectionDebug[%d]:\n", i++);
+ TRACE(" Type = %04x\n", debug->Type);
+ TRACE(" CreatorBackTraceIndex = %04x\n", debug->CreatorBackTraceIndex);
+ TRACE(" CriticalSection = %p\n", debug->CriticalSection);
+ TRACE(" ProcessLocksList.Flink = %p\n", debug->ProcessLocksList.Flink);
+ TRACE(" ProcessLocksList.Blink = %p\n", debug->ProcessLocksList.Blink);
+ TRACE(" EntryCount = %ld\n", debug->EntryCount);
+ TRACE(" ContentionCount = %ld\n", debug->ContentionCount);
+ TRACE(" Spare[0] = %08lx\n", debug->Spare[0]);
+ TRACE(" Spare[1] = %08lx (%s)\n", debug->Spare[1], debugstr_a((char *)debug->Spare[1]));
+ }
+
+ RtlLeaveCriticalSection( &RtlCriticalSectionLock );
+}
+
inline static LONG interlocked_inc( PLONG dest )
{
return interlocked_xchg_add( dest, 1 ) + 1;
@@ -126,12 +171,16 @@
crit->DebugInfo->Type = 0;
crit->DebugInfo->CreatorBackTraceIndex = 0;
crit->DebugInfo->CriticalSection = crit;
- crit->DebugInfo->ProcessLocksList.Blink = &(crit->DebugInfo->ProcessLocksList);
- crit->DebugInfo->ProcessLocksList.Flink = &(crit->DebugInfo->ProcessLocksList);
crit->DebugInfo->EntryCount = 0;
crit->DebugInfo->ContentionCount = 0;
crit->DebugInfo->Spare[0] = 0;
crit->DebugInfo->Spare[1] = 0;
+ RtlEnterCriticalSection( &RtlCriticalSectionLock );
+ InsertTailList( &RtlCriticalSectionList, &(crit->DebugInfo->ProcessLocksList) );
+ RtlLeaveCriticalSection( &RtlCriticalSectionLock );
+
+ if (TRACE_ON(ntdll))
+ CRIT_Dump();
}
}
crit->LockCount = -1;
@@ -195,12 +244,19 @@
crit->LockSemaphore = 0;
if (crit->DebugInfo)
{
+ RtlEnterCriticalSection( &RtlCriticalSectionLock );
+ RemoveEntryList( &(crit->DebugInfo->ProcessLocksList) );
+ RtlLeaveCriticalSection( &RtlCriticalSectionLock );
+
/* only free the ones we made in here */
if (!crit->DebugInfo->Spare[1])
{
RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
crit->DebugInfo = NULL;
}
+
+ if (TRACE_ON(ntdll))
+ CRIT_Dump();
}
return STATUS_SUCCESS;
}
Index: dlls/ntdll/ntdll_misc.h
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/ntdll_misc.h,v
retrieving revision 1.48
diff -u -r1.48 ntdll_misc.h
--- dlls/ntdll/ntdll_misc.h 15 Jul 2004 22:07:21 -0000 1.48
+++ dlls/ntdll/ntdll_misc.h 10 Sep 2004 16:29:14 -0000
@@ -50,6 +50,7 @@
extern void debug_init(void);
extern void thread_init(void);
extern void virtual_init(void);
+extern void critsection_init(void);
/* server support */
extern void server_init_process(void);
Index: dlls/ntdll/thread.c
===================================================================
RCS file: /home/wine/wine/dlls/ntdll/thread.c,v
retrieving revision 1.21
diff -u -r1.21 thread.c
--- dlls/ntdll/thread.c 23 Aug 2004 18:52:54 -0000 1.21
+++ dlls/ntdll/thread.c 10 Sep 2004 16:29:14 -0000
@@ -134,6 +134,7 @@
debug_info.str_pos = debug_info.strings;
debug_info.out_pos = debug_info.output;
+ critsection_init();
debug_init();
virtual_init();