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
=== modified file 'src/include/server/mir/glib_main_loop_sources.h'
--- src/include/server/mir/glib_main_loop_sources.h 2015-02-12 02:11:25 +0000
+++ src/include/server/mir/glib_main_loop_sources.h 2015-02-16 17:20:22 +0000
@@ -104,6 +104,7 @@
104104
105private:105private:
106 class SourceRegistration;106 class SourceRegistration;
107 class RegisteredSigAction;
107 struct HandlerElement108 struct HandlerElement
108 {109 {
109 operator bool() const { return !!handler; }110 operator bool() const { return !!handler; }
@@ -121,7 +122,7 @@
121 mir::Fd signal_write_fd;122 mir::Fd signal_write_fd;
122 mir::ThreadSafeList<HandlerElement> handlers;123 mir::ThreadSafeList<HandlerElement> handlers;
123 std::mutex handled_signals_mutex;124 std::mutex handled_signals_mutex;
124 std::unordered_map<int, struct sigaction> handled_signals;125 std::vector<std::shared_ptr<RegisteredSigAction>> handled_signals;
125 std::unique_ptr<SourceRegistration> source_registration;126 std::unique_ptr<SourceRegistration> source_registration;
126};127};
127128
128129
=== modified file 'src/server/glib_main_loop_sources.cpp'
--- src/server/glib_main_loop_sources.cpp 2015-02-12 02:11:25 +0000
+++ src/server/glib_main_loop_sources.cpp 2015-02-16 17:20:22 +0000
@@ -24,6 +24,7 @@
24#include <atomic>24#include <atomic>
25#include <system_error>25#include <system_error>
26#include <sstream>26#include <sstream>
27#include <iostream>
2728
28#include <csignal>29#include <csignal>
29#include <unistd.h>30#include <unistd.h>
@@ -494,6 +495,56 @@
494495
495std::array<std::atomic<int>,10> md::SignalSources::SourceRegistration::write_fds;496std::array<std::atomic<int>,10> md::SignalSources::SourceRegistration::write_fds;
496497
498struct md::SignalSources::RegisteredSigAction
499{
500 int sig;
501 struct sigaction old_action;
502
503 RegisteredSigAction(RegisteredSigAction const&) = delete;
504 RegisteredSigAction& operator=(RegisteredSigAction const&) = delete;
505
506 RegisteredSigAction(int sig)
507 : sig{sig}
508 {
509 int const no_flags{0};
510 struct sigaction new_action;
511
512 new_action.sa_handler = SourceRegistration::notify_sources_of_signal;
513 sigfillset(&new_action.sa_mask);
514 new_action.sa_flags = no_flags;
515
516 if (sigaction(sig, &new_action, &old_action) == -1)
517 {
518 std::stringstream msg;
519 msg << "Failed to register action for signal " << sig;
520 BOOST_THROW_EXCEPTION(
521 std::system_error(errno, std::system_category(), msg.str()));
522 }
523 }
524 ~RegisteredSigAction()
525 {
526 std::unique_lock<std::mutex> lock(sig_registry_mutex);
527
528 sigaction(sig, &old_action, nullptr);
529 }
530 static std::shared_ptr<RegisteredSigAction> register_action(int sig)
531 {
532 std::unique_lock<std::mutex> lock(sig_registry_mutex);
533
534 auto & entry = sig_registry[sig];
535 auto ret = entry.lock();
536 if (!ret)
537 entry = ret = std::make_shared<RegisteredSigAction>(sig);
538
539 return ret;
540 }
541 static std::mutex sig_registry_mutex;
542 static std::unordered_map<int, std::weak_ptr<RegisteredSigAction>> sig_registry;
543};
544
545std::mutex md::SignalSources::RegisteredSigAction::sig_registry_mutex;
546std::unordered_map<int, std::weak_ptr<md::SignalSources::RegisteredSigAction>> md::SignalSources::RegisteredSigAction::sig_registry;
547
497md::SignalSources::SignalSources(md::FdSources& fd_sources)548md::SignalSources::SignalSources(md::FdSources& fd_sources)
498 : fd_sources(fd_sources)549 : fd_sources(fd_sources)
499{550{
@@ -521,9 +572,6 @@
521572
522md::SignalSources::~SignalSources()573md::SignalSources::~SignalSources()
523{574{
524 for (auto const& handled : handled_signals)
525 sigaction(handled.first, &handled.second, nullptr);
526
527 fd_sources.remove_all_owned_by(this);575 fd_sources.remove_all_owned_by(this);
528}576}
529577
@@ -573,26 +621,7 @@
573{621{
574 std::lock_guard<std::mutex> lock{handled_signals_mutex};622 std::lock_guard<std::mutex> lock{handled_signals_mutex};
575623
576 if (handled_signals.find(sig) != handled_signals.end())624 handled_signals.emplace_back(RegisteredSigAction::register_action(sig));
577 return;
578
579 static int const no_flags{0};
580 struct sigaction old_action;
581 struct sigaction new_action;
582
583 new_action.sa_handler = SourceRegistration::notify_sources_of_signal;
584 sigfillset(&new_action.sa_mask);
585 new_action.sa_flags = no_flags;
586
587 if (sigaction(sig, &new_action, &old_action) == -1)
588 {
589 std::stringstream msg;
590 msg << "Failed to register action for signal " << sig;
591 BOOST_THROW_EXCEPTION(
592 std::system_error(errno, std::system_category(), msg.str()));
593 }
594
595 handled_signals.emplace(sig, old_action);
596}625}
597626
598void md::SignalSources::dispatch_signal(int sig)627void md::SignalSources::dispatch_signal(int sig)
599628
=== modified file 'tests/unit-tests/test_glib_main_loop.cpp'
--- tests/unit-tests/test_glib_main_loop.cpp 2015-02-03 15:07:44 +0000
+++ tests/unit-tests/test_glib_main_loop.cpp 2015-02-16 17:20:22 +0000
@@ -1078,3 +1078,103 @@
1078 // doesn't handle signals, and thus hangs forever.1078 // doesn't handle signals, and thus hangs forever.
1079 execute_in_forked_process(this, [&] { check_mainloop_signal_handling(); });1079 execute_in_forked_process(this, [&] { check_mainloop_signal_handling(); });
1080}1080}
1081
1082TEST(GLibMainLoopRaceTest, signal_handlers_do_not_race_for_destruction)
1083{
1084 using namespace ::testing;
1085
1086 for (int i = 0; i != 100; ++i)
1087 {
1088 int const signum = SIGUSR1;
1089 int handled_signum = 0;
1090 mt::Signal first_loop_running;
1091 mt::Signal first_loop_finished;
1092 mt::Signal first_loop_received_signal;
1093 mt::Signal second_loop_running;
1094 mt::Signal second_loop_finished;
1095
1096 {
1097 mir::GLibMainLoop first{std::make_shared<mir::time::SteadyClock>()};
1098 mir::GLibMainLoop second{std::make_shared<mir::time::SteadyClock>()};
1099
1100 first.register_signal_handler(
1101 {signum},
1102 [&](int)
1103 {
1104 });
1105
1106
1107 std::thread{
1108 [&]
1109 {
1110 int const owner{0};
1111 first.enqueue(&owner, [&] { first_loop_running.raise(); });
1112 first.run();
1113 first_loop_finished.raise();
1114 }}.detach();
1115
1116 std::thread{
1117 [&]
1118 {
1119 int const owner{0};
1120 second.enqueue(&owner, [&] { second_loop_running.raise(); });
1121 second.run();
1122 second_loop_finished.raise();
1123 }}.detach();
1124
1125 ASSERT_TRUE(first_loop_running.wait_for(std::chrono::seconds{5}));
1126 ASSERT_TRUE(second_loop_running.wait_for(std::chrono::seconds{5}));
1127
1128
1129 first.stop();
1130 second.stop();
1131
1132 EXPECT_TRUE(first_loop_finished.wait_for(std::chrono::seconds{5}));
1133 EXPECT_TRUE(second_loop_finished.wait_for(std::chrono::seconds{5}));
1134 }
1135
1136 {
1137 mir::GLibMainLoop first{std::make_shared<mir::time::SteadyClock>()};
1138 mir::GLibMainLoop second{std::make_shared<mir::time::SteadyClock>()};
1139 first.register_signal_handler(
1140 {signum},
1141 [&](int sig)
1142 {
1143 handled_signum = sig;
1144 first_loop_received_signal.raise();
1145 });
1146
1147 std::thread{
1148 [&]
1149 {
1150 int const owner{0};
1151 first.enqueue(&owner, [&] { first_loop_running.raise(); });
1152 first.run();
1153 first_loop_finished.raise();
1154 }}.detach();
1155
1156 std::thread{
1157 [&]
1158 {
1159 int const owner{0};
1160 second.enqueue(&owner, [&] { second_loop_running.raise(); });
1161 second.run();
1162 second_loop_finished.raise();
1163 }}.detach();
1164
1165
1166 ASSERT_TRUE(first_loop_running.wait_for(std::chrono::seconds{5}));
1167 ASSERT_TRUE(second_loop_running.wait_for(std::chrono::seconds{5}));
1168 kill(getpid(), signum);
1169
1170 ASSERT_TRUE(first_loop_received_signal.wait_for(std::chrono::seconds{5}));
1171 first.stop();
1172 second.stop();
1173
1174 EXPECT_TRUE(first_loop_finished.wait_for(std::chrono::seconds{5}));
1175 EXPECT_TRUE(second_loop_finished.wait_for(std::chrono::seconds{5}));
1176 }
1177
1178 EXPECT_THAT(handled_signum, Eq(signum));
1179 }
1180}

Subscribers

People subscribed via source and target branches