KCoreAddons

ksignalhandler.cpp
1/*
2 SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "ksignalhandler.h"
8#include "kcoreaddons_debug.h"
9#include <QSocketNotifier>
10#include <QTimer>
11
12#ifndef Q_OS_WIN
13#include <cerrno>
14#include <fcntl.h>
15#include <signal.h>
16#include <sys/socket.h>
17#include <unistd.h>
18#endif
19
20class KSignalHandlerPrivate : public QObject
21{
22public:
23 static void signalHandler(int signal);
24 void handleSignal();
25
26 QSet<int> m_signalsRegistered;
27 static int signalFd[2];
28 QSocketNotifier *m_handler = nullptr;
29
31};
32int KSignalHandlerPrivate::signalFd[2];
33
34KSignalHandler::KSignalHandler()
35 : d(new KSignalHandlerPrivate)
36{
37 d->q = this;
38#ifndef Q_OS_WIN
39 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, KSignalHandlerPrivate::signalFd)) {
40 qCWarning(KCOREADDONS_DEBUG) << "Couldn't create a socketpair";
41 return;
42 }
43
44 // ensure the sockets are not leaked to child processes, SOCK_CLOEXEC not supported on macOS
45 fcntl(KSignalHandlerPrivate::signalFd[0], F_SETFD, FD_CLOEXEC);
46 fcntl(KSignalHandlerPrivate::signalFd[1], F_SETFD, FD_CLOEXEC);
47
48 QTimer::singleShot(0, [this] {
49 d->m_handler = new QSocketNotifier(KSignalHandlerPrivate::signalFd[1], QSocketNotifier::Read, this);
50 connect(d->m_handler, &QSocketNotifier::activated, d.get(), &KSignalHandlerPrivate::handleSignal);
51 });
52#endif
53}
54
55KSignalHandler::~KSignalHandler()
56{
57#ifndef Q_OS_WIN
58 for (int sig : std::as_const(d->m_signalsRegistered)) {
59 signal(sig, nullptr);
60 }
61 close(KSignalHandlerPrivate::signalFd[0]);
62 close(KSignalHandlerPrivate::signalFd[1]);
63#endif
64}
65
66void KSignalHandler::watchSignal(int signalToTrack)
67{
68 d->m_signalsRegistered.insert(signalToTrack);
69#ifndef Q_OS_WIN
70 signal(signalToTrack, KSignalHandlerPrivate::signalHandler);
71#endif
72}
73
74void KSignalHandlerPrivate::signalHandler(int signal)
75{
76#ifndef Q_OS_WIN
77 const int ret = ::write(signalFd[0], &signal, sizeof(signal));
78 if (ret != sizeof(signal)) {
79 qCWarning(KCOREADDONS_DEBUG) << "signalHandler couldn't write for signal" << strsignal(signal) << " Got error:" << strerror(errno);
80 }
81#else
82 Q_UNUSED(signal);
83#endif
84}
85
86void KSignalHandlerPrivate::handleSignal()
87{
88#ifndef Q_OS_WIN
89 m_handler->setEnabled(false);
90 int signal;
91 const int ret = ::read(KSignalHandlerPrivate::signalFd[1], &signal, sizeof(signal));
92 if (ret != sizeof(signal)) {
93 qCWarning(KCOREADDONS_DEBUG) << "handleSignal couldn't read signal for fd" << KSignalHandlerPrivate::signalFd[1] << " Got error:" << strerror(errno);
94 return;
95 }
96 m_handler->setEnabled(true);
97
98 Q_EMIT q->signalReceived(signal);
99#endif
100}
101
103{
104 static KSignalHandler s_self;
105 return &s_self;
106}
107
108#include "moc_ksignalhandler.cpp"
Allows getting ANSI C signals and forward them onto the Qt eventloop.
void watchSignal(int signal)
Adds signal to be watched for.
static KSignalHandler * self()
Fetches an instance we can use to register our signals.
void signalReceived(int signal)
Notifies that signal is emitted.
const QList< QKeySequence > & close()
Q_EMITQ_EMIT
void activated(QSocketDescriptor socket, QSocketNotifier::Type type)
void setEnabled(bool enable)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Dec 6 2024 12:00:44 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.