libzypp  17.32.5
unixsignalsource.cpp
Go to the documentation of this file.
1 #include "unixsignalsource.h"
4 #include <zypp-core/base/Errno.h>
6 #include <unordered_map>
7 
8 #include <sys/signalfd.h>
9 #include <signal.h>
10 
11 namespace 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;
26  };
27 
29 
31  {
32  }
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 
46  bool UnixSignalSource::addSignal(int signum )
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 onSignal(int signal) override
void onFdReady(int fd, int events) override
SignalProxy< void(int signum)> sigReceived()
static UnixSignalSourceRef create()
Convenience errno wrapper.
Definition: Errno.h:25
std::map< std::string, std::string > read(const Pathname &_path)
Read sysconfig file path_r and return (key,valye) pairs.
Definition: sysconfig.cc:34
AutoDispose<int> calling ::close
Definition: AutoDispose.h:309
#define Z_D()
Definition: zyppglobal.h:104
std::unordered_map< int, int > _signalRefCount
void updateFdWatch(int fd, int mode)
#define WAR
Definition: Logger.h:97
UnixSignalSourcePrivate(UnixSignalSource &p)
void resetDispose()
Set no dispose function.
Definition: AutoDispose.h:171
ZYPP_IMPL_PRIVATE(UnixSignalSource)
#define ZYPP_DECLARE_PUBLIC(Class)
Definition: zyppglobal.h:97
bool removeSignal(int signum)