]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/signals2/test/deadlock_regression_test.cpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / libs / signals2 / test / deadlock_regression_test.cpp
1 // Signals2 library
2 //
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
8 // in its destructor.
9
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)
15
16 // For more information, see http://www.boost.org
17
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>
24
25 namespace bs2 = boost::signals2;
26
27
28 // dummy mutex that detects attempts to recursively lock
29 class test_mutex
30 {
31 public:
32 test_mutex(): m_locked(false) {}
33 void lock()
34 {
35 BOOST_CHECK(m_locked == false);
36 m_locked = true;
37 }
38 bool try_lock()
39 {
40 if(m_locked) return false;
41 lock();
42 return true;
43 }
44 void unlock()
45 {
46 m_locked = false;
47 }
48 private:
49 bool m_locked;
50 };
51
52 using namespace bs2::keywords;
53 typedef bs2::signal_type<void(), mutex_type<test_mutex> >::type Signal;
54
55 class SelfReference: private boost::noncopyable
56 {
57 public:
58 boost::shared_ptr<SelfReference> m_self;
59 boost::shared_ptr<Signal> m_signal;
60
61 boost::signals2::connection m_conReleaseSelf;
62 boost::signals2::connection m_conDoNothing;
63
64 SelfReference()
65 {
66 m_signal = boost::make_shared<Signal>();
67 }
68
69 ~SelfReference()
70 {
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());
80 }
81
82 void ReleaseSelf()
83 {
84 m_self.reset();
85 }
86
87 static void DoNothing()
88 {
89 }
90
91 static void Run()
92 {
93 boost::shared_ptr<Signal> signal;
94 {
95 boost::shared_ptr<SelfReference> obj = boost::make_shared<SelfReference>();
96 obj->m_self = obj;
97 signal = obj->m_signal;
98
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));
101 }
102 (*signal)();
103 }
104 };
105
106 BOOST_AUTO_TEST_CASE(test_main)
107 {
108 SelfReference::Run();
109 }