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