Archived
This forum has been archived. Please start a new discussion on GitHub.
Ice 'hangs' in destroy when called through DLL
Hi everyone,
I'm wrapping Ice 3.3.0 into a DLL (VS 2008) However I am not able to get it up and running properly. The problem is that Ice hangs when I try to unload the DLL. Even if I did not do anything but load and unload the DLL. I did not create any proxy instances, and not created any connections.
I have the following DLL main:
And i wrote the following test application:
When I run this it hangs at ic->destroy().
Here is the call-stack
As far as I know it waits for the timer to die, but it never does. From the Autos window I can see that _destroyed has been set to true.
The _timer instance contains the following values:
I had a similar problem with Ice 3.2.1, at that point the ConnectionMonitor did not die (I didn't create any connections then either, connections set was empty). That is why I upgraded the whole thing to Ice 3.3.0.
Strangly enough if I do not build a DLL, but instantiate Ice from a Console application it works fine. Is there something I am missing?
Regards,
Vincent
I'm wrapping Ice 3.3.0 into a DLL (VS 2008) However I am not able to get it up and running properly. The problem is that Ice hangs when I try to unload the DLL. Even if I did not do anything but load and unload the DLL. I did not create any proxy instances, and not created any connections.
I have the following DLL main:
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) { if (ul_reason_for_call == DLL_PROCESS_ATTACH) { try { // initialize Ice when DLL is loaded. Ice::PropertiesPtr props = Ice::createProperties(); props->setProperty("Ice.MessageSizeMax", "10240"); Ice::InitializationData data; data.properties = props; ic = Ice::initialize(data); } catch (const Ice::Exception& ex) { return FALSE; } } else if (ul_reason_for_call == DLL_PROCESS_DETACH) { // destroy Ice when DLL is unloaded. try { if (ic) { /*ic->shutdown(); ic->waitForShutdown();*/ ic->destroy(); } } catch (const Ice::Exception& ex) { // return true, even though things go wrong. return TRUE; } } return TRUE; }
And i wrote the following test application:
int _tmain(int argc, _TCHAR* argv[]) { /* get handle to dll */ HINSTANCE hGetProcIDDLL = LoadLibrary(_T("H:\\vc\\magnumDll\\Debug\\magnum.dll")); /* Release the Dll */ FreeLibrary(hGetProcIDDLL); return 0; }
When I run this it hangs at ic->destroy().
Here is the call-stack
ntdll.dll!7c90e4f4() [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll] ntdll.dll!7c90df3c() kernel32.dll!7c8025db() kernel32.dll!7c802542() > iceutil33d.dll!IceUtil::ThreadControl::join() Line 61 + 0x10 bytes C++ iceutil33d.dll!IceUtil::Timer::destroy() Line 44 C++ ice33d.dll!IceInternal::Instance::destroy() Line 1246 + 0x18 bytes C++ ice33d.dll!Ice::CommunicatorI::destroy() Line 74 + 0x12 bytes C++ magnum.dll!DllMain(void * hModule=0x10000000, unsigned long ul_reason_for_call=0, void * lpReserved=0x00000000) Line 72 + 0x30 bytes C++ magnum.dll!__DllMainCRTStartup(void * hDllHandle=0x10000000, unsigned long dwReason=0, void * lpreserved=0x00000000) Line 543 + 0x11 bytes C magnum.dll!_DllMainCRTStartup(void * hDllHandle=0x10000000, unsigned long dwReason=0, void * lpreserved=0x00000000) Line 507 + 0x11 bytes C ntdll.dll!7c90118a() ntdll.dll!7c91e024() kernel32.dll!7c801bea() kernel32.dll!7c80ac87() callDll.exe!main(int argc=1, char * * argv=0x00330f80) Line 31 + 0xc bytes C++ callDll.exe!mainCRTStartup() Line 259 + 0x19 bytes C kernel32.dll!7c817067() ice33d.dll!IceInternal::Instance::Instance(const IceInternal::Handle<Ice::Communicator> & communicator={...}, const Ice::InitializationData & initData={...}) Line 980 + 0x59 bytes C++ c483003e()
As far as I know it waits for the timer to die, but it never does. From the Autos window I can see that _destroyed has been set to true.
The _timer instance contains the following values:
- this 0x00a2bec0 {_monitor={...} _destroyed=true _tokens=[0]() ...} IceUtil::Timer * const + IceUtil::Shared {_ref=1 _noDelete=false } IceUtil::Shared - IceUtil::Thread {_stateMutex={...} _started=true _running=false ...} IceUtil::Thread + IceUtil::Shared {_ref=1 _noDelete=false } IceUtil::Shared + __vfptr 0x003d890c const IceUtil::Timer::`vftable'{for `IceUtil::Thread'} * + _stateMutex {_mutex={...} } IceUtil::Mutex _started true bool _running false bool _handle 0x0000009c void * _id 3300 unsigned long - _monitor {_cond={...} _mutex={...} _nnotify=0 } IceUtil::Monitor<IceUtil::Mutex> + _cond {_internal={...} _gate={...} _queue={...} ...} IceUtil::Cond + _mutex {_mutex={...} } IceUtil::Mutex _nnotify 0 int _destroyed true bool _tokens [0]() std::set<IceUtil::Timer::Token,std::less<IceUtil::Timer::Token>,std::allocator<IceUtil::Timer::Token> > _tasks [0]() std::map<IceUtil::Handle<IceUtil::TimerTask>,IceUtil::Time,IceUtil::Timer::TimerTaskCompare,std::allocator<std::pair<IceUtil::Handle<IceUtil::TimerTask> const ,IceUtil::Time> > > + _wakeUpTime {_usec=26506316554 } IceUtil::Time
I had a similar problem with Ice 3.2.1, at that point the ConnectionMonitor did not die (I didn't create any connections then either, connections set was empty). That is why I upgraded the whole thing to Ice 3.3.0.
Strangly enough if I do not build a DLL, but instantiate Ice from a Console application it works fine. Is there something I am missing?
Regards,
Vincent
0
Comments
-
Are you mixing the debug & release runtime DLLs in your application?0
-
Hi Metthew,
No, I created a DLL using /MDd, and linking the iced and iceutild libs.
This is the commandline for the compiler creating the DLL:/Od /I "C:\Ice-3.3.0-VC90\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "MAGNUMDLL_EXPORTS" /D "_WINDLL" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TP /errorReport:prompt
And this for the linker, linking the DLL:/OUT:"\\Rijnh\shares\Users\beveren\vc\magnumDll\Debug\magnum.dll" /INCREMENTAL /NOLOGO /LIBPATH:"C:\Ice-3.3.0-VC90\lib" /DLL /MANIFEST /MANIFESTFILE:"Debug\magnum.dll.intermediate.manifest" /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"\\rijnh\shares\Users\beveren\vc\magnumDll\Debug\magnum.pdb" /SUBSYSTEM:WINDOWS /DYNAMICBASE /NXCOMPAT /MACHINE:X86 /ERRORREPORT:PROMPT iced.lib iceutild.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib
Regards,
Vincent0 -
As an addition I noticed it only goes wrong when invoking it from the DllMain function (invoked by the kernel when FreeLibrary is invoked).
If I would create a DLL function deinit, and invoke ic->destory() there it does go right. However, I wish to perform clean up outside of the control of the people using the library, since it will probably be used by non-programmers in LabView.0 -
Hi Vincent,
I think this the problem:
The Old New Thing : Another reason not to do anything scary in your DllMain: Inadvertent deadlock
destroy() on the Ice communicator instructs the communicator to destroy its thread pools, and "join" these threads. Join is waiting on the thread's handle (Terminating a Thread (Windows)):int rc = WaitForSingleObject(_handle, INFINITE);
I suspect this handle is signaled only after the thread has completed the DLL_THREAD_DETACH, which is blocked on the loader lock. You should be able to confirm this in the debugger.
Cheers,
Bernard0 -
Hey Bernard,
Thank you for your reply. Yes, that is exactly where it hangs. From what I gather it is very likely that this is indeed what is going on.
If I understand correctly there is no solution for it inside the scope of the DllMain.
I could in theory start another thread to invoke the ic->destroy()... but that would be evil, since it will run partially after the DLL_PROCESS_DETACH has been completed.
Do you have a suggestion for a solution, (besides moving it outside the loader lock)?
Regards,
Vincent0 -
Hi Vincent,
The best solution is to destroy your Ice communicator before this DLL unloading. I hope you can find a way to do that in your app.
Cheers,
Bernard0 -
Yes, I was afraid so... well, we'll just hope that they use the LabView components properly
Thank you for your quick reply.
Vincent0 -
I am having the same problem, I am using a c++ dll in matlab. If I unload the dll without destroying the communicator, matlab crashes after a few minutes. What I ended up doing was constantly connecting and disconnecting so that when the dll was unloaded it would already be disconnected. Their didn't appear to be much of a performance loss doing this way.0