I found (and fixed) a deadlock in the Socket reactor when
add/removeEventHandler is called from within an event handler and from a
second thread. After quite a bit of time of scratching my head and
debugging I found out that the problem comes from the two mutexes in the
SocketReactor and the NotifictionCenter classes. If add/removeEventHandler
is called from within an event handler those two mutexes are locked in a
different order than if add/removeEventHandler is called from a different
thread (or outside the event handler code). You can see this in the two
stack backtraces below (mind my annotations enclosed in *** markers). This
results in a typical deadlock situation which is caused by the different
orders in which the two mutexes are locked.
My solution to this deadlock situation was not immediatly clear (at least
to me) but is rather simple. In the current implementation (version 1.3.3)
SocketReactor::dispatch() releases the SocketReactor::_mutex before it
calls SocketNotifier::dispatch() which in turn calls
NotificationCenter::postNotification() where the NotificationCenter::_mutex
is locked. If the SocketReactor::_mutex is held during the complete call to
SocketReactor::dispatch() then I can ensure that the order in which the two
mutexes are locked is the same whether add/removeEventHandler is called
from an event handler or a different thread.
I have appended a patch against the poco-1.3.3 Subversion branch. Please
check if this is an acceptable solution or fix this bug otherwise.
Stack backtrace of the main thread:
===================================
ntdll.dll!7c91eb94()
[Frames below may be incorrect and/or missing, no symbols loaded for
ntdll.dll]
ntdll.dll!7c91e9c0()
ntdll.dll!7c92901b()
ntdll.dll!7c91104b()
> PocoFoundationd.dll!Poco::MutexImpl::lockImpl() Line 76 + 0xc bytes C++
PocoFoundationd.dll!Poco::Mutex::lock() Line 175 C++
PocoFoundationd.dll!Poco::ScopedLock<Poco::Mutex>::ScopedLock<Poco::Mutex
>(Poco::Mutex & mutex={...}) Line 60 C++
PocoFoundationd.dll!Poco::NotificationCenter::removeObserver(const
Poco::AbstractObserver & observer={...}) Line 70 + 0xf bytes C++
*** NotificationCenter::_mutex is locked here! (has to wait for the reactor
thread) ***
PocoNetd.dll!Poco::Net::SocketNotifier::removeObserver(Poco::Net::SocketR
eactor * pReactor=0x0012feec, const Poco::AbstractObserver &
observer={...}) Line 73 + 0x12 bytes C++
PocoNetd.dll!Poco::Net::SocketReactor::removeEventHandler(const
Poco::Net::Socket & socket={...}, const Poco::AbstractObserver &
observer={...}) Line 163 C++
*** SocketReactor::_mutex is locked here! ***
PocoReactorTest.exe!Poco::Net::SocketConnector<Connection>::unregisterCon
nector() Line 142 + 0x49 bytes C++
PocoReactorTest.exe!Poco::Net::SocketConnector<Connection>::~SocketConnec
tor<Connection>() Line 116 C++
PocoReactorTest.exe!Poco::Net::SocketConnector<Connection>::`scalar
deleting destructor'() + 0x2b bytes C++
PocoReactorTest.exe!main() Line 99 + 0x37 bytes C++
PocoReactorTest.exe!__tmainCRTStartup() Line 597 + 0x19 bytes C
PocoReactorTest.exe!mainCRTStartup() Line 414 C
kernel32.dll!7c816fd7()
Stack backtrace of the reactor thread:
===============
ntdll.dll!7c91eb94()
[Frames below may be incorrect and/or missing, no symbols loaded for
ntdll.dll]
ntdll.dll!7c91e9c0()
ntdll.dll!7c92901b()
ntdll.dll!7c91104b()
PocoFoundationd.dll!Poco::MutexImpl::lockImpl() Line 76 + 0xc bytes C++
PocoFoundationd.dll!Poco::FastMutex::lock() Line 206 C++
PocoNetd.dll!Poco::ScopedLock<Poco::FastMutex>::ScopedLock<Poco::FastMute
x>(Poco::FastMutex & mutex={...}) Line 59 + 0xd bytes C++
PocoNetd.dll!Poco::Net::SocketReactor::removeEventHandler(const
Poco::Net::Socket & socket={...}, const Poco::AbstractObserver &
observer={...}) Line 156 + 0xf bytes C++
*** SocketReactor::_mutex is locked here! (has to wait for the main thread)
***
PocoReactorTest.exe!Connection::~Connection() Line 33 + 0x48 bytes C++
PocoReactorTest.exe!Connection::`scalar deleting destructor'() + 0x2b
bytes C++
PocoReactorTest.exe!Connection::onWritable(const
Poco::AutoPtr<Poco::Net::WritableNotification> & notification={...}) Line
48 + 0x2b bytes C++
PocoReactorTest.exe!Poco::NObserver<Connection,Poco::Net::WritableNotific
ation>::notify(Poco::Notification * pNf=0x00c0a000) Line 104 + 0x14
bytes C++
PocoFoundationd.dll!Poco::NotificationCenter::postNotification(Poco::Noti
fication * pNotification=0x00c0a000) Line 95 + 0x29 bytes C++
*** NotificationCenter::_mutex is locked here! ***
PocoNetd.dll!Poco::Net::SocketNotifier::dispatch(Poco::Net::SocketNotific
ation * pNotification=0x00c0a000) Line 96 + 0x12 bytes C++
> PocoNetd.dll!Poco::Net::SocketReactor::dispatch(Poco::AutoPtr<Poco::Net::
SocketNotifier> & pNotifier={...}, Poco::Net::SocketNotification *
pNotification=0x00c0a000) Line 216 + 0x1d bytes C++
PocoNetd.dll!Poco::Net::SocketReactor::dispatch(const Poco::Net::Socket &
socket={...}, Poco::Net::SocketNotification * pNotification=0x00c0a000)
Line 193 C++
PocoNetd.dll!Poco::Net::SocketReactor::run() Line 110 + 0x20 bytes C++
PocoFoundationd.dll!Poco::ThreadImpl::entry(void * pThread=0x0012fe8c)
Line 158 + 0x13 bytes C++
kernel32.dll!7c80b683()
Nobody/Anonymous
None
None
Public
|
Date: 2009-08-07 11:20 I have added a fix in the 1.3.6 branch (rev. 1235), which includes a |
|
Date: 2008-05-02 23:27
|
| Filename | Description | Download |
|---|---|---|
| socket_reactor_deadlock.diff | Bugfix patch against poco-1.3.3 | Download |
| PocoReactorTest.cpp | Test program to reproduce the deadlock. | Download |
| Field | Old Value | Date | By |
|---|---|---|---|
| status_id | Open | 2009-11-23 21:16 | obiltschnig |
| allow_comments | 1 | 2009-11-23 21:16 | obiltschnig |
| close_date | - | 2009-11-23 21:16 | obiltschnig |
| resolution_id | None | 2009-08-07 11:20 | obiltschnig |
| File Added | 276656: PocoReactorTest.cpp | 2008-05-02 23:27 | klaus_uhl |
| File Added | 276655: socket_reactor_deadlock.diff | 2008-05-02 23:25 | klaus_uhl |