c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

emitter.h
Go to the documentation of this file.
1 /* Copyright (C) 2009 to 2015 Chris Vine
2
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License, version 2.1, for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License, version 2.1, along with this library (see the file LGPL.TXT
19 which came with this source code package in the c++-gtk-utils
20 sub-directory); if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 However, it is not intended that the object code of a program whose
24 source code instantiates a template from this file or uses macros or
25 inline functions (of any length) should by reason only of that
26 instantiation or use be subject to the restrictions of use in the GNU
27 Lesser General Public License. With that in mind, the words "and
28 macros, inline functions and instantiations of templates (of any
29 length)" shall be treated as substituted for the words "and small
30 macros and small inline functions (ten lines or less in length)" in
31 the fourth paragraph of section 5 of that licence. This does not
32 affect any other reason why object code may be subject to the
33 restrictions in that licence (nor for the avoidance of doubt does it
34 affect the application of section 2 of that licence to modifications
35 of the source code in this file).
36
37 */
38
39 #ifndef CGU_EMITTER_H
40 #define CGU_EMITTER_H
41
42 /**
43 * @file emitter.h
44 * @brief This file provides a thread-safe signal/slot mechanism, with
45 * automatic disconnection.
46 *
47 * An EmitterArg object is a list of Callback::FunctorArg objects.
48 * Either callable objects (such as lambda expressions or the return
49 * value of std::bind) or Callback::FunctorArg objects may be
50 * "connected" to the EmitterArg object, and these will be executed
51 * when the operator()() or emit() member functions of the EmitterArg
52 * object concerned is called. They will be called in the order in
53 * which they were connected. Emitter is a typedef for
54 * EmitterArg<>. The generalised EmitterArg<T...> type contains
55 * Callback::FunctorArg<T...> objects or callable objects converted
56 * to Callback::FunctorArg<T...> objects (types T... being the
57 * unbound arguments the callback - see Cgu::Callback for further
58 * details, and "Usage" below for examples.) The Emitter type holds
59 * Callback::Functor (namely Callback::FunctorArg<>) objects.
60 *
61 * The main advantage of an emitter object as opposed to storing a
62 * functor object directly, apart from the fact that more than one
63 * functor can be dispatched by a single call to EmitterArg::emit() or
64 * EmitterArg::operator()(), is that it provides for automatic
65 * disconnection of a functor if the object whose member function it
66 * represents or calls into has ceased to exist.
67 *
68 * Where automatic disconnection is wanted, the object whose method is
69 * to be encapsulated by a functor must have a Releaser object as a
70 * public member. The Releaser object should be passed as the second
71 * argument of EmitterArg::connect(). As well as a Releaser object
72 * informing an emitter object when it has ceased to exist, an emitter
73 * object will do the same to the Releaser object if the emitter
74 * object happens to be destroyed before an object whose members it
75 * references or calls into (and therefore before the Releaser
76 * object). Automatic disconnection is mainly useful for non-static
77 * member functions, but it can be employed for static member
78 * functions or non-member functions if wanted (that will in effect
79 * bind the lifetime of the functor to that of the object to whose
80 * Releaser the functor has been attached.)
81 *
82 * It is safe for a connected function (i) to delete the EmitterArg
83 * object to which it is connected, even if there are other functors
84 * still to execute in the same emission (which will execute normally
85 * provided they do not try to call any of the emitter's functions),
86 * (ii) to call 'delete this' nothwithstanding that the connected
87 * functor is protected by a Releaser object (assuming all the other
88 * restraints on calling 'delete this' are met), provided that no
89 * other access would be made to the deleted object in a function call
90 * connected to the same emitter which is due to execute subsequently
91 * in the same emission, and (iii) to disconnect itself from the
92 * EmitterArg object. This design approach has a trade-off: if a
93 * connected functor tries to block, unblock or disconnect another
94 * functor connected to the same EmitterArg object which is due to
95 * execute subsequently in the same emission (or to block, unblock or
96 * disconnect itself when it is due to execute again subsequently in
97 * the same emission), the attempted block, unblock or disconnection
98 * will not have any effect on that emission (it will only have effect
99 * on a subsequent emission). In addition, a connected functor may
100 * not destroy an object which has a non-static method called by
101 * another functor connected to the same emitter and which would
102 * execute subsequently in the same emission, even if that object is
103 * protected by a Releaser object (the non-static method will
104 * unsuccessfully attempt to execute notwithstanding the destruction
105 * of the object it would be operating on).
106 *
107 * The SafeEmitterArg classes are the same as their EmitterArg
108 * counterparts except that they contain Callback::SafeFunctorArg
109 * objects, and their emit(), operator()(), connect(), disconnect(),
110 * block(), unblock() and destructor methods are protected by a mutex
111 * so that different threads can call these methods on the same
112 * emitter object, or create and delete the object.
113 *
114 * Note that the mutexes are released when the operator()()/emit()
115 * methods of the relevent Callback::SafeFunctorArg objects are
116 * called, as SafeEmitterArg objects have no idea what the referenced
117 * callbacks will do so if they were not released deadlocks could
118 * arise from recursive or out-of-order locking of the SafeEmitterArg
119 * mutex. It is therefore for users to provide additional
120 * synchronisation if the functions encapsulated by the relevant
121 * functors themselves need additional protection. Note also the
122 * subsidiary thread-safety points mentioned below.
123 *
124 * The Releaser class is intrinsically thread safe (the overhead of
125 * locking is so low that it is pointless having a separate
126 * unprotected class). This means that if a program is
127 * multi-threaded, you can use the plain EmitterArg classes provided
128 * that only the thread which creates a particular EmitterArg object
129 * calls connect(), block(), unblock((), emit() or operator()() on it,
130 * or deletes it, or calls disconnect() on it (either directly or
131 * through a Releaser object being destroyed). Where more than one
132 * thread might do that in relation to any one emitter object, use
133 * SafeEmitterArg.
134 *
135 * Alternatives
136 * ------------
137 *
138 * These classes are intended as a lightweight thread-safe signal/slot
139 * mechanism for GUI programming. For more demanding usage libsigc++
140 * is a good choice, except that it is not thread-safe. An
141 * alternative to libsigc++ is the boost::signal2 module, which is
142 * thread-safe.
143 *
144 * Subsidiary thread-safety points
145 * -------------------------------
146 *
147 * As mentioned, the SafeEmitterArg classes are thread safe, and their
148 * methods can be called in different threads without ill effect.
149 * However, there are some things that cannot be done. Users should
150 * observe two points.
151 *
152 * First, it has been mentioned that if a connected functor blocks,
153 * unblocks or disconnects another functor connected to the same
154 * emitter object and due to execute subsequently in the same
155 * emission, the blocking, unblocking or disconnection will not have
156 * effect in that emission, and that a connected functor may not
157 * delete an object whose non-static method is due to execute
158 * subsequently in the same emission. The same outcome would result
159 * if another thread tries to do any of these things while an emission
160 * is under way. Where a non-static method of an object is called by
161 * a connected functor, another thread should not try to delete the
162 * object from the time of SafeEmitterArg's operator()() or emit()
163 * beginning to the time of it ending, even if the object is protected
164 * by a Releaser object.
165 *
166 * Secondly, when a Releaser object is passed as the second argument
167 * to the connect() method of a SafeEmitterArg object, the Releaser
168 * object must remain in existence until the connect() method returns
169 * or the emitter may be left in an inconsistent state.
170 *
171 * @anchor AssignmentAnchor
172 * Assignment
173 * ----------
174 *
175 * EmitterArg and SafeEmitterArg objects cannot be copied. Releaser
176 * objects can be (we do not want to make a class uncopiable just
177 * because it has the safety feature of having a Releaser object as a
178 * member).
179 *
180 * So how should assignment of a Releaser object and of a class which
181 * has a Releaser as a member be handled? An object which has a
182 * Releaser as a member and which is being assigned to (the assignee)
183 * could keep all its existing pre-assignment emitter connections - so
184 * far as the Releaser object is concerned, it will have to do so
185 * where the connections are not protected by the Releaser object, and
186 * we could do the same in relation to protected connections, in which
187 * case we would make operator=() of Releaser do nothing: that is,
188 * just return - a default assignment would always be wrong as it
189 * would take the assignor's Releaser state but inherit none of its
190 * connections, which the assignee cannot inherit as they depend on a
191 * remote emitter object or objects.
192 *
193 * However, the state of the assignee after assignment may not be such
194 * as to permit the inheriting of all the assignor's state except its
195 * connections. Accordingly, the default strategy adopted here is for
196 * the Releaser object to become a blank sheet on assignment. After
197 * assignment, an assignee which has a Releaser object as a member
198 * will no longer have any of the emitter connections which were,
199 * prior to assignment, protected by the Releaser object. If in a
200 * particular case the user does not want this behaviour, she should
201 * provide an assignment operator for the class which has Releaser as
202 * a member and leave Releaser alone in the assignment operator.
203 *
204 * Usage
205 * -----
206 *
207 * These are examples:
208 *
209 * @code
210 * using namespace Cgu;
211 *
212 * Emitter e1;
213 * e1.connect([] () {std::cout << "Hello world\n";});
214 * e1();
215 *
216 * SafeEmitter se1;
217 * se1.connect([] () {std::cout << "Hello world\n";});
218 * se1();
219 *
220 * int res;
221 * EmitterArg<int, int&> e2;
222 * e2.connect([] (int i, int& j) {j = 10 * i;});
223 * e2(2, res);
224 * std::cout << "10 times 2 is " << res << '\n';
225 *
226 * SafeEmitterArg<int, int&> se2;
227 * se2.connect([] (int i, int& j) {j = 10 * i;});
228 * se2(2, res);
229 * std::cout << "10 times 2 is " << res << '\n';
230 * @endcode
231 *
232 * Callback::FunctorArg and Callback::SafeFunctorArg objects may be
233 * connected to an emitter, and the connect() method may be directly
234 * initialized with the result of Callback::make(),
235 * Callback::make_ref() or Callback::lambda() and implicit conversion
236 * will take place. Here is an example using Callback::make_ref(),
237 * with a class object my_obj of type MyClass, with a method void
238 * MyClass::my_method(const Something&, int):
239 *
240 * @code
241 * using namespace Cgu;
242 *
243 * Something arg;
244 * SafeEmitterArg<int> se;
245 * se.connect(Callback::make_ref(my_obj, &MyClass::my_method, arg));
246 * se(5);
247 * @endcode
248 *
249 * EmitterArg classes do not provide for a return value. If a
250 * result is wanted, users should pass an unbound argument by
251 * reference or pointer (or pointer to pointer).
252 *
253 * Exception safety
254 * ----------------
255 *
256 * Apart from the emit()/operator()() and connect() methods, nothing
257 * done to an EmitterArg/SafeEmitterArg object should cause an
258 * exception to be thrown. This is because other methods only iterate
259 * through a std::list object using std::for_each(), std::find() or by
260 * hand, and the only things done by std::for_each() or after a
261 * std::find() or iteration is to remove a functor from the list
262 * (copying a functor and comparing functors never throw, nor does
263 * destroying a functor provided the destructors of any bound argument
264 * type do not throw). Thus, an EmitterArg/SafeEmitterArg and
265 * Releaser object should never get into an inconsistent state.
266 *
267 * The connect() method could throw a std::bad_alloc exception, either
268 * on creating new functors or on pushing the functors onto the list.
269 * However, were it to do so, the method has strong exception safety
270 * (assuming merely iterating over a list does not throw, as it should
271 * not).
272 *
273 * The emit()/operator()() methods could throw std::bad_alloc, and so
274 * far as that is concerned emission of all the connected functors
275 * will either all succeed or all fail. In addition, the functions
276 * represented by the functors held by the emitter might throw when
277 * executed. emit()/operator()() do not attempt to catch these
278 * exceptions as there is nothing they could do with them. This means
279 * that although a throwing connected functor will not leave the
280 * EmitterArg/SafeEmitterArg object in an inconsistent state, any
281 * other connected functors due to execute subsequently on that same
282 * emission will not execute. If that is important in any particular
283 * case, the user must incorporate logic in the connected functions to
284 * cater for an exception causing only part execution, or must connect
285 * only one functor to any one signal and "chain" emissions by hand so
286 * as to do the right thing.
287 */
288
289 /*
290 Mutex locking heirarchy:
291
292 Some out-of-order locking must take place because of the
293 relationship between the Releaser and SafeEmitterArg<> classes. The
294 mutex of Releaser is given the higher priority. This means that a
295 plain EmitterArg<> object will not take any hit from the fact that
296 Releaser is also useable with SafeEmitterArg<> objects.
297
298 One consequence is that to avoid deadlocks, it is the
299 SafeEmitterArg<> functions which must yield when a deadlock would
300 otherwise arise. Yielding could occur in
301 SafeEmitterArg<>::~SafeEmitterArg() and
302 SafeEmitterArg<>::disconnect().
303 */
304
305 #ifdef CGU_USE_SCHED_YIELD
306 #include <sched.h>
307 #else
308 #include <unistd.h>
309 #endif
310
311 #include <list>
312 #include <unordered_set>
313 #include <algorithm>
314 #include <functional>
315 #include <utility> // for std::move
316 #include <type_traits> // for std::remove_reference, std::enable_if and std::is_convertible
317
318 #include <c++-gtk-utils/callback.h>
319 #include <c++-gtk-utils/mutex.h>
320 #include <c++-gtk-utils/cgu_config.h>
321
322 namespace Cgu {
323
324 /* The four basic emitter types */
325
326 template <class... FreeArgs> class EmitterArg;
327 template <class... FreeArgs> class SafeEmitterArg;
328 typedef EmitterArg<> Emitter;
329 typedef SafeEmitterArg<> SafeEmitter;
330
331 /**
332 * @class Releaser emitter.h c++-gtk-utils/emitter.h
333 * @brief A class used for tracking EmitterArg and SafeEmitterArg
334 * connections.
335 * @sa EmitterArg SafeEmitterArg
336 * @sa emitter.h
337 * @sa Callback namespace
338 *
339 * This class provides tracking of EmitterArg and SafeEmitterArg
340 * connections. It should be a public member of any target class
341 * which wants functors representing any of its methods to be
342 * disconnected automatically from an EmitterArg or SafeEmitterArg
343 * object when the target class object is destroyed, and is passed as
344 * one of the arguments to the connect() method of EmitterArg or
345 * SafeEmitterArg.
346 *
347 * All its methods are thread-safe.
348 *
349 * For further background, read this: emitter.h
350 */
351
352 class Releaser {
353
354 // from version 2.0.0-rc3 we use std::unordered_set rather than
355 // std::list in Releaser. We can't do that for
356 // EmitterArg/SafeEmitterArg objects, as they need to execute
357 // connected functors in the order in which they were connected.
358 std::unordered_set<Callback::SafeFunctor> disconnect_set;
359 Thread::Mutex mutex;
360
361 // only an EmitterArg or SafeEmitterArg object can access add(), remove and try_remove()
362 void add(const Callback::SafeFunctor&);
363 void remove(const Callback::SafeFunctor&);
364 void try_remove(const Callback::SafeFunctor&, int*);
365 public:
366 template <class... T> friend class EmitterArg;
367 template <class... T> friend class SafeEmitterArg;
368
369 // operator=() and the copy constructor should copy nothing from the
370 // assignor, because disconnect_set should be empty in the
371 // assignee, as any class containing us does not acquire as assignee
372 // any emitter functors representing any of its methods
373
374 /**
375 * See notes on @ref AssignmentAnchor "assignment" to see how this
376 * operates. This does not throw provided that the destructors of any
377 * bound arguments of a functor managed by this Releaser object prior
378 * to assignment do not throw (as they should not do), and assuming
379 * that merely iterating through a list does not throw (as it would
380 * not on any sane implementation).
381 * @param r The assignee.
382 */
383 Releaser& operator=(const Releaser& r);
384
385 /**
386 * This does not copy anything from the Releaser object passed as an
387 * argument - see the notes on @ref AssignmentAnchor "assignment" for
388 * an explanation of why. This does not throw.
389 * @param r A Releaser object.
390 * @exception std::bad_alloc This constructor might throw
391 * std::bad_alloc if memory is exhausted and the system throws in that
392 * case.
393 * @exception Thread::MutexError This constructor might throw
394 * Thread::MutexError if initialisation of the contained mutex fails.
395 * (It is often not worth checking for this, as it means either memory
396 * is exhausted or pthread has run out of other resources to create
397 * new mutexes.)
398 */
399 Releaser(const Releaser& r) {}
400
401 /**
402 * @exception std::bad_alloc The default constructor might throw
403 * std::bad_alloc if memory is exhausted and the system throws in that
404 * case.
405 * @exception Thread::MutexError The default constructor might throw
406 * Thread::MutexError if initialisation of the contained mutex fails.
407 * (It is often not worth checking for this, as it means either memory
408 * is exhausted or pthread has run out of other resources to create
409 * new mutexes.)
410 */
411 Releaser() = default;
412
413 /**
414 * The destructor does not throw provided that the destructors of any
415 * bound arguments of a functor managed by this Releaser object do not
416 * throw (as they should not do), and assuming that merely iterating
417 * through an unordered_set does not throw (as it would not on any
418 * sane implementation).
419 */
420 ~Releaser();
421
422 /* Only has effect if --with-glib-memory-slices-compat or
423 * --with-glib-memory-slices-no-compat option picked */
424 CGU_GLIB_MEMORY_SLICES_FUNCS
425 };
426
427 /* the emitter classes */
428
429 /**
430 * @class EmitterArg emitter.h c++-gtk-utils/emitter.h
431 * @brief A class to execute callbacks connected to it, with provision
432 * for automatic disconnection.
433 * @sa SafeEmitterArg Releaser
434 * @sa emitter.h
435 * @sa Callback namespace
436 *
437 * Callable objects (such as lambda expressions or the return value of
438 * std::bind) or Callback::FunctorArg objects may be connected to
439 * Emitter classes, and will be executed when EmitterArg::emit() or
440 * EmitterArg::operator()() are called.
441 *
442 * One version of the connect() method takes a Releaser object as an
443 * argument. Such a Releaser object should be a public member of any
444 * target class which wants functors representing (or calling into)
445 * any of its methods to be disconnected automatically from the
446 * EmitterArg object when the target class object is destroyed.
447 *
448 * A connection may be explicitly disconnected by calling the
449 * disconnect() method, and may also be temporarily blocked and
450 * subsequently unblocked with the block() and unblock() methods.
451 *
452 * The template types are the types of the unbound arguments, if any.
453 * EmitterArg<> is typedef'ed to Emitter.
454 *
455 * @b Usage
456 *
457 * These are examples:
458 *
459 * @code
460 * using namespace Cgu;
461 *
462 * Emitter e1;
463 * e1.connect([] () {std::cout << "Hello world\n";});
464 * e1();
465 *
466 * int res;
467 * EmitterArg<int, int&> e2;
468 * e2.connect([] (int i, int& j) {j = 10 * i;});
469 * e2(2, res);
470 * std::cout << "10 times 2 is " << res << '\n';
471 * @endcode
472 *
473 * Callback::FunctorArg objects may be connected to an emitter, and
474 * the connect() method may be directly initialized with the result of
475 * Callback::make(), Callback::make_ref() or Callback::lambda() and
476 * implicit conversion will take place. Here is an example using
477 * Callback::make_ref(), with a class object my_obj of type MyClass,
478 * with a method void MyClass::my_method(const Something&, int):
479 *
480 * @code
481 * using namespace Cgu;
482 *
483 * Something arg;
484 * EmitterArg<int> e;
485 * e.connect(Callback::make_ref(my_obj, &MyClass::my_method, arg));
486 * e(5);
487 * @endcode
488 *
489 * For further background, including about thread-safety and exception
490 * safety and other matters, read this: emitter.h, or for more
491 * information about bound and unbound arguments, read this:
492 * Cgu::Callback.
493 */
494
495 template <class... FreeArgs>
496 class EmitterArg {
497
498 #ifndef DOXYGEN_PARSING
499 // f1 is the functor we execute when we emit()
500 // f2 is the functor we execute in our destructor if we are destroyed
501 // before the remote object is
502 struct ListItem {
503 Callback::FunctorArg<FreeArgs...> f1;
504 Callback::Functor f2;
505 bool blocked;
506 ListItem(Callback::FunctorArg<FreeArgs...> f1_, Callback::Functor f2_):
507 f1(f1_), f2(f2_), blocked(false) {}
508 };
509 #endif
510
511 std::list<ListItem> emission_list;
512
513 // only Releaser objects can access this
514 void tracking_disconnect(const Callback::FunctorArg<FreeArgs...>&);
515
516 public:
517 friend class Releaser;
518
519 /**
520 * This will execute the connected functors.
521 * @param args The unbound arguments to be passed to the referenced
522 * function or class method, if any.
523 * @exception std::bad_alloc The method might throw std::bad_alloc if
524 * memory is exhausted and the system throws in that case. In
525 * addition, it will throw if the functions or class methods
526 * referenced by the functors throw (or if the copy constructor of a
527 * free or bound argument throws and it is not a reference argument).
528 */
529 void operator()(typename Cgu::Param<FreeArgs>::ParamType... args) const {emit(args...);}
530
531 /**
532 * This will execute the connected functors.
533 * @param args The unbound arguments to be passed to the referenced
534 * function or class method, if any.
535 * @exception std::bad_alloc The method might throw std::bad_alloc if
536 * memory is exhausted and the system throws in that case. In
537 * addition, it will throw if the functions or class methods
538 * referenced by the functors throw (or if the copy constructor of a
539 * free or bound argument throws and it is not a reference argument).
540 */
541 void emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
542
543 /**
544 * This will execute the connected functors, but it also reports
545 * whether in fact there were any connected functors to execute. (It
546 * is not necessary to use this function just because it is not known
547 * whether a functor is connected - if the standard emit() function is
548 * called when no functor is connected, nothing will happen. The
549 * feature of this method is that it will report the outcome.)
550 * @param args The unbound arguments to be passed to the connected
551 * functions or class methods, if any.
552 * @return Returns false if there were no functors to execute, or true
553 * if functors have been executed.
554 * @exception std::bad_alloc The method might throw std::bad_alloc if
555 * memory is exhausted and the system throws in that case. In
556 * addition, it will throw if the functions or class methods
557 * referenced by the functors throw (or if the copy constructor of a
558 * free or bound argument throws and it is not a reference argument).
559 */
560 bool test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
561
562 /**
563 * Connects a Callback::FunctorArg object.
564 * @param f The Callback::FunctorArg object to connect.
565 * @return The Callback::FunctorArg object connected.
566 * @exception std::bad_alloc The method might throw std::bad_alloc if
567 * memory is exhausted and the system throws in that case.
568 */
569 Callback::FunctorArg<FreeArgs...> connect(const Callback::FunctorArg<FreeArgs...>& f);
570
571 /**
572 * Connects a Callback::FunctorArg object.
573 * @param f The Callback::FunctorArg object to connect.
574 * @param r A Releaser object for automatic disconnection of the
575 * Callback::FunctorArg object if the object whose method it
576 * represents is destroyed.
577 * @return The Callback::FunctorArg object connected.
578 * @exception std::bad_alloc The method might throw std::bad_alloc if
579 * memory is exhausted and the system throws in that case.
580 */
581 Callback::FunctorArg<FreeArgs...> connect(const Callback::FunctorArg<FreeArgs...>& f, Releaser& r);
582
583 /**
584 * Connects a callable object, such as formed by a lambda expression
585 * or the result of std::bind.
586 * @param f The callable object to connect. If must have the same
587 * unbound argument types as the EmitterArg object concerned.
588 * @return A Callback::FunctorArg object which can be passed to
589 * disconnect(), block() or unblock().
590 * @exception std::bad_alloc The method might throw std::bad_alloc if
591 * memory is exhausted and the system throws in that case. If might
592 * also throw if the copy or move constructor of the callable object
593 * throws.
594 *
595 * Since 2.1.0
596 */
597 // we need to use enable_if so that where this function is passed a
598 // Callback::SafeFunctorArg object or a pointer to a
599 // Callback::Callback object or some other convertible object, this
600 // templated overload is dropped from the overload set, in order to
601 // support the deprecated overloads of this function.. This overload
602 // calls into the version of this function taking a
603 // Callback::Functor object in order to perform type erasure.
604 template <class F,
605 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
606 const Callback::FunctorArg<FreeArgs...>>::value>::type>
607 Callback::FunctorArg<FreeArgs...> connect(F&& f) {
608 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)));
609 }
610
611 /**
612 * Connects a callable object, such as formed by a lambda expression
613 * or the result of std::bind.
614 * @param f The callable object to connect. If must have the same
615 * unbound argument types as the EmitterArg object concerned.
616 * @param r A Releaser object for automatic disconnection of the
617 * callable object if an object whose method it represents or calls
618 * into is destroyed.
619 * @return A Callback::FunctorArg object which can be passed to
620 * disconnect(), block() or unblock().
621 * @exception std::bad_alloc The method might throw std::bad_alloc if
622 * memory is exhausted and the system throws in that case. If might
623 * also throw if the copy or move constructor of the callable object
624 * throws.
625 *
626 * Since 2.1.0
627 */
628 // we need to use enable_if so that where this function is passed a
629 // Callback::SafeFunctorArg object or a pointer to a
630 // Callback::Callback object or some other convertible object, this
631 // templated overload is dropped from the overload set, in order to
632 // support the deprecated overloads of this function.. This overload
633 // calls into the version of this function taking a
634 // Callback::Functor object in order to perform type erasure.
635 template <class F,
636 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
637 const Callback::FunctorArg<FreeArgs...>>::value>::type>
638 Callback::FunctorArg<FreeArgs...> connect(F&& f, Releaser& r) {
639 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)), r);
640 }
641
642 /**
643 * Disconnects a functor previously connected. This does not throw
644 * provided that the destructors of any bound arguments do not throw
645 * (as they should not do), and assuming that merely iterating through
646 * a list does not throw (as it would not on any sane implementation).
647 * @param f The functor to disconnect.
648 * @note If the same functor has been connected more than once to the
649 * same EmitterArg object, this call will disconnect all of them.
650 */
651 void disconnect(const Callback::FunctorArg<FreeArgs...>& f);
652
653 /**
654 * Blocks a connected functor from executing when emit() or
655 * operator()() is called until unblock() is called. This method does
656 * not throw (assuming that merely iterating through a list does not
657 * throw, as it would not on any sane implementation).
658 * @param f The functor to block.
659 * @note If the same functor has been connected more than once to the
660 * same EmitterArg object, this call will block all of them.
661 */
662 void block(const Callback::FunctorArg<FreeArgs...>& f);
663
664 /**
665 * Unblocks a previously blocked functor. This method does not throw
666 * (assuming that merely iterating through a list does not throw, as
667 * it would not on any sane implementation).
668 * @param f The functor to unblock.
669 * @note If the same functor has been connected more than once to the
670 * same EmitterArg object, this call will unblock all of them.
671 */
672 void unblock(const Callback::FunctorArg<FreeArgs...>& f);
673
674 /**
675 * @exception std::bad_alloc The constructor might throw
676 * std::bad_alloc if memory is exhausted and the system throws in that
677 * case.
678 */
679 EmitterArg() = default;
680
681 /**
682 * This class cannot be copied. The copy constructor is deleted.
683 */
684 EmitterArg(const EmitterArg&) = delete;
685
686 /**
687 * This class cannot be copied. The assignment operator is deleted.
688 */
689 EmitterArg& operator=(const EmitterArg&) = delete;
690
691 /**
692 * The destructor does not throw provided that the destructors of any
693 * bound arguments do not throw (as they should not do), and assuming
694 * that merely iterating through a list does not throw (as it would
695 * not on any sane implementation).
696 */
697 ~EmitterArg();
698
699 /* Only has effect if --with-glib-memory-slices-compat or
700 * --with-glib-memory-slices-no-compat option picked */
701 CGU_GLIB_MEMORY_SLICES_FUNCS
702 };
703
704 template <class... FreeArgs>
705 EmitterArg<FreeArgs...>::~EmitterArg() {
706 for(const auto& l: emission_list) {l.f2();}
707 }
708
709 template <class... FreeArgs>
710 void EmitterArg<FreeArgs...>::emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
711
712 // create a local copy of emission_list, to enable a connected
713 // function (i) to delete the EmitterArg<> object to which it is
714 // connected, even if there are other functors still to execute in
715 // the same emission (which will execute normally provided they do
716 // not try to call any of the emitter's functions), (ii) to call
717 // 'delete this' nothwithstanding that the connected function is
718 // protected by a Releaser object (assuming all the other restraints
719 // on calling 'delete this' are met), provided that no other access
720 // would be made to the deleted object in a function call connected
721 // to the same emitter which is due to execute subsequently in the
722 // same emission, and (iii) to disconnect itself from the
723 // EmitterArg object. This design approach has a trade-off: if a
724 // connected function tries to block, unblock or disconnect another
725 // function connected to the same EmitterArg<> object which is due
726 // to execute subsequently in the same emission (or to block,
727 // unblock or disconnect itself when it is due to execute again
728 // subsequently in the same emission), the attempted block, unblock
729 // or disconnection will not have any effect on that emission (it
730 // will only have effect on a subsequent emission). In addition, a
731 // connected function may not destroy an object whose non-static
732 // method is connected to the same emitter and which would execute
733 // subsequently in the same emission, even if that object is
734 // protected by a Releaser object (the non-static method will
735 // unsuccessfully attempt to execute notwithstanding the destruction
736 // of the object it would be operating on).
737
738 // we can't use uniform initialisation here as it would be
739 // construed as invoking an initialiser list with a list item,
740 // rather than passing an already formed list
741 std::list<ListItem> local_list = emission_list;
742
743 for (const auto& l: local_list) {
744 if (!l.blocked) l.f1(args...);
745 }
746 }
747
748 template <class... FreeArgs>
749 bool EmitterArg<FreeArgs...>::test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
750 if (emission_list.empty()) return false;
751 emit(args...);
752 return true;
753 }
754
755 template <class... FreeArgs>
756 Callback::FunctorArg<FreeArgs...> EmitterArg<FreeArgs...>::connect(const Callback::FunctorArg<FreeArgs...>& f1) {
757 emission_list.emplace_back(f1, Callback::Functor());
758 return f1;
759 }
760
761 template <class... FreeArgs>
762 Callback::FunctorArg<FreeArgs...> EmitterArg<FreeArgs...>::connect(const Callback::FunctorArg<FreeArgs...>& f1, Releaser& r) {
763 // In this method:
764 // f1 is the functor we execute when we emit()
765 // f2 is the functor we execute in our destructor if we are destroyed before the
766 // remote object is
767 // f3 is the functor the remote object executes in its Releaser if it is destroyed
768 // before we are, or if Releaser::operator=() is called
769
770 Callback::SafeFunctor f3{Callback::make_ref(*this, &EmitterArg<FreeArgs...>::tracking_disconnect, f1)};
771 Callback::Functor f2{Callback::make_ref(r, &Releaser::remove, f3)};
772 r.add(f3);
773 try {
774 emission_list.emplace_back(f1, f2);
775 }
776 catch (...) {
777 r.remove(f3);
778 throw;
779 }
780 return f1;
781 }
782
783 template <class... FreeArgs>
784 void EmitterArg<FreeArgs...>::disconnect(const Callback::FunctorArg<FreeArgs...>& arg) {
785 // in theory, we could have connected the same functor object
786 // more than once, so cater for that
787 auto iter = emission_list.begin();
788 for (;;) {
789 iter = std::find_if(iter, emission_list.end(),
790 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
791 if (iter != emission_list.end()) {
792 // remove ourselves from the remote Releaser object
793 (iter->f2)();
794
795 // remove this item from emission_list
796 iter = emission_list.erase(iter);
797 }
798 else break;
799 }
800 }
801
802 // tracking disconnect() is the same as disconnect(), except that we do not
803 // execute f2 as the remote Releaser object will destroy its own functors
804 // in that case
805 template <class... FreeArgs>
806 void EmitterArg<FreeArgs...>::tracking_disconnect(const Callback::FunctorArg<FreeArgs...>& arg) {
807 auto iter = emission_list.begin();
808 for (;;) {
809 iter = std::find_if(iter, emission_list.end(),
810 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
811 if (iter != emission_list.end()) {
812 // remove this item from emission_list
813 iter = emission_list.erase(iter);
814 }
815 else break;
816 }
817 }
818
819 template <class... FreeArgs>
820 void EmitterArg<FreeArgs...>::block(const Callback::FunctorArg<FreeArgs...>& arg) {
821 // in theory, we could have connected the same functor object
822 // more than once, so cater for that
823 auto iter = emission_list.begin();
824 for (;;) {
825 iter = std::find_if(iter, emission_list.end(),
826 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
827 if (iter != emission_list.end()) {
828 iter->blocked = true;
829 ++iter;
830 }
831 else break;
832 }
833 }
834
835 template <class... FreeArgs>
836 void EmitterArg<FreeArgs...>::unblock(const Callback::FunctorArg<FreeArgs...>& arg) {
837 // in theory, we could have connected the same functor object
838 // more than once, so cater for that
839 auto iter = emission_list.begin();
840 for (;;) {
841 iter = std::find_if(iter, emission_list.end(),
842 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
843 if (iter != emission_list.end()) {
844 iter->blocked = false;
845 ++iter;
846 }
847 else break;
848 }
849 }
850
851 /**
852 * @class SafeEmitterArg emitter.h c++-gtk-utils/emitter.h
853 * @brief A thread-safe class to execute callbacks connected to it,
854 * with provision for automatic disconnection.
855 * @sa EmitterArg Releaser
856 * @sa emitter.h
857 * @sa Callback namespace
858 *
859 * This is a thread-safe version of the EmitterArg class. Callable
860 * objects (such as lambda expressions or the return value of
861 * std::bind) or Callback::SafeFunctorArg objects may be connected to
862 * SafeEmitter classes (referred to be below as "connected
863 * callables"), and will be executed when SafeEmitterArg::emit() or
864 * SafeEmitterArg::operator()() are called.
865 *
866 * One version of the connect() method takes a Releaser object as an
867 * argument. Such a Releaser object should be a public member of any
868 * target class which wants connected callables representing (or
869 * calling into) any of its methods to be disconnected automatically
870 * from the SafeEmitterArg object when the target class object is
871 * destroyed.
872 *
873 * A connection may be explicitly disconnected by calling the
874 * disconnect() method, and may also be temporarily blocked and
875 * subsequently unblocked with the block() and unblock() methods.
876 *
877 * The template types are the types of the unbound arguments, if any.
878 * SafeEmitterArg<> is typedef'ed to SafeEmitter.
879 *
880 * @b Usage
881 *
882 * These are examples:
883 *
884 * @code
885 * using namespace Cgu;
886 *
887 * SafeEmitter se1;
888 * se1.connect([] () {std::cout << "Hello world\n";});
889 * se1();
890 *
891 * int res;
892 * SafeEmitterArg<int, int&> se2;
893 * se2.connect([] (int i, int& j) {j = 10 * i;});
894 * se2(2, res);
895 * std::cout << "10 times 2 is " << res << '\n';
896 * @endcode
897 *
898 * Callback::SafeFunctorArg objects may be connected to an emitter,
899 * and the connect() method may be directly initialized with the
900 * result of Callback::make(), Callback::make_ref() or
901 * Callback::lambda() and implicit conversion will take place. Here
902 * is an example using Callback::make_ref(), with a class object
903 * my_obj of type MyClass, with a method void MyClass::my_method(const
904 * Something&, int):
905 *
906 * @code
907 * using namespace Cgu;
908 *
909 * Something arg;
910 * SafeEmitterArg<int> se;
911 * se.connect(Callback::make_ref(my_obj, &MyClass::my_method, arg));
912 * se(5);
913 * @endcode
914 *
915 * For further background, including about thread-safety and exception
916 * safety and other matters, read this: emitter.h, or for more
917 * information about bound and unbound arguments, read this:
918 * Cgu::Callback.
919 */
920
921 template <class... FreeArgs>
922 class SafeEmitterArg {
923
924 #ifndef DOXYGEN_PARSING
925 // f1 is the functor we execute when we emit()
926 // f2 is the functor we execute in our destructor if we are destroyed
927 // before the remote object is
928 struct ListItem {
929 Callback::SafeFunctorArg<FreeArgs...> f1;
930 Callback::SafeFunctorArg<int*> f2;
931 bool blocked;
932 ListItem(Callback::SafeFunctorArg<FreeArgs...> f1_, Callback::SafeFunctorArg<int*> f2_):
933 f1(f1_), f2(f2_), blocked(false) {}
934 };
935 #endif
936
937 std::list<ListItem> emission_list;
938 mutable Thread::Mutex mutex; // make this mutable so we can lock/unlock in const methods
939
940 // only Releaser objects can access this
941 void tracking_disconnect(const Callback::SafeFunctorArg<FreeArgs...>&);
942
943 public:
944 friend class Releaser;
945
946 /**
947 * This will execute the connected functors. It is thread safe if the
948 * functions or class methods referenced by the connected functors are
949 * thread safe.
950 * @param args The unbound arguments to be passed to the referenced
951 * function or class method, if any.
952 * @exception std::bad_alloc The method might throw std::bad_alloc if
953 * memory is exhausted and the system throws in that case. In
954 * addition, it will throw if the functions or class methods
955 * referenced by the functors throw (or if the copy constructor of a
956 * free or bound argument throws and it is not a reference argument).
957 */
958 void operator()(typename Cgu::Param<FreeArgs>::ParamType... args) const {emit(args...);}
959
960 /**
961 * This will execute the connected functors. It is thread safe if the
962 * functions or class methods referenced by the connected functors are
963 * thread safe.
964 * @param args The unbound arguments to be passed to the referenced
965 * function or class method, if any.
966 * @exception std::bad_alloc The method might throw std::bad_alloc if
967 * memory is exhausted and the system throws in that case. In
968 * addition, it will throw if the functions or class methods
969 * referenced by the functors throw (or if the copy constructor of a
970 * free or bound argument throws and it is not a reference argument).
971 */
972 void emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
973
974 /**
975 * This will execute the connected functors, but it also reports
976 * whether in fact there were any connected functors to execute. It
977 * is thread safe if the functions or class methods referenced by the
978 * connected functors are thread safe. (It is not necessary to use
979 * this function just because it is not known whether a functor is
980 * connected - if the standard emit() function is called when no
981 * functor is connected, nothing will happen. The feature of this
982 * method is that it will report the outcome.)
983 * @param args The unbound arguments to be passed to the referenced
984 * function or class method, if any.
985 * @return Returns false if there were no functors to execute, or true
986 * if functors have been executed.
987 * @exception std::bad_alloc The method might throw std::bad_alloc if
988 * memory is exhausted and the system throws in that case. In
989 * addition, it will throw if the functions or class methods
990 * referenced by the functors throw (or if the copy constructor of a
991 * free or bound argument throws and it is not a reference argument).
992 */
993 bool test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
994
995 /**
996 * Connects a Callback::SafeFunctorArg object.
997 * @param f The Callback::SafeFunctorArg object to connect.
998 * @return The Callback::SafeFunctorArg object connected.
999 * @exception std::bad_alloc The method might throw std::bad_alloc if
1000 * memory is exhausted and the system throws in that case.
1001 */
1002 Callback::SafeFunctorArg<FreeArgs...> connect(const Callback::SafeFunctorArg<FreeArgs...>& f);
1003
1004 /**
1005 * Connects a Callback::SafeFunctorArg object.
1006 * @param f The Callback::SafeFunctorArg object to connect.
1007 * @param r A Releaser object for automatic disconnection of the
1008 * Callback::SafeFunctorArg object if the object whose method it
1009 * represents is destroyed.
1010 * @return The Callback::SafeFunctorArg object connected.
1011 * @exception std::bad_alloc The method might throw std::bad_alloc if
1012 * memory is exhausted and the system throws in that case.
1013 */
1014 Callback::SafeFunctorArg<FreeArgs...> connect(const Callback::SafeFunctorArg<FreeArgs...>& f, Releaser& r);
1015
1016 /**
1017 * Connects a callable object, such as formed by a lambda expression
1018 * or the result of std::bind.
1019 * @param f The callable object to connect. If must have the same
1020 * unbound argument types as the SafeEmitterArg object concerned.
1021 * @return A Callback::SafeFunctorArg object which can be passed to
1022 * disconnect(), block() or unblock().
1023 * @exception std::bad_alloc The method might throw std::bad_alloc if
1024 * memory is exhausted and the system throws in that case. If might
1025 * also throw if the copy or move constructor of the callable object
1026 * throws.
1027 *
1028 * Since 2.1.0
1029 */
1030 // we need to use enable_if so that where this function is passed a
1031 // Callback::SafeFunctorArg object or a pointer to a
1032 // Callback::Callback object or some other convertible object, this
1033 // templated overload is dropped from the overload set, in order to
1034 // support the Callback::SafeFunctorArg overloads of this function.
1035 // This overload calls into the version of this function taking a
1036 // Callback::SafeFunctor object in order to perform type erasure.
1037 template <class F,
1038 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
1039 const Callback::SafeFunctorArg<FreeArgs...>>::value>::type>
1040 Callback::SafeFunctorArg<FreeArgs...> connect(F&& f) {
1041 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)));
1042 }
1043
1044 /**
1045 * Connects a callable object, such as formed by a lambda expression
1046 * or the result of std::bind.
1047 * @param f The callable object to connect. If must have the same
1048 * unbound argument types as the SafeEmitterArg object concerned.
1049 * @param r A Releaser object for automatic disconnection of the
1050 * callable object if an object whose method it represents or calls
1051 * into is destroyed.
1052 * @return A Callback::SafeFunctorArg object which can be passed to
1053 * disconnect(), block() or unblock().
1054 * @exception std::bad_alloc The method might throw std::bad_alloc if
1055 * memory is exhausted and the system throws in that case. If might
1056 * also throw if the copy or move constructor of the callable object
1057 * throws.
1058 *
1059 * Since 2.1.0
1060 */
1061 // we need to use enable_if so that where this function is passed a
1062 // Callback::SafeFunctorArg object or a pointer to a
1063 // Callback::Callback object or some other convertible object, this
1064 // templated overload is dropped from the overload set, in order to
1065 // support the Callback::SafeFunctorArg overloads of this function.
1066 // This overload calls into the version of this function taking a
1067 // Callback::SafeFunctor object in order to perform type erasure.
1068 template <class F,
1069 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
1070 const Callback::SafeFunctorArg<FreeArgs...>>::value>::type>
1071 Callback::SafeFunctorArg<FreeArgs...> connect(F&& f, Releaser& r) {
1072 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)), r);
1073 }
1074
1075 /**
1076 * Disconnects a functor previously connected. This does not throw
1077 * provided that the destructors of any bound arguments do not throw
1078 * (as they should not do), and assuming that merely iterating through
1079 * a list does not throw (as it would not on any sane implementation).
1080 * It is thread safe.
1081 * @param f The functor to disconnect.
1082 * @note If the same functor has been connected more than once to the
1083 * same SafeEmitterArg object, this call will disconnect all of them.
1084 */
1085 void disconnect(const Callback::SafeFunctorArg<FreeArgs...>& f);
1086
1087 /**
1088 * Blocks a connected functor from executing when emit() or
1089 * operator()() is called until unblock() is called. This method does
1090 * not throw (assuming that merely iterating through a list does not
1091 * throw, as it would not on any sane implementation). It is thread
1092 * safe.
1093 * @param f The functor to block.
1094 * @note If the same functor has been connected more than once to the
1095 * same SafeEmitterArg object, this call will block all of them.
1096 */
1097 void block(const Callback::SafeFunctorArg<FreeArgs...>& f);
1098
1099 /**
1100 * Unblocks a previously blocked functor. This method does not throw
1101 * (assuming that merely iterating through a list does not throw, as
1102 * it would not on any sane implementation). It is thread safe.
1103 * @param f The functor to unblock.
1104 * @note If the same functor has been connected more than once to the
1105 * same SafeEmitterArg object, this call will unblock all of them.
1106 */
1107 void unblock(const Callback::SafeFunctorArg<FreeArgs...>& f);
1108
1109 /**
1110 * @exception std::bad_alloc The constructor might throw
1111 * std::bad_alloc if memory is exhausted and the system throws in that
1112 * case.
1113 * @exception Thread::MutexError The constructor might throw
1114 * Thread::MutexError if initialisation of the contained mutex fails.
1115 * (It is often not worth checking for this, as it means either memory
1116 * is exhausted or pthread has run out of other resources to create
1117 * new mutexes.)
1118 */
1119 SafeEmitterArg() = default;
1120
1121 /**
1122 * This class cannot be copied. The copy constructor is deleted.
1123 */
1124 SafeEmitterArg(const SafeEmitterArg&) = delete;
1125
1126 /**
1127 * This class cannot be copied. The assignment operator is deleted.
1128 */
1129 SafeEmitterArg& operator=(const SafeEmitterArg&) = delete;
1130
1131 /**
1132 * The destructor does not throw provided that the destructors of any
1133 * bound arguments do not throw (as they should not do), and assuming
1134 * that merely iterating through a list does not throw (as it would
1135 * not on any sane implementation). It is thread-safe as regards the
1136 * dropping of any connected functors and of any relevant Releaser
1137 * objects.
1138 */
1139 ~SafeEmitterArg();
1140
1141 /* Only has effect if --with-glib-memory-slices-compat or
1142 * --with-glib-memory-slices-no-compat option picked */
1143 CGU_GLIB_MEMORY_SLICES_FUNCS
1144 };
1145
1146 template <class... FreeArgs>
1147 SafeEmitterArg<FreeArgs...>::~SafeEmitterArg() {
1148
1149 // go through emission_list() item by item, popping off the front and erasing
1150 // as we go in case Releaser::try_remove() fails to acquire the lock on one
1151 // of the iterations
1152 Thread::Mutex::Lock lock{mutex};
1153 while (!emission_list.empty()) {
1154 auto iter = emission_list.begin();
1155 int result = 0; // f2 might be a no-op
1156 // remove ourselves from the remote Releaser object
1157 (iter->f2)(&result);
1158 if (!result) { // we got the Releaser mutex lock or no-op
1159 // now remove this item from emission_list
1160 emission_list.erase(iter);
1161 }
1162 else {
1163 mutex.unlock();
1164 // spin nicely
1165 #ifdef CGU_USE_SCHED_YIELD
1166 sched_yield();
1167 #else
1168 usleep(10);
1169 #endif
1170 mutex.lock();
1171 }
1172 }
1173 }
1174
1175 template <class... FreeArgs>
1176 void SafeEmitterArg<FreeArgs...>::emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
1177
1178 // create a local copy of emission_list, to enable a connected
1179 // function (i) to delete the EmitterArg<> object to which it is
1180 // connected, even if there are other functors still to execute in
1181 // the same emission (which will execute normally provided they do
1182 // not try to call any of the emitter's functions), (ii) to call
1183 // 'delete this' nothwithstanding that the connected function is
1184 // protected by a Releaser object (assuming all the other restraints
1185 // on calling 'delete this' are met), provided that no other access
1186 // would be made to the deleted object in a function call connected
1187 // to the same emitter which is due to execute subsequently in the
1188 // same emission, and (iii) to disconnect itself from the
1189 // EmitterArg<> object. This design approach has a trade-off: if a
1190 // connected function tries to block, unblock or disconnect another
1191 // function connected to the same EmitterArg<> object which is due
1192 // to execute subsequently in the same emission (or to block,
1193 // unblock or disconnect itself when it is due to execute again
1194 // subsequently in the same emission), the attempted block, unblock
1195 // or disconnection will not have any effect on that emission (it
1196 // will only have effect on a subsequent emission). In addition, a
1197 // connected function may not destroy an object whose non-static
1198 // method is connected to the same emitter and which would execute
1199 // subsequently in the same emission, even if that object is
1200 // protected by a Releaser object (the non-static method will
1201 // unsuccessfully attempt to execute notwithstanding the destruction
1202 // of the object it would be operating on).
1203
1204 // SafeFunctorArg usage has the additional point that while an
1205 // emission is in course, another thread should not try to do any of
1206 // those things, or the same outcome will result. Another thread
1207 // should leave alone objects connected to a SafeEmitterArg<> object
1208 // from the time of operator()() or emit() beginning to the time of
1209 // it ending, and not try to interfere.
1210
1211 // a side effect of having a local list is that, as required, we
1212 // will not be holding our mutex when executing the functors it
1213 // contains. It is OK having the functors in two different lists
1214 // which are potentially (when our mutex is released) in two
1215 // different threads, because the functors hold their
1216 // Callback::Callback objects by SharedLockPtr so their reference
1217 // count is protected (they are SafeFunctorArg<> functors).
1218
1219 // we could reduce contention on the mutex by allocating local_list
1220 // outside the mutex, eg by taking the size of emission_list within
1221 // the mutex, then allocating the nodes of local_list outside the
1222 // mutex with that size, and then copying items across within the
1223 // mutex (checking the end iterators of both containers when
1224 // iterating because the size of emitter_list could have changed
1225 // while allocating local_list) and, if the size of emission list
1226 // did change by another thread disconnecting a functor in the
1227 // interval when local_list was allocated, resizing local_list
1228 // downwards with std::list::resize(). However this is mostly
1229 // pointless, because although this arrangement would be as equally
1230 // thread-safe as the implementation below and lessen contention,
1231 // since you don't know exactly what functors will be executed
1232 // anyway if functors are added or removed by one thread while
1233 // another is emitting, such concurrent emitting is not a practice
1234 // to make special provision for. Accordingly, we go the simpler,
1235 // more naive route below.
1236
1237 std::list<ListItem> local_list;
1238 { // scope block for mutex lock
1239 Thread::Mutex::Lock lock{mutex};
1240 local_list = emission_list;
1241 }
1242
1243 for (const auto& l: local_list) {
1244 if (!l.blocked) l.f1(args...);
1245 }
1246 }
1247
1248 template <class... FreeArgs>
1249 bool SafeEmitterArg<FreeArgs...>::test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
1250
1251 std::list<ListItem> local_list;
1252 { // scope block for mutex lock
1253 Thread::Mutex::Lock lock{mutex};
1254 if (emission_list.empty()) return false;
1255 local_list = emission_list;
1256 }
1257
1258 for (const auto& l: local_list) {
1259 if (!l.blocked) l.f1(args...);
1260 }
1261 return true;
1262 }
1263
1264 template <class... FreeArgs>
1265 Callback::SafeFunctorArg<FreeArgs...> SafeEmitterArg<FreeArgs...>::connect(const Callback::SafeFunctorArg<FreeArgs...>& f1) {
1266 // construct the new node outside the mutex to reduce contention and
1267 // then splice it at the end
1268 std::list<ListItem> tmp{ListItem{f1, Callback::SafeFunctorArg<int*>()}};
1269 Thread::Mutex::Lock lock{mutex};
1270 emission_list.splice(emission_list.end(), std::move(tmp));
1271 return f1;
1272 }
1273
1274 template <class... FreeArgs>
1275 Callback::SafeFunctorArg<FreeArgs...> SafeEmitterArg<FreeArgs...>::connect(const Callback::SafeFunctorArg<FreeArgs...>& f1, Releaser& r) {
1276 // In this method:
1277 // f1 is the functor we execute when we emit()
1278 // f2 is the functor we execute in our destructor if we are destroyed before the
1279 // remote object is
1280 // f3 is the functor the remote object executes in its Releaser if it is destroyed
1281 // before we are, or if Releaser::operator=() is called
1282
1283 Callback::SafeFunctor f3{Callback::make_ref(*this, &SafeEmitterArg<FreeArgs...>::tracking_disconnect, f1)};
1284 Callback::SafeFunctorArg<int*> f2{Callback::make_ref(r, &Releaser::try_remove, f3)};
1285 // we can't call Releaser::add() when holding our mutex or we will
1286 // get out of order locking, as Releaser's mutex is acquired in that
1287 // method, and we don't need to do so
1288 r.add(f3);
1289 try {
1290 // construct the new node outside the mutex to reduce contention
1291 // and then splice it at the end
1292 std::list<ListItem> tmp{ListItem{f1, f2}};
1293 Thread::Mutex::Lock lock{mutex};
1294 emission_list.splice(emission_list.end(), std::move(tmp));
1295 }
1296 catch (...) {
1297 r.remove(f3);
1298 throw;
1299 }
1300 return f1;
1301 }
1302
1303 template <class... FreeArgs>
1304 void SafeEmitterArg<FreeArgs...>::disconnect(const Callback::SafeFunctorArg<FreeArgs...>& arg) {
1305 // in theory, we could have connected the same functor object more than
1306 // once, so cater for that as well as Releaser::try_remove() failing
1307 Thread::Mutex::Lock lock{mutex};
1308 auto iter = emission_list.begin();
1309 for(;;) {
1310 iter = std::find_if(iter, emission_list.end(),
1311 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
1312 if (iter != emission_list.end()) {
1313 int result = 0; // f2 might be a no-op
1314 // remove ourselves from the remote Releaser object
1315 (iter->f2)(&result);
1316 if (!result) { // we got the Releaser mutex lock or no-op
1317 // now remove this item from emission_list
1318 iter = emission_list.erase(iter);
1319 }
1320 else {
1321 mutex.unlock();
1322 // spin nicely
1323 #ifdef CGU_USE_SCHED_YIELD
1324 sched_yield();
1325 #else
1326 usleep(10);
1327 #endif
1328 mutex.lock();
1329 // start again at the beginning - we have released the mutex
1330 // so our iterator may have become invalid
1331 iter = emission_list.begin();
1332 }
1333 }
1334 else break;
1335 }
1336 }
1337
1338 // tracking disconnect() is the same as disconnect(), except that we do not
1339 // execute f2 as the remote Releaser object will destroy its own functors
1340 // in that case
1341 template <class... FreeArgs>
1342 void SafeEmitterArg<FreeArgs...>::tracking_disconnect(const Callback::SafeFunctorArg<FreeArgs...>& arg) {
1343 Thread::Mutex::Lock lock{mutex};
1344 auto iter = emission_list.begin();
1345 for (;;) {
1346 iter = std::find_if(iter, emission_list.end(),
1347 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
1348 if (iter != emission_list.end()) {
1349 // remove this item from emission_list
1350 iter = emission_list.erase(iter);
1351 }
1352 else break;
1353 }
1354 }
1355
1356 template <class... FreeArgs>
1357 void SafeEmitterArg<FreeArgs...>::block(const Callback::SafeFunctorArg<FreeArgs...>& arg) {
1358 // in theory, we could have connected the same functor object
1359 // more than once, so cater for that
1360 Thread::Mutex::Lock lock{mutex};
1361 auto iter = emission_list.begin();
1362 for (;;) {
1363 iter = std::find_if(iter, emission_list.end(),
1364 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
1365 if (iter != emission_list.end()) {
1366 iter->blocked = true;
1367 ++iter;
1368 }
1369 else break;
1370 }
1371 }
1372
1373 template <class... FreeArgs>
1374 void SafeEmitterArg<FreeArgs...>::unblock(const Callback::SafeFunctorArg<FreeArgs...>& arg) {
1375 // in theory, we could have connected the same functor object
1376 // more than once, so cater for that
1377 Thread::Mutex::Lock lock{mutex};
1378 auto iter = emission_list.begin();
1379 for (;;) {
1380 iter = std::find_if(iter, emission_list.end(),
1381 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
1382 if (iter != emission_list.end()) {
1383 iter->blocked = false;
1384 ++iter;
1385 }
1386 else break;
1387 }
1388 }
1389
1390 } // namespace Cgu
1391
1392 #endif // EMITTER_H
Cgu::Param
Struct for automatic typing of function parameter arguments.
Definition: param.h:83
Cgu::SafeEmitter
SafeEmitterArg SafeEmitter
Definition: emitter.h:329
Cgu::Callback::make_ref
CallbackArg< FreeArgs... > * make_ref(T &t, void(T::*func)(FreeArgs...))
Definition: callback.h:1352
Cgu
Definition: application.h:44
Cgu::SafeEmitterArg::~SafeEmitterArg
~SafeEmitterArg()
Definition: emitter.h:1147
Cgu::SafeEmitterArg::unblock
void unblock(const Callback::SafeFunctorArg< FreeArgs... > &f)
Definition: emitter.h:1374
Cgu::SafeEmitterArg::test_emit
bool test_emit(typename Cgu::Param< FreeArgs >::ParamType... args) const
Definition: emitter.h:1249
Cgu::SafeEmitterArg::operator=
SafeEmitterArg & operator=(const SafeEmitterArg &)=delete
Cgu::EmitterArg::test_emit
bool test_emit(typename Cgu::Param< FreeArgs >::ParamType... args) const
Definition: emitter.h:749
Cgu::EmitterArg::EmitterArg
EmitterArg()=default
Cgu::Callback::Functor
FunctorArg Functor
Definition: callback.h:778
Cgu::SafeEmitterArg::SafeEmitterArg
SafeEmitterArg()=default
Cgu::EmitterArg::connect
Callback::FunctorArg< FreeArgs... > connect(const Callback::FunctorArg< FreeArgs... > &f)
callback.h
This file provides classes for type erasure.
Cgu::EmitterArg::connect
Callback::FunctorArg< FreeArgs... > connect(F &&f, Releaser &r)
Definition: emitter.h:638
Cgu::SafeEmitterArg::connect
Callback::SafeFunctorArg< FreeArgs... > connect(F &&f, Releaser &r)
Definition: emitter.h:1071
Cgu::EmitterArg::operator=
EmitterArg & operator=(const EmitterArg &)=delete
Cgu::SafeEmitterArg::connect
Callback::SafeFunctorArg< FreeArgs... > connect(const Callback::SafeFunctorArg< FreeArgs... > &f)
Cgu::EmitterArg::unblock
void unblock(const Callback::FunctorArg< FreeArgs... > &f)
Definition: emitter.h:836
Cgu::Releaser::~Releaser
~Releaser()
Cgu::SafeEmitterArg::connect
Callback::SafeFunctorArg< FreeArgs... > connect(F &&f)
Definition: emitter.h:1040
Cgu::Releaser::operator=
Releaser & operator=(const Releaser &r)
Cgu::SafeEmitterArg
A thread-safe class to execute callbacks connected to it, with provision for automatic disconnection.
Definition: emitter.h:327
Cgu::EmitterArg::~EmitterArg
~EmitterArg()
Definition: emitter.h:705
Cgu::Callback::SafeFunctorArg
Functor class holding a Callback::CallbackArg object, with thread-safe reference count.
Definition: callback.h:778
Cgu::EmitterArg::disconnect
void disconnect(const Callback::FunctorArg< FreeArgs... > &f)
Definition: emitter.h:784
Cgu::SafeEmitterArg::block
void block(const Callback::SafeFunctorArg< FreeArgs... > &f)
Definition: emitter.h:1357
Cgu::Thread::Mutex::Lock
A scoped locking class for exception safe Mutex locking.
Definition: mutex.h:207
Cgu::EmitterArg::block
void block(const Callback::FunctorArg< FreeArgs... > &f)
Definition: emitter.h:820
CGU_GLIB_MEMORY_SLICES_FUNCS
#define CGU_GLIB_MEMORY_SLICES_FUNCS
Definition: cgu_config.h:84
Cgu::Thread::Mutex::Lock::unlock
int unlock() noexcept
Definition: mutex.h:277
Cgu::EmitterArg::emit
void emit(typename Cgu::Param< FreeArgs >::ParamType... args) const
Definition: emitter.h:710
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::Emitter
EmitterArg Emitter
Definition: emitter.h:327
Cgu::SafeEmitterArg::operator()
void operator()(typename Cgu::Param< FreeArgs >::ParamType... args) const
Definition: emitter.h:958
Cgu::EmitterArg::connect
Callback::FunctorArg< FreeArgs... > connect(F &&f)
Definition: emitter.h:607
Cgu::EmitterArg
A class to execute callbacks connected to it, with provision for automatic disconnection.
Definition: emitter.h:326
Cgu::Releaser::Releaser
Releaser(const Releaser &r)
Definition: emitter.h:399
Cgu::Callback::FunctorArg
Functor class holding a Callback::CallbackArg object.
Definition: callback.h:777
Cgu::Releaser
A class used for tracking EmitterArg and SafeEmitterArg connections.
Definition: emitter.h:352
Cgu::SafeEmitterArg::disconnect
void disconnect(const Callback::SafeFunctorArg< FreeArgs... > &f)
Definition: emitter.h:1304
Cgu::Releaser::Releaser
Releaser()=default
Cgu::EmitterArg::operator()
void operator()(typename Cgu::Param< FreeArgs >::ParamType... args) const
Definition: emitter.h:529
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:117
Cgu::SafeEmitterArg::emit
void emit(typename Cgu::Param< FreeArgs >::ParamType... args) const
Definition: emitter.h:1176
cgu_config.h