libzypp  17.35.19
signals.h
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \----------------------------------------------------------------------/
9 *
10 * This file contains private API, this might break at any time between releases.
11 * You have been warned!
12 *
13 */
14 #ifndef ZYPP_NG_BASE_SIGNALS_H_INCLUDED
15 #define ZYPP_NG_BASE_SIGNALS_H_INCLUDED
16 
17 #ifdef ENABLE_SYWU
18 #include <sywu/signal.hpp>
19 #else
20 #include <sigc++/trackable.h>
21 #include <sigc++/signal.h>
22 #include <sigc++/connection.h>
23 #include <sigc++/visit_each.h>
24 #include <sigc++/adaptors/adaptors.h>
25 #endif
26 #include <memory>
27 #include <utility>
28 #include <cassert>
31 
143 namespace zyppng {
144 
145 
150  template <class R, class... T>
151  class Signal;
152 
159  template <class SignalHost, typename ReturnType, typename... Arguments>
160  class MemSignal;
161 
162  class Base;
163  class BasePrivate;
164 
165 #ifdef ENABLE_SYWU
166  using connection = sywu::Connection;
167 
168  template <class R, class... T>
169  using SignalProxyBase = sywu::SignalConceptImpl<R(T...)>;
170 
171  template <class R, class... T>
172  class Signal<R(T...)> : public sywu::Signal<R(T...)>
173  { };
174 
175  template <class SignalHost, typename ReturnType, typename... Arguments>
176  class MemSignal<SignalHost, ReturnType(Arguments...)> : public sywu::MemberSignal<SignalHost, ReturnType(Arguments...)>
177  { };
178 
179 #else
182  using sigc::track_obj;
183 
184  template <class R, class... T>
185  using SignalProxyBase = sigc::signal<R(T...)>;
186 
187 
188  template <class R, class... T>
189  class Signal<R(T...)> : public sigc::signal<R(T...)>
190  {
191  public:
193  assert(this->impl()->exec_count_ == 0);
194  if ( this->impl()->exec_count_ > 0 ) {
195  WAR << "Deleting Signal during emission, this is usually a BUG, Slots will be blocked to prevent SIGSEGV." << std::endl;
196 #ifdef LIBZYPP_USE_SIGC_BLOCK_WORKAROUND
197  // older sigc versions will segfault if clear() is called in signal emission
198  // we use block instead in those cases which seems to have the same result
199  // since we do not use the slot instances explicitely that _should_ not have side effects
200  // https://bugzilla.gnome.org/show_bug.cgi?id=784550
201  this->block();
202  return;
203 #endif
204  }
205 
206  this->clear();
207  }
208  };
209 
210  template <class SignalHost, typename ReturnType, typename... Arguments>
211  class MemSignal<SignalHost, ReturnType(Arguments...)> : public sigc::signal<ReturnType(Arguments...)>
212  {
213  public:
214  MemSignal ( SignalHost &host ) : _host(host) {}
215 
217 
218  assert(this->impl()->exec_count_ == 0);
219  if ( this->impl()->exec_count_ > 0 ) {
220  WAR << "Deleting MemSignal during emission, this is definitely a BUG, Slots will be blocked to prevent SIGSEGV." << std::endl;
221 #ifdef LIBZYPP_USE_SIGC_BLOCK_WORKAROUND
222  // older sigc versions will segfault if clear() is called in signal emission
223  // we use block instead in those cases which seems to have the same result
224  // since we do not use the slot instances explicitely that _should_ not have side effects
225  // https://bugzilla.gnome.org/show_bug.cgi?id=784550
226  this->block();
227  return;
228 #endif
229  }
230  this->clear();
231  }
232 
233  template<typename... Args>
234  auto emit( Args&& ...arg ) const {
235  auto ref = _host.shared_from_this();
236  return sigc::signal<ReturnType(Arguments...)>::emit( std::forward<Args>(arg)...);
237  }
238 
239  template<typename... Args>
240  auto operator()( Args&& ...arg ) const {
241  //auto ref = _host.shared_from_this();
242  return sigc::signal<ReturnType(Arguments...)>::operator()( std::forward<Args>(arg)...);
243  }
244 
245  private:
246  SignalHost &_host;
247  };
248 
249  namespace internal {
250 
255  template <typename T>
256  inline auto lock_shared_makeLock ( const T& locker ) {
257  try {
258  if constexpr ( std::is_base_of_v<BasePrivate, T> ) {
259  return locker.z_func()->shared_from_this();
260  } else {
261  return locker.shared_from_this();
262  }
263  } catch ( const std::bad_weak_ptr &e ) {
264  ZYPP_CAUGHT( e );
265  ZYPP_THROW( e );
266  }
267  }
268 
273  template <typename T_functor, typename ...Lockers>
274  struct lock_shared : public sigc::adapts<T_functor>
275  {
276  template <typename... Args>
277  decltype(auto) operator()( Args&&... args ) const {
278 
279  try {
280  auto __attribute__ ((__unused__)) lck = std::apply( []( auto&... lockers ) {
281  return std::make_tuple( lock_shared_makeLock( lockers.invoke() )... );
282  }, _lcks );
283 
284  // seems the overloaded function templates in sigc++2 force us to fully specify the overload
285  // we want to use. std::invoke() fails in that case.
286  //return std::invoke( this->functor_, std::forward<Args>(args)... );
287  if constexpr ( sizeof... (Args) == 0 ) {
288  return this->functor_();
289  } else {
290  return this->functor_.template operator()<decltype ( std::forward<Args>(args) )...> ( std::forward<Args>(args)... );
291  }
292  } catch ( const std::bad_weak_ptr &e ) {
293  ZYPP_CAUGHT( e );
294  ERR << "Ignoring signal emit due to a bad_weak_ptr exception during object locking. Maybe the signal was sent to a object that is currently destructing?" << std::endl;
295 #ifndef ZYPP_NDEBUG
296  assert( false );
297 #endif
298  if constexpr ( !std::is_same_v<void, typename sigc::adapts<T_functor>::result_type> )
299  return typename sigc::adapts<T_functor>::result_type{};
300  else
301  return;
302  }
303  }
304 
305  // Constructs a my_adaptor object that wraps the passed functor.
306  // Initializes adapts<T_functor>::functor_, which is invoked from operator()().
307  explicit lock_shared( const T_functor& functor, const Lockers&... lcks ) :
308  sigc::adapts<T_functor>(functor),
309  _lcks( lcks... )
310  {}
311 
312  std::tuple<sigc::const_limit_reference<Lockers>...> _lcks;
313  };
314 
315  template< typename Functor, typename ...Obj >
316  inline decltype(auto) locking_fun( const Functor &f, const Obj&... o )
317  {
318  return lock_shared<Functor, Obj...>( f, o...);
319  }
320 
321  }
322 #endif
323 
324  template <class R, class... T>
325  class SignalProxy;
326 
332  template <class R, class... T>
333  class SignalProxy<R(T...)>
334  {
335  public:
336  using SignalType = SignalProxyBase<R,T...>;
337 
338  SignalProxy ( SignalType &sig ) : _sig ( sig ) {}
339 
343  template <typename... Args>
344  connection connect( Args&&... slot )
345  {
346  return _sig.connect( std::forward<Args>(slot)... );
347  }
348 
349  private:
351  };
352 
353 }
354 
355 #ifndef ENABLE_SYWU
356 //
357 // Specialization of sigc::visitor for lock_shared.
358 namespace sigc
359 {
360  template <typename T_functor, typename ...Lockers>
361  struct visitor<zyppng::internal::lock_shared<T_functor, Lockers...> >
362  {
363  template <typename T_action>
364  static void do_visit_each(const T_action& action,
366  {
367  sigc::visit_each(action, target.functor_);
368  std::apply( [&]( auto&... a) {
369  ((void)sigc::visit_each(action, a),...);
370  }, target._lcks );
371 
372  }
373  };
374 } // end namespace sigc
375 #endif
376 
377 #endif // ZYPP_NG_CORE_SIGNALS_H_INCLUDED
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:424
SignalProxyBase< R, T... > SignalType
Definition: signals.h:336
static void do_visit_each(const T_action &action, const zyppng::internal::lock_shared< T_functor, Lockers... > &target)
Definition: signals.h:364
connection connect(Args &&... slot)
Forwards the arguments to the internal connect function of the signal type.
Definition: signals.h:344
#define ERR
Definition: Logger.h:102
lock_shared(const T_functor &functor, const Lockers &... lcks)
Definition: signals.h:307
#define WAR
Definition: Logger.h:101
SignalProxy(SignalType &sig)
Definition: signals.h:338
std::tuple< sigc::const_limit_reference< Lockers >... > _lcks
Definition: signals.h:312
Definition: signals.h:358
#define ZYPP_CAUGHT(EXCPT)
Drops a logline telling the Exception was caught (in order to handle it).
Definition: Exception.h:440
sigc::connection connection
Definition: signals.h:180
struct zypp::media::MediaBlock __attribute__
unsigned short a
decltype(auto) locking_fun(const Functor &f, const Obj &... o)
Definition: signals.h:316
sigc::trackable trackable
Definition: signals.h:181
auto lock_shared_makeLock(const T &locker)
Definition: signals.h:256
sigc::signal< R(T...)> SignalProxyBase
Definition: signals.h:185