System.Data.SQLite

Login
This project makes use of Eagle, provided by Mistachkin Systems.
Eagle: Secure Software Automation
Ticket Hash: 393d954be013c24a4ab0a038478771f6be0f5c2e
Title: Deadlock in default connection pool implementation - support custom connection pool
Status: Closed Type: Feature_Request
Severity: Important Priority: NextRelease
Subsystem: Connection_Pool Resolution: Fixed
Last Modified: 2013-02-19 09:08:43
Version Found In: 1.0.82.0
User Comments:
anonymous added on 2013-02-12 13:24:48:
The fix for 996d13cd87 causes a deadlock due to the use of GC.WaitForPendingFinalizers() when creating connections in the (STA) main thread while finalization of COM objects is delegated to the same thread (which is blocked by waiting for finalizers).

mistachkin added on 2013-02-12 19:54:16: (text/x-fossil-plain)
To clarify: This is not a deadlock in System.Data.SQLite itself.  It would be
useful to know some additional information here:

1. What are the types of these COM objects?
2. What are their finalizers actually doing at the point of the deadlock?

anonymous added on 2013-02-13 12:07:53: (text/x-fossil-plain)
We are not using any COM objects directly in our application, but we are using WPF controls (only standard ones from PresentationCore) which make use of some from Text Services Framework (http://msdn.microsoft.com/en-us/library/windows/desktop/ms629032%28v=vs.85%29.aspx). Thus we have no control over how these are used, nor can we say what exactly these are doing. But I can provide the interesting call stacks:

Main thread:

0000000000194aa8 000007fefe0f1420 ntdll!ZwWaitForMultipleObjects+0xa
0000000000194ab0 0000000077442cf3 KERNELBASE!WaitForMultipleObjectsEx+0xe8
0000000000194bb0 000007fee84f17c7 KERNEL32!WaitForMultipleObjectsExImplementation+0xb3
0000000000194c40 000007fee26710c4 clr!DoNDirectCall__PatchGetThreadCall+0x7b
0000000000194cf0 000007fee2649a3e WindowsBase_ni!DomainBoundILStubClass.IL_STUB_PInvoke(Int32, IntPtr[], Boolean, Int32, Boolean)+0x94
0000000000194de0 000007fee8583534 WindowsBase_ni!System.Windows.Threading.DispatcherSynchronizationContext.Wait(IntPtr[], Boolean, Int32)+0x4e
0000000000194e20 000007fee8583649 clr!CallDescrWorker+0x84
0000000000194e80 000007fee85836c5 clr!CallDescrWorkerWithHandler+0xa9
0000000000194f00 000007fee8588cd4 clr!MethodDesc::CallDescr+0x2a1
0000000000195150 000007fee8691c53 clr!MethodDesc::CallTargetWorker+0x44
0000000000195190 000007fee8691ca3 clr!Thread::DoSyncContextWait+0xe3
0000000000195340 000007fee8526b13 clr! ?? ::FNODOBFM::`string'+0xa53ce
0000000000195440 000007fee8526d0a clr!Thread::DoAppropriateWait+0x73
00000000001954c0 000007fee871a358 clr!CLREvent::WaitEx+0xc1
0000000000195560 000007fee8718d98 clr!WKS::GCHeap::FinalizerThreadWait+0xc1
00000000001955c0 000007fee84f19c2 clr!GCInterface::WaitForPendingFinalizers+0x48
0000000000195610 000007ff006440e7 clr!DoNDirectCallWorker+0x62
00000000001956a0 000007ff00641deb System_Data_SQLite!System.Data.SQLite.SQLiteConnectionPool.Remove(System.String, Int32, Int32 ByRef)+0x347
0000000000195830 000007ff0057eb1c System_Data_SQLite!System.Data.SQLite.SQLite3.Open(System.String, System.Data.SQLite.SQLiteConnectionFlags, System.Data.SQLite.SQLiteOpenFlagsEnum, Int32, Boolean)+0x7b
00000000001958c0 000007ff0074fe26 System_Data_SQLite!System.Data.SQLite.SQLiteConnection.Open()+0x76c

GC thread

000000001af6e5f8 000007fefe0f10dc ntdll!ZwWaitForSingleObject+0xa
000000001af6e600 000007fefed0e68e KERNELBASE!WaitForSingleObjectEx+0x79
000000001af6e6a0 000007fefee43700 ole32!GetToSTA+0x8a [d:\w7rtm\com\ole32\com\dcomrem\chancont.cxx:131]
000000001af6e6f0 000007fefee4265b ole32!CRpcChannelBuffer::SwitchAptAndDispatchCall+0x13b [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx:4413]
000000001af6e790 000007fefecfdaaa ole32!CRpcChannelBuffer::SendReceive2+0x11b [d:\w7rtm\com\ole32\com\dcomrem\channelb.cxx:4074]
000000001af6e950 000007fefed0cbe6 ole32!CAptRpcChnl::SendReceive+0x52 [d:\w7rtm\com\ole32\com\dcomrem\callctrl.cxx:603]
000000001af6ea20 000007fefee4205d ole32!CCtxComChnl::SendReceive+0x15c [d:\w7rtm\com\ole32\com\dcomrem\ctxchnl.cxx:679]
000000001af6ead0 000007fefe2bb949 ole32!NdrExtpProxySendReceive+0x45 [d:\w7rtm\com\rpc\ndrole\proxy.cxx:1932]
000000001af6eb00 000007fefee421d0 RPCRT4!NdrpClientCall3+0x2e2
000000001af6edc0 000007fefecfd8a2 ole32!ObjectStublessClient+0x11d [d:\w7rtm\com\rpc\ndrole\amd64\stblsclt.cxx:621]
000000001af6f150 000007fefed1ea07 ole32!ObjectStubless+0x42 [d:\w7rtm\com\rpc\ndrole\amd64\stubless.asm:117]
000000001af6f1a0 000007fefed249d1 ole32!CObjectContext::InternalContextCallback+0x31537
000000001af6f2c0 000007fee86bd244 ole32!CObjectContext::ContextCallback+0x81 [d:\w7rtm\com\ole32\com\dcomrem\context.cxx:4182]
000000001af6f350 000007fee86bd2cd clr!CtxEntry::EnterContext+0x21e
000000001af6f480 000007fee86bd04a clr!RCWCleanupList::ReleaseRCWListInCorrectCtx+0xe8
000000001af6f4d0 000007fee869429e clr! ?? ::FNODOBFM::`string'+0x87540
000000001af6f580 000007fee8550fa1 clr!SyncBlockCache::CleanupSyncBlocks+0x133
000000001af6f5e0 000007fee86802f5 clr!Thread::DoExtraWorkForFinalizer+0x9a
000000001af6f610 000007fee8591b9a clr!WKS::GCHeap::FinalizerThreadWorker+0x55
000000001af6f640 000007fee8591b2f clr!VirtualCallStubManager::GenerateResolveCacheElem+0xaa
000000001af6f680 000007fee8591a9c clr!FullSegmentIterator+0x194
000000001af6f780 000007fee871fafe clr!ClrSafeInt<unsigned int>::ClrSafeInt<unsigned int><unsigned __int64>+0xb5
000000001af6f820 000007fee871ff6f clr!ManagedThreadBase_NoADTransition+0x3f
000000001af6f880 000007fee860a236 clr!WKS::GCHeap::FinalizerThreadStart+0x93
000000001af6f8c0 000000007743652d clr!Thread::intermediateThreadProc+0x7d
000000001af6f980 00000000779dc521 KERNEL32!BaseThreadInitThunk+0xd
000000001af6f9b0 0000000000000000 ntdll!RtlUserThreadStart+0x1d

mistachkin added on 2013-02-13 21:36:31: (text/x-fossil-plain)
Thanks for the additional information.

Technically, this issue is not a bug in System.Data.SQLite.  I'm not sure why WPF
requires synchronization with another thread during finalization of its objects;
however, I think the best course of action here is to avoid using the connection
pool in WPF applications.

mistachkin added on 2013-02-13 22:00:44: (text/x-fossil-plain)
Added warning to docs on trunk, here [dabfe38a9e].

anonymous added on 2013-02-14 09:27:06: (text/x-fossil-plain)
These COM objects have to be destroyed on the same thread where they have been created; this is not only true for WPF application but a general problem (see http://support.microsoft.com/kb/828988/en-us).

It would be helpful if you could either avoid the implicit lock or make it possible to plug-in a different connection-pool implementation.

mistachkin added on 2013-02-15 04:46:29: (text/x-fossil-plain)
Yes, I'm aware that COM objects may have thread-affinity.

Unfortunately, the call to WaitForPendingFinalizers cannot be removed without
impacting the correctness of the implementation.

I'll start working on making an external (pluggable) connection pool possible.

Thanks for your feedback.

mistachkin added on 2013-02-15 08:39:38: (text/x-fossil-wiki)
The initial prototype of the custom connection pool support is now available [/timeline?r=customPool|here].

mistachkin added on 2013-02-16 02:45:13: (text/x-fossil-plain)
Full docs and tests are now checked-in on the same branch.

mistachkin added on 2013-02-19 09:08:43: (text/x-fossil-plain)
Merged to trunk via check-in [90142c95cc].