c++-gtk-utils: emitter.h Source File

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 2014 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. 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 <utility> // for std::move
315 #include <type_traits> // for std::remove_reference, std::enable_if and std::is_convertible
316
317 #include <c++-gtk-utils/callback.h>
318 #include <c++-gtk-utils/mutex.h>
319 #include <c++-gtk-utils/cgu_config.h>
320
321 namespace Cgu {
322
323 /* The four basic emitter types */
324
325 template <class... FreeArgs> class EmitterArg;
326 template <class... FreeArgs> class SafeEmitterArg;
327 typedef EmitterArg<> Emitter;
328 typedef SafeEmitterArg<> SafeEmitter;
329
330 /**
331 * @class Releaser emitter.h c++-gtk-utils/emitter.h
332 * @brief A class used for tracking EmitterArg and SafeEmitterArg
333 * connections.
334 * @sa EmitterArg SafeEmitterArg
335 * @sa emitter.h
336 * @sa Callback namespace
337 *
338 * This class provides tracking of EmitterArg and SafeEmitterArg
339 * connections. It should be a public member of any target class
340 * which wants functors representing any of its methods to be
341 * disconnected automatically from an EmitterArg or SafeEmitterArg
342 * object when the target class object is destroyed, and is passed as
343 * one of the arguments to the connect() method of EmitterArg or
344 * SafeEmitterArg.
345 *
346 * All its methods are thread-safe.
347 *
348 * For further background, read this: emitter.h
349 */
350
351 class Releaser {
352
353 // from version 2.0.0-rc3 we use std::unordered_set rather than
354 // std::list in Releaser. We can't do that for
355 // EmitterArg/SafeEmitterArg objects, as they need to execute
356 // connected functors in the order in which they were connected.
357 std::unordered_set<Callback::SafeFunctor> disconnect_set;
358 Thread::Mutex mutex;
359
360 // only an EmitterArg or SafeEmitterArg object can access add(), remove and try_remove()
361 void add(const Callback::SafeFunctor&);
362 void remove(const Callback::SafeFunctor&);
363 void try_remove(const Callback::SafeFunctor&, int*);
364 public:
365 template <class... T> friend class EmitterArg;
366 template <class... T> friend class SafeEmitterArg;
367
368 // operator=() and the copy constructor should copy nothing from the
369 // assignor, because disconnect_set should be empty in the
370 // assignee, as any class containing us does not acquire as assignee
371 // any emitter functors representing any of its methods
372
373 /**
374 * See notes on @ref AssignmentAnchor "assignment" to see how this
375 * operates. This does not throw provided that the destructors of any
376 * bound arguments of a functor managed by this Releaser object prior
377 * to assignment do not throw (as they should not do), and assuming
378 * that merely iterating through a list does not throw (as it would
379 * not on any sane implementation).
380 * @param r The assignee.
381 */
382 Releaser& operator=(const Releaser& r);
383
384 /**
385 * This does not copy anything from the Releaser object passed as an
386 * argument - see the notes on @ref AssignmentAnchor "assignment" for
387 * an explanation of why. This does not throw.
388 * @param r A Releaser object.
389 * @exception std::bad_alloc This constructor might throw
390 * std::bad_alloc if memory is exhausted and the system throws in that
391 * case.
392 * @exception Thread::MutexError This constructor might throw
393 * Thread::MutexError if initialisation of the contained mutex fails.
394 * (It is often not worth checking for this, as it means either memory
395 * is exhausted or pthread has run out of other resources to create
396 * new mutexes.)
397 */
398 Releaser(const Releaser& r) {}
399
400 /**
401 * @exception std::bad_alloc The default constructor might throw
402 * std::bad_alloc if memory is exhausted and the system throws in that
403 * case.
404 * @exception Thread::MutexError The default constructor might throw
405 * Thread::MutexError if initialisation of the contained mutex fails.
406 * (It is often not worth checking for this, as it means either memory
407 * is exhausted or pthread has run out of other resources to create
408 * new mutexes.)
409 */
410 Releaser() = default;
411
412 /**
413 * The destructor does not throw provided that the destructors of any
414 * bound arguments of a functor managed by this Releaser object do not
415 * throw (as they should not do), and assuming that merely iterating
416 * through an unordered_set does not throw (as it would not on any
417 * sane implementation).
418 */
419 ~Releaser();
420
421 /* Only has effect if --with-glib-memory-slices-compat or
422 * --with-glib-memory-slices-no-compat option picked */
423 CGU_GLIB_MEMORY_SLICES_FUNCS
424 };
425
426 /* the emitter classes */
427
428 /**
429 * @class EmitterArg emitter.h c++-gtk-utils/emitter.h
430 * @brief A class to execute callbacks connected to it, with provision
431 * for automatic disconnection.
432 * @sa SafeEmitterArg Releaser
433 * @sa emitter.h
434 * @sa Callback namespace
435 *
436 * Callable objects (such as lambda expressions or the return value of
437 * std::bind) or Callback::FunctorArg objects may be connected to
438 * Emitter classes, and will be executed when EmitterArg::emit() or
439 * EmitterArg::operator()() are called.
440 *
441 * One version of the connect() method takes a Releaser object as an
442 * argument. Such a Releaser object should be a public member of any
443 * target class which wants functors representing (or calling into)
444 * any of its methods to be disconnected automatically from the
445 * EmitterArg object when the target class object is destroyed.
446 *
447 * A connection may be explicitly disconnected by calling the
448 * disconnect() method, and may also be temporarily blocked and
449 * subsequently unblocked with the block() and unblock() methods.
450 *
451 * The template types are the types of the unbound arguments, if any.
452 * EmitterArg<> is typedef'ed to Emitter.
453 *
454 * @b Usage
455 *
456 * These are examples:
457 *
458 * @code
459 * using namespace Cgu;
460 *
461 * Emitter e1;
462 * e1.connect([] () {std::cout << "Hello world\n";});
463 * e1();
464 *
465 * int res;
466 * EmitterArg<int, int&> e2;
467 * e2.connect([] (int i, int& j) {j = 10 * i;});
468 * e2(2, res);
469 * std::cout << "10 times 2 is " << res << '\n';
470 * @endcode
471 *
472 * Callback::FunctorArg objects may be connected to an emitter, and
473 * the connect() method may be directly initialized with the result of
474 * Callback::make(), Callback::make_ref() or Callback::lambda() and
475 * implicit conversion will take place. Here is an example using
476 * Callback::make_ref(), with a class object my_obj of type MyClass,
477 * with a method void MyClass::my_method(const Something&, int):
478 *
479 * @code
480 * using namespace Cgu;
481 *
482 * Something arg;
483 * EmitterArg<int> e;
484 * e.connect(Callback::make_ref(my_obj, &MyClass::my_method, arg));
485 * e(5);
486 * @endcode
487 *
488 * For further background, including about thread-safety and exception
489 * safety and other matters, read this: emitter.h, or for more
490 * information about bound and unbound arguments, read this:
491 * Cgu::Callback.
492 */
493
494 template <class... FreeArgs>
495 class EmitterArg {
496
497 #ifndef DOXYGEN_PARSING
498 // f1 is the functor we execute when we emit()
499 // f2 is the functor we execute in our destructor if we are destroyed
500 // before the remote object is
501 struct ListItem {
502 Callback::FunctorArg<FreeArgs...> f1;
503 Callback::Functor f2;
504 bool blocked;
505 ListItem(Callback::FunctorArg<FreeArgs...> f1_, Callback::Functor f2_):
506 f1(f1_), f2(f2_), blocked(false) {}
507 };
508 #endif
509
510 std::list<ListItem> emission_list;
511
512 // only Releaser objects can access this
513 void tracking_disconnect(const Callback::FunctorArg<FreeArgs...>&);
514
515 public:
516 friend class Releaser;
517
518 /**
519 * This will execute the connected functors.
520 * @param args The unbound arguments to be passed to the referenced
521 * function or class method, if any.
522 * @exception std::bad_alloc The method might throw std::bad_alloc if
523 * memory is exhausted and the system throws in that case. In
524 * addition, it will throw if the functions or class methods
525 * referenced by the functors throw (or if the copy constructor of a
526 * free or bound argument throws and it is not a reference argument).
527 */
528 void operator()(typename Cgu::Param<FreeArgs>::ParamType... args) const {emit(args...);}
529
530 /**
531 * This will execute the connected functors.
532 * @param args The unbound arguments to be passed to the referenced
533 * function or class method, if any.
534 * @exception std::bad_alloc The method might throw std::bad_alloc if
535 * memory is exhausted and the system throws in that case. In
536 * addition, it will throw if the functions or class methods
537 * referenced by the functors throw (or if the copy constructor of a
538 * free or bound argument throws and it is not a reference argument).
539 */
540 void emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
541
542 /**
543 * This will execute the connected functors, but it also reports
544 * whether in fact there were any connected functors to execute. (It
545 * is not necessary to use this function just because it is not known
546 * whether a functor is connected - if the standard emit() function is
547 * called when no functor is connected, nothing will happen. The
548 * feature of this method is that it will report the outcome.)
549 * @param args The unbound arguments to be passed to the connected
550 * functions or class methods, if any.
551 * @return Returns false if there were no functors to execute, or true
552 * if functors have been executed.
553 * @exception std::bad_alloc The method might throw std::bad_alloc if
554 * memory is exhausted and the system throws in that case. In
555 * addition, it will throw if the functions or class methods
556 * referenced by the functors throw (or if the copy constructor of a
557 * free or bound argument throws and it is not a reference argument).
558 */
559 bool test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
560
561 /**
562 * Connects a Callback::FunctorArg object.
563 * @param f The Callback::FunctorArg object to connect.
564 * @return The Callback::FunctorArg object connected.
565 * @exception std::bad_alloc The method might throw std::bad_alloc if
566 * memory is exhausted and the system throws in that case.
567 */
568 Callback::FunctorArg<FreeArgs...> connect(const Callback::FunctorArg<FreeArgs...>& f);
569
570 /**
571 * Connects a Callback::FunctorArg object.
572 * @param f The Callback::FunctorArg object to connect.
573 * @param r A Releaser object for automatic disconnection of the
574 * Callback::FunctorArg object if the object whose method it
575 * represents is destroyed.
576 * @return The Callback::FunctorArg object connected.
577 * @exception std::bad_alloc The method might throw std::bad_alloc if
578 * memory is exhausted and the system throws in that case.
579 */
580 Callback::FunctorArg<FreeArgs...> connect(const Callback::FunctorArg<FreeArgs...>& f, Releaser& r);
581
582 /**
583 * Connects a callable object, such as formed by a lambda expression
584 * or the result of std::bind.
585 * @param f The callable object to connect. If must have the same
586 * unbound argument types as the EmitterArg object concerned.
587 * @return A Callback::FunctorArg object which can be passed to
588 * disconnect(), block() or unblock().
589 * @exception std::bad_alloc The method might throw std::bad_alloc if
590 * memory is exhausted and the system throws in that case. If might
591 * also throw if the copy or move constructor of the callable object
592 * throws.
593 *
594 * Since 2.1.0
595 */
596 // we need to use enable_if so that where this function is passed a
597 // Callback::SafeFunctorArg object or a pointer to a
598 // Callback::Callback object or some other convertible object, this
599 // templated overload is dropped from the overload set, in order to
600 // support the deprecated overloads of this function.. This overload
601 // calls into the version of this function taking a
602 // Callback::Functor object in order to perform type erasure.
603 template <class F,
604 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
605 const Callback::FunctorArg<FreeArgs...>>::value>::type>
606 Callback::FunctorArg<FreeArgs...> connect(F&& f) {
607 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)));
608 }
609
610 /**
611 * Connects a callable object, such as formed by a lambda expression
612 * or the result of std::bind.
613 * @param f The callable object to connect. If must have the same
614 * unbound argument types as the EmitterArg object concerned.
615 * @param r A Releaser object for automatic disconnection of the
616 * callable object if an object whose method it represents or calls
617 * into is destroyed.
618 * @return A Callback::FunctorArg object which can be passed to
619 * disconnect(), block() or unblock().
620 * @exception std::bad_alloc The method might throw std::bad_alloc if
621 * memory is exhausted and the system throws in that case. If might
622 * also throw if the copy or move constructor of the callable object
623 * throws.
624 *
625 * Since 2.1.0
626 */
627 // we need to use enable_if so that where this function is passed a
628 // Callback::SafeFunctorArg object or a pointer to a
629 // Callback::Callback object or some other convertible object, this
630 // templated overload is dropped from the overload set, in order to
631 // support the deprecated overloads of this function.. This overload
632 // calls into the version of this function taking a
633 // Callback::Functor object in order to perform type erasure.
634 template <class F,
635 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
636 const Callback::FunctorArg<FreeArgs...>>::value>::type>
637 Callback::FunctorArg<FreeArgs...> connect(F&& f, Releaser& r) {
638 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)), r);
639 }
640
641 /**
642 * Disconnects a functor previously connected. This does not throw
643 * provided that the destructors of any bound arguments do not throw
644 * (as they should not do), and assuming that merely iterating through
645 * a list does not throw (as it would not on any sane implementation).
646 * @param f The functor to disconnect.
647 * @note If the same functor has been connected more than once to the
648 * same EmitterArg object, this call will disconnect all of them.
649 */
650 void disconnect(const Callback::FunctorArg<FreeArgs...>& f);
651
652 /**
653 * Blocks a connected functor from executing when emit() or
654 * operator()() is called until unblock() is called. This method does
655 * not throw (assuming that merely iterating through a list does not
656 * throw, as it would not on any sane implementation).
657 * @param f The functor to block.
658 * @note If the same functor has been connected more than once to the
659 * same EmitterArg object, this call will block all of them.
660 */
661 void block(const Callback::FunctorArg<FreeArgs...>& f);
662
663 /**
664 * Unblocks a previously blocked functor. This method does not throw
665 * (assuming that merely iterating through a list does not throw, as
666 * it would not on any sane implementation).
667 * @param f The functor to unblock.
668 * @note If the same functor has been connected more than once to the
669 * same EmitterArg object, this call will unblock all of them.
670 */
671 void unblock(const Callback::FunctorArg<FreeArgs...>& f);
672
673 /**
674 * @exception std::bad_alloc The constructor might throw
675 * std::bad_alloc if memory is exhausted and the system throws in that
676 * case.
677 */
678 EmitterArg() = default;
679
680 /**
681 * This class cannot be copied. The copy constructor is deleted.
682 */
683 EmitterArg(const EmitterArg&) = delete;
684
685 /**
686 * This class cannot be copied. The assignment operator is deleted.
687 */
688 EmitterArg& operator=(const EmitterArg&) = delete;
689
690 /**
691 * The destructor does not throw provided that the destructors of any
692 * bound arguments do not throw (as they should not do), and assuming
693 * that merely iterating through a list does not throw (as it would
694 * not on any sane implementation).
695 */
696 ~EmitterArg();
697
698 /* Only has effect if --with-glib-memory-slices-compat or
699 * --with-glib-memory-slices-no-compat option picked */
700 CGU_GLIB_MEMORY_SLICES_FUNCS
701 };
702
703 template <class... FreeArgs>
704 EmitterArg<FreeArgs...>::~EmitterArg() {
705 for(const auto& l: emission_list) {l.f2();}
706 }
707
708 template <class... FreeArgs>
709 void EmitterArg<FreeArgs...>::emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
710
711 // create a local copy of emission_list, to enable a connected
712 // function (i) to delete the EmitterArg<> object to which it is
713 // connected, even if there are other functors still to execute in
714 // the same emission (which will execute normally provided they do
715 // not try to call any of the emitter's functions), (ii) to call
716 // 'delete this' nothwithstanding that the connected function is
717 // protected by a Releaser object (assuming all the other restraints
718 // on calling 'delete this' are met), provided that no other access
719 // would be made to the deleted object in a function call connected
720 // to the same emitter which is due to execute subsequently in the
721 // same emission, and (iii) to disconnect itself from the
722 // EmitterArg object. This design approach has a trade-off: if a
723 // connected function tries to block, unblock or disconnect another
724 // function connected to the same EmitterArg<> object which is due
725 // to execute subsequently in the same emission (or to block,
726 // unblock or disconnect itself when it is due to execute again
727 // subsequently in the same emission), the attempted block, unblock
728 // or disconnection will not have any effect on that emission (it
729 // will only have effect on a subsequent emission). In addition, a
730 // connected function may not destroy an object whose non-static
731 // method is connected to the same emitter and which would execute
732 // subsequently in the same emission, even if that object is
733 // protected by a Releaser object (the non-static method will
734 // unsuccessfully attempt to execute notwithstanding the destruction
735 // of the object it would be operating on).
736
737 // we can't use uniform initialisation here as it would be
738 // construed as invoking an initialiser list with a list item,
739 // rather than passing an already formed list
740 std::list<ListItem> local_list = emission_list;
741
742 for (const auto& l: local_list) {
743 if (!l.blocked) l.f1(args...);
744 }
745 }
746
747 template <class... FreeArgs>
748 bool EmitterArg<FreeArgs...>::test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
749 if (emission_list.empty()) return false;
750 emit(args...);
751 return true;
752 }
753
754 template <class... FreeArgs>
755 Callback::FunctorArg<FreeArgs...> EmitterArg<FreeArgs...>::connect(const Callback::FunctorArg<FreeArgs...>& f1) {
756 emission_list.emplace_back(f1, Callback::Functor());
757 return f1;
758 }
759
760 template <class... FreeArgs>
761 Callback::FunctorArg<FreeArgs...> EmitterArg<FreeArgs...>::connect(const Callback::FunctorArg<FreeArgs...>& f1, Releaser& r) {
762 // In this method:
763 // f1 is the functor we execute when we emit()
764 // f2 is the functor we execute in our destructor if we are destroyed before the
765 // remote object is
766 // f3 is the functor the remote object executes in its Releaser if it is destroyed
767 // before we are, or if Releaser::operator=() is called
768
769 Callback::SafeFunctor f3{Callback::make_ref(*this, &EmitterArg<FreeArgs...>::tracking_disconnect, f1)};
770 Callback::Functor f2{Callback::make_ref(r, &Releaser::remove, f3)};
771 r.add(f3);
772 try {
773 emission_list.emplace_back(f1, f2);
774 }
775 catch (...) {
776 r.remove(f3);
777 throw;
778 }
779 return f1;
780 }
781
782 template <class... FreeArgs>
783 void EmitterArg<FreeArgs...>::disconnect(const Callback::FunctorArg<FreeArgs...>& arg) {
784 // in theory, we could have connected the same functor object
785 // more than once, so cater for that
786 auto iter = emission_list.begin();
787 for (;;) {
788 iter = std::find_if(iter, emission_list.end(),
789 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
790 if (iter != emission_list.end()) {
791 // remove ourselves from the remote Releaser object
792 (iter->f2)();
793
794 // remove this item from emission_list
795 iter = emission_list.erase(iter);
796 }
797 else break;
798 }
799 }
800
801 // tracking disconnect() is the same as disconnect(), except that we do not
802 // execute f2 as the remote Releaser object will destroy its own functors
803 // in that case
804 template <class... FreeArgs>
805 void EmitterArg<FreeArgs...>::tracking_disconnect(const Callback::FunctorArg<FreeArgs...>& arg) {
806 auto iter = emission_list.begin();
807 for (;;) {
808 iter = std::find_if(iter, emission_list.end(),
809 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
810 if (iter != emission_list.end()) {
811 // remove this item from emission_list
812 iter = emission_list.erase(iter);
813 }
814 else break;
815 }
816 }
817
818 template <class... FreeArgs>
819 void EmitterArg<FreeArgs...>::block(const Callback::FunctorArg<FreeArgs...>& arg) {
820 // in theory, we could have connected the same functor object
821 // more than once, so cater for that
822 auto iter = emission_list.begin();
823 for (;;) {
824 iter = std::find_if(iter, emission_list.end(),
825 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
826 if (iter != emission_list.end()) {
827 iter->blocked = true;
828 ++iter;
829 }
830 else break;
831 }
832 }
833
834 template <class... FreeArgs>
835 void EmitterArg<FreeArgs...>::unblock(const Callback::FunctorArg<FreeArgs...>& arg) {
836 // in theory, we could have connected the same functor object
837 // more than once, so cater for that
838 auto iter = emission_list.begin();
839 for (;;) {
840 iter = std::find_if(iter, emission_list.end(),
841 [&arg](const ListItem& p) -> bool {return p.f1 == arg;});
842 if (iter != emission_list.end()) {
843 iter->blocked = false;
844 ++iter;
845 }
846 else break;
847 }
848 }
849
850 /**
851 * @class SafeEmitterArg emitter.h c++-gtk-utils/emitter.h
852 * @brief A thread-safe class to execute callbacks connected to it,
853 * with provision for automatic disconnection.
854 * @sa EmitterArg Releaser
855 * @sa emitter.h
856 * @sa Callback namespace
857 *
858 * This is a thread-safe version of the EmitterArg class. Callable
859 * objects (such as lambda expressions or the return value of
860 * std::bind) or Callback::SafeFunctorArg objects may be connected to
861 * SafeEmitter classes (referred to be below as "connected
862 * callables"), and will be executed when SafeEmitterArg::emit() or
863 * SafeEmitterArg::operator()() are called.
864 *
865 * One version of the connect() method takes a Releaser object as an
866 * argument. Such a Releaser object should be a public member of any
867 * target class which wants connected callables representing (or
868 * calling into) any of its methods to be disconnected automatically
869 * from the SafeEmitterArg object when the target class object is
870 * destroyed.
871 *
872 * A connection may be explicitly disconnected by calling the
873 * disconnect() method, and may also be temporarily blocked and
874 * subsequently unblocked with the block() and unblock() methods.
875 *
876 * The template types are the types of the unbound arguments, if any.
877 * SafeEmitterArg<> is typedef'ed to SafeEmitter.
878 *
879 * @b Usage
880 *
881 * These are examples:
882 *
883 * @code
884 * using namespace Cgu;
885 *
886 * SafeEmitter se1;
887 * se1.connect([] () {std::cout << "Hello world\n";});
888 * se1();
889 *
890 * int res;
891 * SafeEmitterArg<int, int&> se2;
892 * se2.connect([] (int i, int& j) {j = 10 * i;});
893 * se2(2, res);
894 * std::cout << "10 times 2 is " << res << '\n';
895 * @endcode
896 *
897 * Callback::SafeFunctorArg objects may be connected to an emitter,
898 * and the connect() method may be directly initialized with the
899 * result of Callback::make(), Callback::make_ref() or
900 * Callback::lambda() and implicit conversion will take place. Here
901 * is an example using Callback::make_ref(), with a class object
902 * my_obj of type MyClass, with a method void MyClass::my_method(const
903 * Something&, int):
904 *
905 * @code
906 * using namespace Cgu;
907 *
908 * Something arg;
909 * SafeEmitterArg<int> se;
910 * se.connect(Callback::make_ref(my_obj, &MyClass::my_method, arg));
911 * se(5);
912 * @endcode
913 *
914 * For further background, including about thread-safety and exception
915 * safety and other matters, read this: emitter.h, or for more
916 * information about bound and unbound arguments, read this:
917 * Cgu::Callback.
918 */
919
920 template <class... FreeArgs>
921 class SafeEmitterArg {
922
923 #ifndef DOXYGEN_PARSING
924 // f1 is the functor we execute when we emit()
925 // f2 is the functor we execute in our destructor if we are destroyed
926 // before the remote object is
927 struct ListItem {
928 Callback::SafeFunctorArg<FreeArgs...> f1;
929 Callback::SafeFunctorArg<int*> f2;
930 bool blocked;
931 ListItem(Callback::SafeFunctorArg<FreeArgs...> f1_, Callback::SafeFunctorArg<int*> f2_):
932 f1(f1_), f2(f2_), blocked(false) {}
933 };
934 #endif
935
936 std::list<ListItem> emission_list;
937 mutable Thread::Mutex mutex; // make this mutable so we can lock/unlock in const methods
938
939 // only Releaser objects can access this
940 void tracking_disconnect(const Callback::SafeFunctorArg<FreeArgs...>&);
941
942 public:
943 friend class Releaser;
944
945 /**
946 * This will execute the connected functors. It is thread safe if the
947 * functions or class methods referenced by the connected functors are
948 * thread safe.
949 * @param args The unbound arguments to be passed to the referenced
950 * function or class method, if any.
951 * @exception std::bad_alloc The method might throw std::bad_alloc if
952 * memory is exhausted and the system throws in that case. In
953 * addition, it will throw if the functions or class methods
954 * referenced by the functors throw (or if the copy constructor of a
955 * free or bound argument throws and it is not a reference argument).
956 */
957 void operator()(typename Cgu::Param<FreeArgs>::ParamType... args) const {emit(args...);}
958
959 /**
960 * This will execute the connected functors. It is thread safe if the
961 * functions or class methods referenced by the connected functors are
962 * thread safe.
963 * @param args The unbound arguments to be passed to the referenced
964 * function or class method, if any.
965 * @exception std::bad_alloc The method might throw std::bad_alloc if
966 * memory is exhausted and the system throws in that case. In
967 * addition, it will throw if the functions or class methods
968 * referenced by the functors throw (or if the copy constructor of a
969 * free or bound argument throws and it is not a reference argument).
970 */
971 void emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
972
973 /**
974 * This will execute the connected functors, but it also reports
975 * whether in fact there were any connected functors to execute. It
976 * is thread safe if the functions or class methods referenced by the
977 * connected functors are thread safe. (It is not necessary to use
978 * this function just because it is not known whether a functor is
979 * connected - if the standard emit() function is called when no
980 * functor is connected, nothing will happen. The feature of this
981 * method is that it will report the outcome.)
982 * @param args The unbound arguments to be passed to the referenced
983 * function or class method, if any.
984 * @return Returns false if there were no functors to execute, or true
985 * if functors have been executed.
986 * @exception std::bad_alloc The method might throw std::bad_alloc if
987 * memory is exhausted and the system throws in that case. In
988 * addition, it will throw if the functions or class methods
989 * referenced by the functors throw (or if the copy constructor of a
990 * free or bound argument throws and it is not a reference argument).
991 */
992 bool test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const;
993
994 /**
995 * Connects a Callback::SafeFunctorArg object.
996 * @param f The Callback::SafeFunctorArg object to connect.
997 * @return The Callback::SafeFunctorArg object connected.
998 * @exception std::bad_alloc The method might throw std::bad_alloc if
999 * memory is exhausted and the system throws in that case.
1000 */
1001 Callback::SafeFunctorArg<FreeArgs...> connect(const Callback::SafeFunctorArg<FreeArgs...>& f);
1002
1003 /**
1004 * Connects a Callback::SafeFunctorArg object.
1005 * @param f The Callback::SafeFunctorArg object to connect.
1006 * @param r A Releaser object for automatic disconnection of the
1007 * Callback::SafeFunctorArg object if the object whose method it
1008 * represents is destroyed.
1009 * @return The Callback::SafeFunctorArg object connected.
1010 * @exception std::bad_alloc The method might throw std::bad_alloc if
1011 * memory is exhausted and the system throws in that case.
1012 */
1013 Callback::SafeFunctorArg<FreeArgs...> connect(const Callback::SafeFunctorArg<FreeArgs...>& f, Releaser& r);
1014
1015 /**
1016 * Connects a callable object, such as formed by a lambda expression
1017 * or the result of std::bind.
1018 * @param f The callable object to connect. If must have the same
1019 * unbound argument types as the SafeEmitterArg object concerned.
1020 * @return A Callback::SafeFunctorArg object which can be passed to
1021 * disconnect(), block() or unblock().
1022 * @exception std::bad_alloc The method might throw std::bad_alloc if
1023 * memory is exhausted and the system throws in that case. If might
1024 * also throw if the copy or move constructor of the callable object
1025 * throws.
1026 *
1027 * Since 2.1.0
1028 */
1029 // we need to use enable_if so that where this function is passed a
1030 // Callback::SafeFunctorArg object or a pointer to a
1031 // Callback::Callback object or some other convertible object, this
1032 // templated overload is dropped from the overload set, in order to
1033 // support the Callback::SafeFunctorArg overloads of this function.
1034 // This overload calls into the version of this function taking a
1035 // Callback::SafeFunctor object in order to perform type erasure.
1036 template <class F,
1037 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
1038 const Callback::SafeFunctorArg<FreeArgs...>>::value>::type>
1039 Callback::SafeFunctorArg<FreeArgs...> connect(F&& f) {
1040 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)));
1041 }
1042
1043 /**
1044 * Connects a callable object, such as formed by a lambda expression
1045 * or the result of std::bind.
1046 * @param f The callable object to connect. If must have the same
1047 * unbound argument types as the SafeEmitterArg object concerned.
1048 * @param r A Releaser object for automatic disconnection of the
1049 * callable object if an object whose method it represents or calls
1050 * into is destroyed.
1051 * @return A Callback::SafeFunctorArg object which can be passed to
1052 * disconnect(), block() or unblock().
1053 * @exception std::bad_alloc The method might throw std::bad_alloc if
1054 * memory is exhausted and the system throws in that case. If might
1055 * also throw if the copy or move constructor of the callable object
1056 * throws.
1057 *
1058 * Since 2.1.0
1059 */
1060 // we need to use enable_if so that where this function is passed a
1061 // Callback::SafeFunctorArg object or a pointer to a
1062 // Callback::Callback object or some other convertible object, this
1063 // templated overload is dropped from the overload set, in order to
1064 // support the Callback::SafeFunctorArg overloads of this function.
1065 // This overload calls into the version of this function taking a
1066 // Callback::SafeFunctor object in order to perform type erasure.
1067 template <class F,
1068 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
1069 const Callback::SafeFunctorArg<FreeArgs...>>::value>::type>
1070 Callback::SafeFunctorArg<FreeArgs...> connect(F&& f, Releaser& r) {
1071 return connect(Callback::lambda<FreeArgs...>(std::forward<F>(f)), r);
1072 }
1073
1074 /**
1075 * Disconnects a functor previously connected. This does not throw
1076 * provided that the destructors of any bound arguments do not throw
1077 * (as they should not do), and assuming that merely iterating through
1078 * a list does not throw (as it would not on any sane implementation).
1079 * It is thread safe.
1080 * @param f The functor to disconnect.
1081 * @note If the same functor has been connected more than once to the
1082 * same SafeEmitterArg object, this call will disconnect all of them.
1083 */
1084 void disconnect(const Callback::SafeFunctorArg<FreeArgs...>& f);
1085
1086 /**
1087 * Blocks a connected functor from executing when emit() or
1088 * operator()() is called until unblock() is called. This method does
1089 * not throw (assuming that merely iterating through a list does not
1090 * throw, as it would not on any sane implementation). It is thread
1091 * safe.
1092 * @param f The functor to block.
1093 * @note If the same functor has been connected more than once to the
1094 * same SafeEmitterArg object, this call will block all of them.
1095 */
1096 void block(const Callback::SafeFunctorArg<FreeArgs...>& f);
1097
1098 /**
1099 * Unblocks a previously blocked functor. This method does not throw
1100 * (assuming that merely iterating through a list does not throw, as
1101 * it would not on any sane implementation). It is thread safe.
1102 * @param f The functor to unblock.
1103 * @note If the same functor has been connected more than once to the
1104 * same SafeEmitterArg object, this call will unblock all of them.
1105 */
1106 void unblock(const Callback::SafeFunctorArg<FreeArgs...>& f);
1107
1108 /**
1109 * @exception std::bad_alloc The constructor might throw
1110 * std::bad_alloc if memory is exhausted and the system throws in that
1111 * case.
1112 * @exception Thread::MutexError The constructor might throw
1113 * Thread::MutexError if initialisation of the contained mutex fails.
1114 * (It is often not worth checking for this, as it means either memory
1115 * is exhausted or pthread has run out of other resources to create
1116 * new mutexes.)
1117 */
1118 SafeEmitterArg() = default;
1119
1120 /**
1121 * This class cannot be copied. The copy constructor is deleted.
1122 */
1123 SafeEmitterArg(const SafeEmitterArg&) = delete;
1124
1125 /**
1126 * This class cannot be copied. The assignment operator is deleted.
1127 */
1128 SafeEmitterArg& operator=(const SafeEmitterArg&) = delete;
1129
1130 /**
1131 * The destructor does not throw provided that the destructors of any
1132 * bound arguments do not throw (as they should not do), and assuming
1133 * that merely iterating through a list does not throw (as it would
1134 * not on any sane implementation). It is thread-safe as regards the
1135 * dropping of any connected functors and of any relevant Releaser
1136 * objects.
1137 */
1138 ~SafeEmitterArg();
1139
1140 /* Only has effect if --with-glib-memory-slices-compat or
1141 * --with-glib-memory-slices-no-compat option picked */
1142 CGU_GLIB_MEMORY_SLICES_FUNCS
1143 };
1144
1145 template <class... FreeArgs>
1146 SafeEmitterArg<FreeArgs...>::~SafeEmitterArg() {
1147
1148 // go through emission_list() item by item, popping off the front and erasing
1149 // as we go in case Releaser::try_remove() fails to acquire the lock on one
1150 // of the iterations
1151 Thread::Mutex::Lock lock{mutex};
1152 while (!emission_list.empty()) {
1153 auto iter = emission_list.begin();
1154 int result = 0; // f2 might be a no-op
1155 // remove ourselves from the remote Releaser object
1156 (iter->f2)(&result);
1157 if (!result) { // we got the Releaser mutex lock or no-op
1158 // now remove this item from emission_list
1159 emission_list.erase(iter);
1160 }
1161 else {
1162 mutex.unlock();
1163 // spin nicely
1164 #ifdef CGU_USE_SCHED_YIELD
1165 sched_yield();
1166 #else
1167 usleep(10);
1168 #endif
1169 mutex.lock();
1170 }
1171 }
1172 }
1173
1174 template <class... FreeArgs>
1175 void SafeEmitterArg<FreeArgs...>::emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
1176
1177 // create a local copy of emission_list, to enable a connected
1178 // function (i) to delete the EmitterArg<> object to which it is
1179 // connected, even if there are other functors still to execute in
1180 // the same emission (which will execute normally provided they do
1181 // not try to call any of the emitter's functions), (ii) to call
1182 // 'delete this' nothwithstanding that the connected function is
1183 // protected by a Releaser object (assuming all the other restraints
1184 // on calling 'delete this' are met), provided that no other access
1185 // would be made to the deleted object in a function call connected
1186 // to the same emitter which is due to execute subsequently in the
1187 // same emission, and (iii) to disconnect itself from the
1188 // EmitterArg<> object. This design approach has a trade-off: if a
1189 // connected function tries to block, unblock or disconnect another
1190 // function connected to the same EmitterArg<> object which is due
1191 // to execute subsequently in the same emission (or to block,
1192 // unblock or disconnect itself when it is due to execute again
1193 // subsequently in the same emission), the attempted block, unblock
1194 // or disconnection will not have any effect on that emission (it
1195 // will only have effect on a subsequent emission). In addition, a
1196 // connected function may not destroy an object whose non-static
1197 // method is connected to the same emitter and which would execute
1198 // subsequently in the same emission, even if that object is
1199 // protected by a Releaser object (the non-static method will
1200 // unsuccessfully attempt to execute notwithstanding the destruction
1201 // of the object it would be operating on).
1202
1203 // SafeFunctorArg usage has the additional point that while an
1204 // emission is in course, another thread should not try to do any of
1205 // those things, or the same outcome will result. Another thread
1206 // should leave alone objects connected to a SafeEmitterArg<> object
1207 // from the time of operator()() or emit() beginning to the time of
1208 // it ending, and not try to interfere.
1209
1210 // a side effect of having a local list is that, as required, we
1211 // will not be holding our mutex when executing the functors it
1212 // contains. It is OK having the functors in two different lists
1213 // which are potentially (when our mutex is released) in two
1214 // different threads, because the functors hold their
1215 // Callback::Callback objects by SharedLockPtr so their reference
1216 // count is protected (they are SafeFunctorArg<> functors).
1217
1218 // we could reduce contention on the mutex by allocating local_list
1219 // outside the mutex, eg by taking the size of emission_list within
1220 // the mutex, then allocating the nodes of local_list outside the
1221 // mutex with that size, and then copying items across within the
1222 // mutex (checking the end iterators of both containers when
1223 // iterating because the size of emitter_list could have changed
1224 // while allocating local_list) and, if the size of emission list
1225 // did change by another thread disconnecting a functor in the
1226 // interval when local_list was allocated, resizing local_list
1227 // downwards with std::list::resize(). However this is mostly
1228 // pointless, because although this arrangement would be as equally
1229 // thread-safe as the implementation below and lessen contention,
1230 // since you don't know exactly what functors will be executed
1231 // anyway if functors are added or removed by one thread while
1232 // another is emitting, such concurrent emitting is not a practice
1233 // to make special provision for. Accordingly, we go the simpler,
1234 // more naive route below.
1235
1236 std::list<ListItem> local_list;
1237 { // scope block for mutex lock
1238 Thread::Mutex::Lock lock{mutex};
1239 local_list = emission_list;
1240 }
1241
1242 for (const auto& l: local_list) {
1243 if (!l.blocked) l.f1(args...);
1244 }
1245 }
1246
1247 template <class... FreeArgs>
1248 bool SafeEmitterArg<FreeArgs...>::test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const {
1249
1250 std::list<ListItem> local_list;
1251 { // scope block for mutex lock
1252 Thread::Mutex::Lock lock{mutex};
1253 if (emission_list.empty()) return false;
1254 local_list = emission_list;
1255 }
1256
1257 for (const auto& l: local_list) {
1258 if (!l.blocked) l.f1(args...);
1259 }
1260 return true;
1261 }
1262
1263 template <class... FreeArgs>
1264 Callback::SafeFunctorArg<FreeArgs...> SafeEmitterArg<FreeArgs...>::connect(const Callback::SafeFunctorArg<FreeArgs...>& f1) {
1265 // construct the new node outside the mutex to reduce contention and
1266 // then splice it at the end
1267 std::list<ListItem> tmp{ListItem{f1, Callback::SafeFunctorArg<int*>()}};
1268 Thread::Mutex::Lock lock{mutex};
1269 emission_list.splice(emission_list.end(), std::move(tmp));
1270 return f1;
1271 }
1272
1273 template <class... FreeArgs>
1274 Callback::SafeFunctorArg<FreeArgs...> SafeEmitterArg<FreeArgs...>::connect(const Callback::SafeFunctorArg<FreeArgs...>& f1, Releaser& r) {
1275 // In this method:
1276 // f1 is the functor we execute when we emit()
1277 // f2 is the functor we execute in our destructor if we are destroyed before the
1278 // remote object is
1279 // f3 is the functor the remote object executes in its Releaser if it is destroyed
1280 // before we are, or if Releaser::operator=() is called
1281
1282 Callback::SafeFunctor f3{Callback::make_ref(*this, &SafeEmitterArg<FreeArgs...>::tracking_disconnect, f1)};
1283 Callback::SafeFunctorArg<int*> f2{Callback::make_ref(r, &Releaser::try_remove, f3)};
1284 // we can't call Releaser::add() when holding our mutex or we will
1285 // get out of order locking, as Releaser's mutex is acquired in that
1286 // method, and we don't need to do so
1287 r.add(f3);
1288 try {
1289 // construct the new node outside the mutex to reduce contention
1290 // and then splice it at the end
1291 std::list<ListItem> tmp{ListItem{f1, f2}};
1292 Thread::Mutex::Lock lock{mutex};
1293 emission_list.splice(emission_list.end(), std::move(tmp));
1294 }
1295 catch (...) {
1296 r.remove(f3);
1297 throw;
1298 }
1299 return f1;
1300 }
1301
1302 template <class... FreeArgs>
1303 void SafeEmitterArg<FreeArgs...>::disconnect(const Callback::SafeFunctorArg<FreeArgs...>& arg) {
1304 // in theory, we could have connected the same functor object more than
1305 // once, so cater for that as well as Releaser::try_remove() failing
1306 Thread::Mutex::Lock lock{mutex};
1307 auto iter = emission_list.begin();
1308 for(;;) {
1309 // gcc-4.4 doesn't support lambdas:
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