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"