3 // Regression test based on bug report from Arian Alin Radu.
4 // The problem was that tracked objects could be released
5 // while holding the signal mutex during signal invocation.
6 // This could result in a recursive
7 // lock attempt if the tracked object manipulates the signal
10 // Copyright Frank Mori Hess 2019
11 // Use, modification and
12 // distribution is subject to the Boost Software License, Version
13 // 1.0. (See accompanying file LICENSE_1_0.txt or copy at
14 // http://www.boost.org/LICENSE_1_0.txt)
16 // For more information, see http://www.boost.org
18 #define BOOST_TEST_MODULE signals2 deadlock regression test
19 #include <boost/test/included/unit_test.hpp>
20 #include <boost/shared_ptr.hpp>
21 #include <boost/make_shared.hpp>
22 #include <boost/signals2/signal.hpp>
23 #include <boost/signals2/signal_type.hpp>
25 namespace bs2
= boost::signals2
;
28 // dummy mutex that detects attempts to recursively lock
32 test_mutex(): m_locked(false) {}
35 BOOST_CHECK(m_locked
== false);
40 if(m_locked
) return false;
52 using namespace bs2::keywords
;
53 typedef bs2::signal_type
<void(), mutex_type
<test_mutex
> >::type Signal
;
55 class SelfReference
: private boost::noncopyable
58 boost::shared_ptr
<SelfReference
> m_self
;
59 boost::shared_ptr
<Signal
> m_signal
;
61 boost::signals2::connection m_conReleaseSelf
;
62 boost::signals2::connection m_conDoNothing
;
66 m_signal
= boost::make_shared
<Signal
>();
71 // the first slot (ReleaseSelf) has been called; now the trackable object (this)
72 // was released, while the second slot is locked
73 BOOST_CHECK(!m_conReleaseSelf
.connected());
74 // the second slot is locked, and we enter a recursive (pthread: dead) lock
75 BOOST_CHECK(m_conDoNothing
.connected());
76 m_conReleaseSelf
.disconnect();
77 m_conDoNothing
.disconnect();
78 // enter recursive (pthread: dead) lock again:
79 BOOST_CHECK(m_signal
->empty());
87 static void DoNothing()
93 boost::shared_ptr
<Signal
> signal
;
95 boost::shared_ptr
<SelfReference
> obj
= boost::make_shared
<SelfReference
>();
97 signal
= obj
->m_signal
;
99 obj
->m_conReleaseSelf
= signal
->connect(Signal::slot_type(&SelfReference::ReleaseSelf
, obj
.get()).track(obj
));
100 obj
->m_conDoNothing
= signal
->connect(Signal::slot_type(&SelfReference::DoNothing
));
106 BOOST_AUTO_TEST_CASE(test_main
)
108 SelfReference::Run();