File indexing completed on 2024-05-19 03:56:25

0001 /*
0002     SPDX-FileCopyrightText: 2021 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "ksignalhandler.h"
0008 #include "kcoreaddons_debug.h"
0009 #include <QSocketNotifier>
0010 #include <QTimer>
0011 
0012 #ifndef Q_OS_WIN
0013 #include <cerrno>
0014 #include <fcntl.h>
0015 #include <signal.h>
0016 #include <sys/socket.h>
0017 #include <unistd.h>
0018 #endif
0019 
0020 class KSignalHandlerPrivate : public QObject
0021 {
0022 public:
0023     static void signalHandler(int signal);
0024     void handleSignal();
0025 
0026     QSet<int> m_signalsRegistered;
0027     static int signalFd[2];
0028     QSocketNotifier *m_handler = nullptr;
0029 
0030     KSignalHandler *q;
0031 };
0032 int KSignalHandlerPrivate::signalFd[2];
0033 
0034 KSignalHandler::KSignalHandler()
0035     : d(new KSignalHandlerPrivate)
0036 {
0037     d->q = this;
0038 #ifndef Q_OS_WIN
0039     if (::socketpair(AF_UNIX, SOCK_STREAM, 0, KSignalHandlerPrivate::signalFd)) {
0040         qCWarning(KCOREADDONS_DEBUG) << "Couldn't create a socketpair";
0041         return;
0042     }
0043 
0044     // ensure the sockets are not leaked to child processes, SOCK_CLOEXEC not supported on macOS
0045     fcntl(KSignalHandlerPrivate::signalFd[0], F_SETFD, FD_CLOEXEC);
0046     fcntl(KSignalHandlerPrivate::signalFd[1], F_SETFD, FD_CLOEXEC);
0047 
0048     QTimer::singleShot(0, [this] {
0049         d->m_handler = new QSocketNotifier(KSignalHandlerPrivate::signalFd[1], QSocketNotifier::Read, this);
0050         connect(d->m_handler, &QSocketNotifier::activated, d.get(), &KSignalHandlerPrivate::handleSignal);
0051     });
0052 #endif
0053 }
0054 
0055 KSignalHandler::~KSignalHandler()
0056 {
0057 #ifndef Q_OS_WIN
0058     for (int sig : std::as_const(d->m_signalsRegistered)) {
0059         signal(sig, nullptr);
0060     }
0061     close(KSignalHandlerPrivate::signalFd[0]);
0062     close(KSignalHandlerPrivate::signalFd[1]);
0063 #endif
0064 }
0065 
0066 void KSignalHandler::watchSignal(int signalToTrack)
0067 {
0068     d->m_signalsRegistered.insert(signalToTrack);
0069 #ifndef Q_OS_WIN
0070     signal(signalToTrack, KSignalHandlerPrivate::signalHandler);
0071 #endif
0072 }
0073 
0074 void KSignalHandlerPrivate::signalHandler(int signal)
0075 {
0076 #ifndef Q_OS_WIN
0077     const int ret = ::write(signalFd[0], &signal, sizeof(signal));
0078     if (ret != sizeof(signal)) {
0079         qCWarning(KCOREADDONS_DEBUG) << "signalHandler couldn't write for signal" << strsignal(signal) << " Got error:" << strerror(errno);
0080     }
0081 #endif
0082 }
0083 
0084 void KSignalHandlerPrivate::handleSignal()
0085 {
0086 #ifndef Q_OS_WIN
0087     m_handler->setEnabled(false);
0088     int signal;
0089     const int ret = ::read(KSignalHandlerPrivate::signalFd[1], &signal, sizeof(signal));
0090     if (ret != sizeof(signal)) {
0091         qCWarning(KCOREADDONS_DEBUG) << "handleSignal couldn't read signal for fd" << KSignalHandlerPrivate::signalFd[1] << " Got error:" << strerror(errno);
0092         return;
0093     }
0094     m_handler->setEnabled(true);
0095 
0096     Q_EMIT q->signalReceived(signal);
0097 #endif
0098 }
0099 
0100 KSignalHandler *KSignalHandler::self()
0101 {
0102     static KSignalHandler s_self;
0103     return &s_self;
0104 }
0105 
0106 #include "moc_ksignalhandler.cpp"