libzypp 17.37.17
unixsignalsource.cpp
Go to the documentation of this file.
1#include "unixsignalsource.h"
6#include <unordered_map>
7
8#include <sys/signalfd.h>
9#include <signal.h>
10
11namespace zyppng {
12
14 {
16 public:
18 ::sigemptyset ( &_orgSigMask );
19 pthread_sigmask (SIG_SETMASK, nullptr, &_orgSigMask);
20 }
21
22 sigset_t _orgSigMask;
24 std::unordered_map<int, int> _signalRefCount;
25 Signal<void (int)> _sigReceived;
26 };
27
29
33
35 {
36 Z_D();
37 // restore the original sigmask
38 pthread_sigmask (SIG_SETMASK, &d->_orgSigMask, nullptr);
39 }
40
41 UnixSignalSourceRef UnixSignalSource::create()
42 {
43 return UnixSignalSourceRef( new UnixSignalSource() );
44 }
45
47 {
48 Z_D();
49
50 if ( d->_signalRefCount.count(signum) != 0 && d->_signalRefCount[signum] > 0 ) {
51 // we already handle this signal, just increase refcount
52 d->_signalRefCount[signum]++;
53 } else {
54
55 const auto &handleError = [&]() {
56 d->_signalRefCount.erase ( signum );
57 return false;
58 };
59
60 // add the signal to our map
61 d->_signalRefCount[signum] = 1;
62
63 sigset_t sigMask;
64 sigemptyset (&sigMask );
65
66 // add all the signals we monitor to our set so we can update the signalfd correctly
67 for ( const auto &sig : d->_signalRefCount ) {
68 sigaddset(&sigMask, sig.first);
69 }
70
71 // signalfd signals should be blocked
72 // man page says: The set of blocked signals is the union of the current set and the set argument.
73 // so we should not accidentially delete other blocks done by the application
74 if (pthread_sigmask (SIG_BLOCK, &sigMask, NULL) == -1) {
75 return handleError();
76 }
77
78
79 // set or update our signal fd
80 zypp::AutoFD aFd = signalfd ( d->_signalFd, &sigMask, SFD_NONBLOCK | SFD_CLOEXEC );
81 if ( aFd == -1 ){
82 return handleError();
83 }
84
85 if ( d->_signalFd != aFd ) {
86 d->_signalFd = aFd;
87 } else {
88 aFd.resetDispose ();
89 }
91 }
92 return true;
93 }
94
96 {
97 Z_D();
98 if ( !d->_signalRefCount.count(signum) || d->_signalRefCount[signum] == 0 ) {
99 return true;
100 }
101 d->_signalRefCount[signum]--;
102
103 if ( d->_signalRefCount[signum] <= 0 ) {
104
105 d->_signalRefCount.erase(signum);
106
107 // remove the signal from our fd
108 sigset_t sigMask;
109 sigemptyset ( &sigMask );
110 for ( const auto &sig : d->_signalRefCount ) {
111 sigaddset(&sigMask, sig.first);
112 }
113
114 auto res = signalfd ( d->_signalFd, &sigMask, SFD_NONBLOCK | SFD_CLOEXEC );
115 if ( res == -1 ) {
116 WAR << "Failed to update signalfd with errno: " << zypp::Errno() << std::endl;
117 return false;
118 }
119
120 // unblock the signal
121 sigemptyset ( &sigMask );
122 sigaddset(&sigMask, signum);
123 pthread_sigmask(SIG_UNBLOCK, &sigMask, NULL);
124 }
125
126 if ( d->_signalRefCount.size () == 0 ) {
127 removeFdWatch ( d->_signalFd );
128 d->_signalFd = -1;
129 }
130 return true;
131 }
132
134 {
135 return d_func()->_sigReceived;
136 }
137
138 void zyppng::UnixSignalSource::onFdReady( int fd, int events )
139 {
140 Z_D();
141 struct signalfd_siginfo sfd_si;
142 if ( read(fd, &sfd_si, sizeof(sfd_si)) == -1 ) {
143 WAR << "Failed to read from signalfd" << std::endl;
144 return;
145 }
146
147 if ( d->_signalRefCount.count ( sfd_si.ssi_signo ))
148 d->_sigReceived.emit( sfd_si.ssi_signo );
149 else
150 WAR << "Received unexpected UNIX signal on signalFD: " << sfd_si.ssi_signo << std::endl;
151 }
152
154 {}
155
156} // namespace zyppng
void resetDispose()
Set no dispose function.
Convenience errno wrapper.
Definition Errno.h:26
AbstractEventSourcePrivate(AbstractEventSource &p)
void updateFdWatch(int fd, int mode)
std::unordered_map< int, int > _signalRefCount
UnixSignalSourcePrivate(UnixSignalSource &p)
void onFdReady(int fd, int events) override
static UnixSignalSourceRef create()
void onSignal(int signal) override
SignalProxy< void(int signum)> sigReceived()
AutoDispose<int> calling close
#define WAR
Definition Logger.h:101
#define ZYPP_IMPL_PRIVATE(Class)
Definition zyppglobal.h:92
#define Z_D()
Definition zyppglobal.h:105
#define ZYPP_DECLARE_PUBLIC(Class)
Definition zyppglobal.h:98