Unity 8
UnixSignalHandler.cpp
1 /*
2  * Copyright (C) 2015 Canonical, Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 3, as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranties of
10  * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
11  * PURPOSE. See the GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Author: Marcus Tomlinson <marcus.tomlinson@canonical.com>
17  */
18 
19 #include "UnixSignalHandler.h"
20 
21 #include <QDebug>
22 
23 #include <csignal>
24 #include <sys/socket.h>
25 #include <unistd.h>
26 
27 int UnixSignalHandler::sighupFd[2];
28 int UnixSignalHandler::sigintFd[2];
29 int UnixSignalHandler::sigtermFd[2];
30 
31 UnixSignalHandler::UnixSignalHandler(const std::function<void()>& f, QObject *parent)
32  : QObject(parent),
33  m_func(f)
34 {
35  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighupFd))
36  {
37  qFatal("Couldn't create HUP socketpair");
38  }
39  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFd))
40  {
41  qFatal("Couldn't create INT socketpair");
42  }
43  if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigtermFd))
44  {
45  qFatal("Couldn't create TERM socketpair");
46  }
47 
48  m_socketNotifierHup = new QSocketNotifier(sighupFd[1], QSocketNotifier::Read, this);
49  connect(m_socketNotifierHup, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigHup);
50  m_socketNotifierInt = new QSocketNotifier(sigintFd[1], QSocketNotifier::Read, this);
51  connect(m_socketNotifierInt, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigInt);
52  m_socketNotifierTerm = new QSocketNotifier(sigtermFd[1], QSocketNotifier::Read, this);
53  connect(m_socketNotifierTerm, &QSocketNotifier::activated, this, &UnixSignalHandler::handleSigTerm);
54 }
55 
56 void UnixSignalHandler::hupSignalHandler(int)
57 {
58  char a = 1;
59  ::write(sighupFd[0], &a, sizeof(a));
60 }
61 
62 void UnixSignalHandler::intSignalHandler(int)
63 {
64  char a = 1;
65  ::write(sigintFd[0], &a, sizeof(a));
66 }
67 
68 void UnixSignalHandler::termSignalHandler(int)
69 {
70  char a = 1;
71  ::write(sigtermFd[0], &a, sizeof(a));
72 }
73 
74 int UnixSignalHandler::setupUnixSignalHandlers()
75 {
76  struct sigaction sighup, sigint, sigterm;
77 
78  sighup.sa_handler = UnixSignalHandler::hupSignalHandler;
79  sigemptyset(&sighup.sa_mask);
80  sighup.sa_flags = SA_RESTART;
81 
82  if (sigaction(SIGHUP, &sighup, 0) > 0)
83  {
84  return 1;
85  }
86 
87  sigint.sa_handler = UnixSignalHandler::intSignalHandler;
88  sigemptyset(&sigint.sa_mask);
89  sigint.sa_flags = SA_RESTART;
90 
91  if (sigaction(SIGINT, &sigint, 0) > 0)
92  {
93  return 2;
94  }
95 
96  sigterm.sa_handler = UnixSignalHandler::termSignalHandler;
97  sigemptyset(&sigterm.sa_mask);
98  sigterm.sa_flags = SA_RESTART;
99 
100  if (sigaction(SIGTERM, &sigterm, 0) > 0)
101  {
102  return 3;
103  }
104 
105  return 0;
106 }
107 
108 void UnixSignalHandler::handleSigHup()
109 {
110  m_socketNotifierHup->setEnabled(false);
111  char tmp;
112  ::read(sighupFd[1], &tmp, sizeof(tmp));
113 
114  m_func();
115 
116  m_socketNotifierHup->setEnabled(true);
117 }
118 
119 void UnixSignalHandler::handleSigInt()
120 {
121  m_socketNotifierInt->setEnabled(false);
122  char tmp;
123  ::read(sigintFd[1], &tmp, sizeof(tmp));
124 
125  m_func();
126 
127  m_socketNotifierInt->setEnabled(true);
128 }
129 
130 void UnixSignalHandler::handleSigTerm()
131 {
132  m_socketNotifierTerm->setEnabled(false);
133  char tmp;
134  ::read(sigtermFd[1], &tmp, sizeof(tmp));
135 
136  m_func();
137 
138  m_socketNotifierTerm->setEnabled(true);
139 }