1/*
2 SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-only
5*/
6
7#include "ksignalhandler.h"
8#include "kcoreaddons_debug.h"
9#include <QSocketNotifier>
10
11#ifndef Q_OS_WIN
12#include <cerrno>
13#include <signal.h>
14#include <sys/socket.h>
15#include <unistd.h>
16#endif
17
18class KSignalHandlerPrivate : public QObject
19{
20public:
21 static void signalHandler(int signal);
22 void handleSignal();
23
24 QSet<int> m_signalsRegistered;
25 static int signalFd[2];
26 QSocketNotifier *m_handler = nullptr;
27
28 KSignalHandler *q;
29};
30int KSignalHandlerPrivate::signalFd[2];
31
32KSignalHandler::KSignalHandler()
33 : d(new KSignalHandlerPrivate)
34{
35 d->q = this;
36#ifndef Q_OS_WIN
37 if (::socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, protocol: 0, fds: KSignalHandlerPrivate::signalFd)) {
38 qCWarning(KCOREADDONS_DEBUG) << "Couldn't create a socketpair";
39 return;
40 }
41
42 d->m_handler = new QSocketNotifier(KSignalHandlerPrivate::signalFd[1], QSocketNotifier::Read, this);
43 connect(sender: d->m_handler, signal: &QSocketNotifier::activated, receiver: d.get(), slot: &KSignalHandlerPrivate::handleSignal);
44#endif
45}
46
47KSignalHandler::~KSignalHandler()
48{
49#ifndef Q_OS_WIN
50 for (int sig : std::as_const(t&: d->m_signalsRegistered)) {
51 signal(sig: sig, handler: nullptr);
52 }
53 close(fd: KSignalHandlerPrivate::signalFd[0]);
54 close(fd: KSignalHandlerPrivate::signalFd[1]);
55#endif
56}
57
58void KSignalHandler::watchSignal(int signalToTrack)
59{
60 d->m_signalsRegistered.insert(value: signalToTrack);
61#ifndef Q_OS_WIN
62 signal(sig: signalToTrack, handler: KSignalHandlerPrivate::signalHandler);
63#endif
64}
65
66void KSignalHandlerPrivate::signalHandler(int signal)
67{
68#ifndef Q_OS_WIN
69 const int ret = ::write(fd: signalFd[0], buf: &signal, n: sizeof(signal));
70 if (ret != sizeof(signal)) {
71 qCWarning(KCOREADDONS_DEBUG) << "signalHandler couldn't write for signal" << strsignal(sig: signal) << " Got error:" << strerror(errno);
72 }
73#endif
74}
75
76void KSignalHandlerPrivate::handleSignal()
77{
78#ifndef Q_OS_WIN
79 m_handler->setEnabled(false);
80 int signal;
81 const int ret = ::read(fd: KSignalHandlerPrivate::signalFd[1], buf: &signal, nbytes: sizeof(signal));
82 if (ret != sizeof(signal)) {
83 qCWarning(KCOREADDONS_DEBUG) << "handleSignal couldn't read signal for fd" << KSignalHandlerPrivate::signalFd[1] << " Got error:" << strerror(errno);
84 return;
85 }
86 m_handler->setEnabled(true);
87
88 Q_EMIT q->signalReceived(signal);
89#endif
90}
91
92KSignalHandler *KSignalHandler::self()
93{
94 static KSignalHandler s_self;
95 return &s_self;
96}
97

source code of kcoreaddons/src/lib/util/ksignalhandler.cpp