Mir

Merge lp:~mir-team/mir/fix-delayed-sigaction-restore into lp:mir

Proposed by Andreas Pokorny
Status: Work in progress
Proposed branch: lp:~mir-team/mir/fix-delayed-sigaction-restore
Merge into: lp:mir
Diff against target: 235 lines (+154/-24)
3 files modified
src/include/server/mir/glib_main_loop_sources.h (+2/-1)
src/server/glib_main_loop_sources.cpp (+52/-23)
tests/unit-tests/test_glib_main_loop.cpp (+100/-0)
To merge this branch: bzr merge lp:~mir-team/mir/fix-delayed-sigaction-restore
Reviewer Review Type Date Requested Status
Mir development team Pending
Review via email: mp+249862@code.launchpad.net

Commit message

Keep sigaction alive through shared_ptr

Description of the change

This is the MP with the glib problems

To post a comment you must log in.

Unmerged revisions

2318. By Andreas Pokorny

Keep sig actions alive through shared_ptr

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/include/server/mir/glib_main_loop_sources.h'
2--- src/include/server/mir/glib_main_loop_sources.h 2015-02-12 02:11:25 +0000
3+++ src/include/server/mir/glib_main_loop_sources.h 2015-02-16 17:20:22 +0000
4@@ -104,6 +104,7 @@
5
6 private:
7 class SourceRegistration;
8+ class RegisteredSigAction;
9 struct HandlerElement
10 {
11 operator bool() const { return !!handler; }
12@@ -121,7 +122,7 @@
13 mir::Fd signal_write_fd;
14 mir::ThreadSafeList<HandlerElement> handlers;
15 std::mutex handled_signals_mutex;
16- std::unordered_map<int, struct sigaction> handled_signals;
17+ std::vector<std::shared_ptr<RegisteredSigAction>> handled_signals;
18 std::unique_ptr<SourceRegistration> source_registration;
19 };
20
21
22=== modified file 'src/server/glib_main_loop_sources.cpp'
23--- src/server/glib_main_loop_sources.cpp 2015-02-12 02:11:25 +0000
24+++ src/server/glib_main_loop_sources.cpp 2015-02-16 17:20:22 +0000
25@@ -24,6 +24,7 @@
26 #include <atomic>
27 #include <system_error>
28 #include <sstream>
29+#include <iostream>
30
31 #include <csignal>
32 #include <unistd.h>
33@@ -494,6 +495,56 @@
34
35 std::array<std::atomic<int>,10> md::SignalSources::SourceRegistration::write_fds;
36
37+struct md::SignalSources::RegisteredSigAction
38+{
39+ int sig;
40+ struct sigaction old_action;
41+
42+ RegisteredSigAction(RegisteredSigAction const&) = delete;
43+ RegisteredSigAction& operator=(RegisteredSigAction const&) = delete;
44+
45+ RegisteredSigAction(int sig)
46+ : sig{sig}
47+ {
48+ int const no_flags{0};
49+ struct sigaction new_action;
50+
51+ new_action.sa_handler = SourceRegistration::notify_sources_of_signal;
52+ sigfillset(&new_action.sa_mask);
53+ new_action.sa_flags = no_flags;
54+
55+ if (sigaction(sig, &new_action, &old_action) == -1)
56+ {
57+ std::stringstream msg;
58+ msg << "Failed to register action for signal " << sig;
59+ BOOST_THROW_EXCEPTION(
60+ std::system_error(errno, std::system_category(), msg.str()));
61+ }
62+ }
63+ ~RegisteredSigAction()
64+ {
65+ std::unique_lock<std::mutex> lock(sig_registry_mutex);
66+
67+ sigaction(sig, &old_action, nullptr);
68+ }
69+ static std::shared_ptr<RegisteredSigAction> register_action(int sig)
70+ {
71+ std::unique_lock<std::mutex> lock(sig_registry_mutex);
72+
73+ auto & entry = sig_registry[sig];
74+ auto ret = entry.lock();
75+ if (!ret)
76+ entry = ret = std::make_shared<RegisteredSigAction>(sig);
77+
78+ return ret;
79+ }
80+ static std::mutex sig_registry_mutex;
81+ static std::unordered_map<int, std::weak_ptr<RegisteredSigAction>> sig_registry;
82+};
83+
84+std::mutex md::SignalSources::RegisteredSigAction::sig_registry_mutex;
85+std::unordered_map<int, std::weak_ptr<md::SignalSources::RegisteredSigAction>> md::SignalSources::RegisteredSigAction::sig_registry;
86+
87 md::SignalSources::SignalSources(md::FdSources& fd_sources)
88 : fd_sources(fd_sources)
89 {
90@@ -521,9 +572,6 @@
91
92 md::SignalSources::~SignalSources()
93 {
94- for (auto const& handled : handled_signals)
95- sigaction(handled.first, &handled.second, nullptr);
96-
97 fd_sources.remove_all_owned_by(this);
98 }
99
100@@ -573,26 +621,7 @@
101 {
102 std::lock_guard<std::mutex> lock{handled_signals_mutex};
103
104- if (handled_signals.find(sig) != handled_signals.end())
105- return;
106-
107- static int const no_flags{0};
108- struct sigaction old_action;
109- struct sigaction new_action;
110-
111- new_action.sa_handler = SourceRegistration::notify_sources_of_signal;
112- sigfillset(&new_action.sa_mask);
113- new_action.sa_flags = no_flags;
114-
115- if (sigaction(sig, &new_action, &old_action) == -1)
116- {
117- std::stringstream msg;
118- msg << "Failed to register action for signal " << sig;
119- BOOST_THROW_EXCEPTION(
120- std::system_error(errno, std::system_category(), msg.str()));
121- }
122-
123- handled_signals.emplace(sig, old_action);
124+ handled_signals.emplace_back(RegisteredSigAction::register_action(sig));
125 }
126
127 void md::SignalSources::dispatch_signal(int sig)
128
129=== modified file 'tests/unit-tests/test_glib_main_loop.cpp'
130--- tests/unit-tests/test_glib_main_loop.cpp 2015-02-03 15:07:44 +0000
131+++ tests/unit-tests/test_glib_main_loop.cpp 2015-02-16 17:20:22 +0000
132@@ -1078,3 +1078,103 @@
133 // doesn't handle signals, and thus hangs forever.
134 execute_in_forked_process(this, [&] { check_mainloop_signal_handling(); });
135 }
136+
137+TEST(GLibMainLoopRaceTest, signal_handlers_do_not_race_for_destruction)
138+{
139+ using namespace ::testing;
140+
141+ for (int i = 0; i != 100; ++i)
142+ {
143+ int const signum = SIGUSR1;
144+ int handled_signum = 0;
145+ mt::Signal first_loop_running;
146+ mt::Signal first_loop_finished;
147+ mt::Signal first_loop_received_signal;
148+ mt::Signal second_loop_running;
149+ mt::Signal second_loop_finished;
150+
151+ {
152+ mir::GLibMainLoop first{std::make_shared<mir::time::SteadyClock>()};
153+ mir::GLibMainLoop second{std::make_shared<mir::time::SteadyClock>()};
154+
155+ first.register_signal_handler(
156+ {signum},
157+ [&](int)
158+ {
159+ });
160+
161+
162+ std::thread{
163+ [&]
164+ {
165+ int const owner{0};
166+ first.enqueue(&owner, [&] { first_loop_running.raise(); });
167+ first.run();
168+ first_loop_finished.raise();
169+ }}.detach();
170+
171+ std::thread{
172+ [&]
173+ {
174+ int const owner{0};
175+ second.enqueue(&owner, [&] { second_loop_running.raise(); });
176+ second.run();
177+ second_loop_finished.raise();
178+ }}.detach();
179+
180+ ASSERT_TRUE(first_loop_running.wait_for(std::chrono::seconds{5}));
181+ ASSERT_TRUE(second_loop_running.wait_for(std::chrono::seconds{5}));
182+
183+
184+ first.stop();
185+ second.stop();
186+
187+ EXPECT_TRUE(first_loop_finished.wait_for(std::chrono::seconds{5}));
188+ EXPECT_TRUE(second_loop_finished.wait_for(std::chrono::seconds{5}));
189+ }
190+
191+ {
192+ mir::GLibMainLoop first{std::make_shared<mir::time::SteadyClock>()};
193+ mir::GLibMainLoop second{std::make_shared<mir::time::SteadyClock>()};
194+ first.register_signal_handler(
195+ {signum},
196+ [&](int sig)
197+ {
198+ handled_signum = sig;
199+ first_loop_received_signal.raise();
200+ });
201+
202+ std::thread{
203+ [&]
204+ {
205+ int const owner{0};
206+ first.enqueue(&owner, [&] { first_loop_running.raise(); });
207+ first.run();
208+ first_loop_finished.raise();
209+ }}.detach();
210+
211+ std::thread{
212+ [&]
213+ {
214+ int const owner{0};
215+ second.enqueue(&owner, [&] { second_loop_running.raise(); });
216+ second.run();
217+ second_loop_finished.raise();
218+ }}.detach();
219+
220+
221+ ASSERT_TRUE(first_loop_running.wait_for(std::chrono::seconds{5}));
222+ ASSERT_TRUE(second_loop_running.wait_for(std::chrono::seconds{5}));
223+ kill(getpid(), signum);
224+
225+ ASSERT_TRUE(first_loop_received_signal.wait_for(std::chrono::seconds{5}));
226+ first.stop();
227+ second.stop();
228+
229+ EXPECT_TRUE(first_loop_finished.wait_for(std::chrono::seconds{5}));
230+ EXPECT_TRUE(second_loop_finished.wait_for(std::chrono::seconds{5}));
231+ }
232+
233+ EXPECT_THAT(handled_signum, Eq(signum));
234+ }
235+}

Subscribers

People subscribed via source and target branches