File indexing completed on 2025-01-05 04:37:31

0001 /*
0002     SPDX-FileCopyrightText: 2010 Joris Guisson <joris.guisson@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef BT_SIGNALCATCHER_H
0008 #define BT_SIGNALCATCHER_H
0009 
0010 #ifndef Q_WS_WIN
0011 
0012 #include <QObject>
0013 #include <QSocketNotifier>
0014 #include <ktorrent_export.h>
0015 #include <setjmp.h>
0016 #include <signal.h>
0017 #include <util/error.h>
0018 
0019 namespace bt
0020 {
0021 /**
0022     Variable used to jump from the SIGBUS handler back to the place which triggered the SIGBUS.
0023 */
0024 extern KTORRENT_EXPORT sigjmp_buf sigbus_env;
0025 
0026 /**
0027  * Protects against SIGBUS errors when doing mmapped IO
0028  **/
0029 class KTORRENT_EXPORT BusErrorGuard
0030 {
0031 public:
0032     BusErrorGuard();
0033     virtual ~BusErrorGuard();
0034 };
0035 
0036 /**
0037     Exception throw when a SIGBUS is caught.
0038 */
0039 class KTORRENT_EXPORT BusError : public bt::Error
0040 {
0041 public:
0042     BusError(bool write_operation);
0043     ~BusError() override;
0044 
0045     /// Whether or not the SIGBUS was triggered by a write operation
0046     bool write_operation;
0047 };
0048 
0049 /**
0050  * Class to handle UNIX signals (not Qt ones)
0051  */
0052 class KTORRENT_EXPORT SignalCatcher : public QObject
0053 {
0054     Q_OBJECT
0055 public:
0056     SignalCatcher(QObject *parent = nullptr);
0057     ~SignalCatcher() override;
0058 
0059     /**
0060      * Catch a UNIX signal
0061      * @param sig SIGINT, SIGTERM or some other signal
0062      * @return true upon success, false otherwise
0063      **/
0064     bool catchSignal(int sig);
0065 
0066 private Q_SLOTS:
0067     void handleInput(int fd);
0068 
0069 private:
0070     static void signalHandler(int sig, siginfo_t *siginfo, void *ptr);
0071 
0072 Q_SIGNALS:
0073     /// Emitted when a
0074     void triggered();
0075 
0076 private:
0077     QSocketNotifier *notifier;
0078     static int signal_received_pipe[2];
0079 };
0080 }
0081 
0082 /// Before writing to memory mapped data, call this macro to ensure that SIGBUS signals are caught and properly dealt with
0083 #define BUS_ERROR_WPROTECT()                                                                                                                                   \
0084     BusErrorGuard bus_error_guard;                                                                                                                             \
0085     if (sigsetjmp(bt::sigbus_env, 1))                                                                                                                          \
0086     throw bt::BusError(true)
0087 
0088 /// Before reading from memory mapped data, call this macro to ensure that SIGBUS signals are caught and properly dealt with
0089 #define BUS_ERROR_RPROTECT()                                                                                                                                   \
0090     BusErrorGuard bus_error_guard;                                                                                                                             \
0091     if (sigsetjmp(bt::sigbus_env, 1))                                                                                                                          \
0092     throw bt::BusError(false)
0093 
0094 #endif
0095 
0096 #endif // BT_SIGNALCATCHER_H