c++-gtk-utils
|
00001 /* Copyright (C) 2009 to 2011 Chris Vine 00002 00003 The library comprised in this file or of which this file is part is 00004 distributed by Chris Vine under the GNU Lesser General Public 00005 License as follows: 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public License 00009 as published by the Free Software Foundation; either version 2.1 of 00010 the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but 00013 WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License, version 2.1, for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License, version 2.1, along with this library (see the file LGPL.TXT 00019 which came with this source code package in the c++-gtk-utils 00020 sub-directory); if not, write to the Free Software Foundation, Inc., 00021 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00022 00023 However, it is not intended that the object code of a program whose 00024 source code instantiates a template from this file or uses macros or 00025 inline functions (of any length) should by reason only of that 00026 instantiation or use be subject to the restrictions of use in the GNU 00027 Lesser General Public License. With that in mind, the words "and 00028 macros, inline functions and instantiations of templates (of any 00029 length)" shall be treated as substituted for the words "and small 00030 macros and small inline functions (ten lines or less in length)" in 00031 the fourth paragraph of section 5 of that licence. This does not 00032 affect any other reason why object code may be subject to the 00033 restrictions in that licence (nor for the avoidance of doubt does it 00034 affect the application of section 2 of that licence to modifications 00035 of the source code in this file). 00036 00037 */ 00038 00039 #ifndef CGU_EMITTER_H 00040 #define CGU_EMITTER_H 00041 00042 /** 00043 * @file emitter.h 00044 * @brief This file provides a thread-safe signal/slot mechanism, with 00045 * automatic disconnection. 00046 * 00047 * An EmitterArg object is a list of Callback::FunctorArg objects. 00048 * Callback::FunctorArg objects may be "connected" to the EmitterArg 00049 * object, and all functors so connected will be executed when the 00050 * operator()() or emit() member functions of the EmitterArg object 00051 * concerned is called. They will be called in the order in which 00052 * they were connected. Emitter is a typedef for EmitterArg<>. The 00053 * generalised EmitterArg<T...> type contains 00054 * Callback::FunctorArg<T...> objects (type T being the unbound 00055 * arguments of a Callback::CallbackArg<T...> callback - see 00056 * Cgu::Callback for further details, and "Usage" below for examples.) 00057 * The Emitter type holds Callback::Functor (namely 00058 * Callback::FunctorArg<>) objects. 00059 * 00060 * The main advantage of an emitter object as opposed to storing a 00061 * functor object directly, apart from the fact that more than one 00062 * functor can be dispatched by a single call to EmitterArg::emit() or 00063 * EmitterArg::operator()(), is that it provides for automatic 00064 * disconnection of a functor if the object whose member function it 00065 * represents has ceased to exist. 00066 * 00067 * Where automatic disconnection is wanted, the object whose method is 00068 * to be encapsulated by a functor must have a Releaser object as a 00069 * public member function. The Releaser object should be passed as 00070 * the second argument of EmitterArg::connect(). As well as a 00071 * Releaser object informing an emitter object when it has ceased to 00072 * exist, an emitter object will do the same to the Releaser object if 00073 * the emitter object happens to be destroyed before an object whose 00074 * members it references (and therefore before the Releaser object). 00075 * Automatic disconnection is mainly useful for non-static member 00076 * functions, but it can be employed for static member functions or 00077 * non-member functions if wanted (that will in effect bind the 00078 * lifetime of the functor to that of the object to whose Releaser the 00079 * functor has been attached.) 00080 * 00081 * It is safe for a connected function (i) to delete the EmitterArg 00082 * object to which it is connected, even if there are other functors 00083 * still to execute in the same emission (which will execute normally 00084 * provided they do not try to call any of the emitter's functions), 00085 * (ii) to call 'delete this' nothwithstanding that the connected 00086 * function is protected by a Releaser object (assuming all the other 00087 * restraints on calling 'delete this' are met), provided that no 00088 * other access would be made to the deleted object in a function call 00089 * connected to the same emitter which is due to execute subsequently 00090 * in the same emission, and (iii) to disconnect itself from the 00091 * EmitterArg object. This design approach has a trade-off: if a 00092 * connected function tries to block, unblock or disconnect another 00093 * function connected to the same EmitterArg object which is due to 00094 * execute subsequently in the same emission (or to block, unblock or 00095 * disconnect itself when it is due to execute again subsequently in 00096 * the same emission), the attempted block, unblock or disconnection 00097 * will not have any effect on that emission (it will only have effect 00098 * on a subsequent emission). In addition, a connected function may 00099 * not destroy an object whose non-static method is connected to the 00100 * same emitter and which would execute subsequently in the same 00101 * emission, even if that object is protected by a Releaser object 00102 * (the non-static method will unsuccessfully attempt to execute 00103 * notwithstanding the destruction of the object it would be operating 00104 * on). 00105 * 00106 * The SafeEmitterArg classes are the same as their EmitterArg 00107 * counterparts except that they contain Callback::SafeFunctorArg 00108 * objects, and their emit(), operator()(), connect(), disconnect(), 00109 * block(), unblock() and destructor methods are protected by a mutex 00110 * so that different threads can call these methods on the same 00111 * emitter object, or create and delete the object. 00112 * 00113 * Note that the mutexes are released when the operator()()/emit() 00114 * methods of the relevent Callback::SafeFunctorArg objects are 00115 * called, as SafeEmitterArg objects have no idea what the referenced 00116 * callbacks will do so if they were not released deadlocks could 00117 * arise from recursive or out-of-order locking of the SafeEmitterArg 00118 * mutex. It is therefore for users to provide additional 00119 * synchronisation if the functions encapsulated by the relevant 00120 * functors themselves need additional protection. Note also the 00121 * subsidiary thread-safety points mentioned below. 00122 * 00123 * The Releaser class is intrinsically thread safe (the overhead of 00124 * locking is so low that it is pointless having a separate 00125 * unprotected class). This means that if a program is 00126 * multi-threaded, you can use the plain EmitterArg classes provided 00127 * that only the thread which creates a particular EmitterArg object 00128 * calls connect(), block(), unblock((), emit() or operator()() on it, 00129 * or deletes it, or calls disconnect() on it (either directly or 00130 * through a Releaser object being destroyed). Where more than one 00131 * thread might do that in relation to any one emitter object, use 00132 * SafeEmitterArg. 00133 * 00134 * @b Alternatives 00135 * 00136 * These classes are intended as a lightweight thread-safe signal/slot 00137 * mechanism for GUI programming. For more demanding usage libsigc++ 00138 * is a good choice, except that it is not thread-safe. An 00139 * alternative to libsigc++ is the boost::signal2 module, which is 00140 * thread-safe. 00141 * 00142 * @b Subsidiary @b thread-safety @b points 00143 * 00144 * As mentioned, the SafeEmitterArg classes are thread safe, and their 00145 * methods can be called in different threads without ill effect. 00146 * However, there are some things that cannot be done. Users should 00147 * observe two points. 00148 * 00149 * First, it has been mentioned that if a connected function blocks, 00150 * unblocks or disconnects another function connected to the same 00151 * emitter object and due to execute subsequently in the same 00152 * emission, the blocking, unblocking or disconnection will not have 00153 * effect in that emission, and that a connected function may not 00154 * delete an object whose non-static method is due to execute 00155 * subsequently in the same emission. The same outcome would result 00156 * if another thread tries to do any of these things while an emission 00157 * is under way. Another thread should therefore leave alone objects 00158 * connected to a SafeEmitterArg object from the time of operator()() 00159 * or emit() beginning to the time of it ending, and not try to 00160 * interfere. 00161 * 00162 * Secondly, when a Releaser object is passed as the second argument 00163 * to the connect() method of a SafeEmitterArg object, the Releaser 00164 * object must remain in existence until the connect() method returns 00165 * or the emitter may be left in an inconsistent state. 00166 * 00167 * @anchor AssignmentAnchor 00168 * @b Assignment 00169 * 00170 * EmitterArg and SafeEmitterArg objects cannot be copied. Releaser 00171 * objects can be (we do not want to make a class uncopiable just 00172 * because it has the safety feature of having a Releaser object as a 00173 * member). 00174 * 00175 * So how should assignment of a Releaser object and of a class which 00176 * has a Releaser as a member be handled? An object which has a 00177 * Releaser as a member and which is being assigned to (the assignee) 00178 * could keep all its existing pre-assignment emitter connections - so 00179 * far as the Releaser object is concerned, it will have to do so 00180 * where the connections are not protected by the Releaser object, and 00181 * we could do the same in relation to protected connections, in which 00182 * case we would make operator=() of Releaser do nothing: that is, 00183 * just return - a default assignment would always be wrong as it 00184 * would take the assignor's Releaser state but inherit none of its 00185 * connections, which the assignee cannot inherit as they depend on a 00186 * remote emitter object or objects. 00187 * 00188 * However, the state of the assignee after assignment may not be such 00189 * as to permit the inheriting of all the assignor's state except its 00190 * connections. Accordingly, the default strategy adopted here is for 00191 * the Releaser object to become a blank sheet on assignment. After 00192 * assignment, an assignee which has a Releaser object as a member 00193 * will no longer have any of the emitter connections which were, 00194 * prior to assignment, protected by the Releaser object. If in a 00195 * particular case the user does not want this behaviour, she should 00196 * provide an assignment operator in the class which has Releaser as a 00197 * member and leave Releaser alone in the assignment operator. 00198 * 00199 * @b Usage 00200 * 00201 * For an object my_obj of class type MyClass, with a method void 00202 * MyClass::my_method(int, int, const char*), usage for a fully bound 00203 * functor and emitter would be: 00204 * 00205 * @code 00206 * using namespace Cgu; 00207 * int arg1 = 1, arg2 = 5; 00208 * Emitter e; 00209 * e.connect(Callback::make(my_obj, &MyClass::my_method, arg1, arg2, "Hello\n")); 00210 * e(); 00211 * 00212 * SafeEmitter se; 00213 * se.connect(Callback::make(my_obj, &MyClass::my_method, arg1, arg2, "Hello\n")); 00214 * se(); 00215 * @endcode 00216 * 00217 * Or for a partially bound functor and emitter: 00218 * 00219 * @code 00220 * using namespace Cgu; 00221 * int arg1 = 1, arg2 = 5; 00222 * EmitterArg<int, const char*> e; 00223 * e.connect(Callback::make(my_obj, &MyClass::my_method, arg1)); 00224 * e(arg2, "Hello\n"); 00225 * 00226 * SafeEmitterArg<int, const char*> se; 00227 * se.connect(Callback::make(my_obj, &MyClass::my_method, arg1)); 00228 * se(arg2, "Hello\n"); 00229 * @endcode 00230 * 00231 * EmitterArg classes do not provide for a return value. If a 00232 * result is wanted, users should pass an unbound argument by 00233 * reference or pointer (or pointer to pointer). 00234 * 00235 * CallbackArg (and so FunctorArg and EmitterArg) objects can be 00236 * constructed for up to three bound arguments and an unlimited number 00237 * of unbound arguments, or from std::function objects (in which case 00238 * there is no limit to the number of bound arguments nor their 00239 * ordering with unbound arguments). See Cgu::Callback for further 00240 * details. 00241 * 00242 * @b Exception @b safety 00243 * 00244 * Apart from the emit()/operator()() and connect() methods, nothing 00245 * done to an EmitterArg/SafeEmitterArg object should cause an 00246 * exception to be thrown. This is because other methods only iterate 00247 * through a std::list object using std::for_each(), std::find() or by 00248 * hand, and the only things done by std::for_each() or after a 00249 * std::find() or iteration is to remove a functor from the list 00250 * (copying a functor and comparing functors never throw, nor does 00251 * destroying a functor provided the destructors of any bound argument 00252 * type do not throw). Thus, an EmitterArg/SafeEmitterArg and 00253 * Releaser object should never get into an inconsistent state. 00254 * 00255 * The connect() method could throw a std::bad_alloc exception, either 00256 * on creating new functors or on pushing the functors onto the list. 00257 * However, were it to do so, the method has strong exception safety 00258 * (assuming merely iterating over a list does not throw, as it should 00259 * not). 00260 * 00261 * The emit()/operator()() methods could throw std::bad_alloc, and so 00262 * far as that is concerned emission of all the connected functions 00263 * will either all succeed or all fail. In addition, the connected 00264 * functions referenced by the functors held by the emitter might 00265 * throw when executed. emit()/operator()() do not attempt to catch 00266 * these exceptions as there is nothing they could do with them. This 00267 * means that although a throwing connected function will not leave 00268 * the EmitterArg/SafeEmitterArg object in an inconsistent state, any 00269 * other connected functions due to execute subsequently on that same 00270 * emission will not execute. If that is important in any particular 00271 * case, the user must incorporate logic in the connected functions to 00272 * cater for an exception causing only part execution, or must connect 00273 * only one function to any one signal and "chain" emissions by hand 00274 * so as to do the right thing. 00275 */ 00276 00277 /* 00278 Mutex locking heirarchy: 00279 00280 Some out-of-order locking must take place because of the 00281 relationship between the Releaser and SafeEmitterArg<> classes. The 00282 mutex of Releaser is given the higher priority. This means that a 00283 plain EmitterArg<> object will not take any hit from the fact that 00284 Releaser is also useable with SafeEmitterArg<> objects. 00285 00286 One consequence is that to avoid deadlocks, it is the 00287 SafeEmitterArg<> functions which must yield when a deadlock would 00288 otherwise arise. Yielding could occur in 00289 SafeEmitterArg<>::~SafeEmitterArg() and 00290 SafeEmitterArg<>::disconnect(). 00291 */ 00292 00293 #ifdef CGU_USE_SCHED_YIELD 00294 #include <sched.h> 00295 #else 00296 #include <unistd.h> 00297 #endif 00298 00299 #include <list> 00300 #include <unordered_set> 00301 #include <algorithm> 00302 #include <functional> 00303 00304 #include <c++-gtk-utils/callback.h> 00305 #include <c++-gtk-utils/mutex.h> 00306 #include <c++-gtk-utils/cgu_config.h> 00307 00308 namespace Cgu { 00309 00310 /* The four basic emitter types */ 00311 00312 template <class... FreeArgs> class EmitterArg; 00313 template <class... FreeArgs> class SafeEmitterArg; 00314 typedef EmitterArg<> Emitter; 00315 typedef SafeEmitterArg<> SafeEmitter; 00316 00317 /** 00318 * @class Releaser emitter.h c++-gtk-utils/emitter.h 00319 * @brief A class used for tracking EmitterArg and SafeEmitterArg 00320 * connections. 00321 * @sa EmitterArg SafeEmitterArg 00322 * @sa emitter.h 00323 * @sa Callback namespace 00324 * 00325 * This class provides tracking of EmitterArg and SafeEmitterArg 00326 * connections. It should be a public member of any target class 00327 * which wants functors representing any of its methods to be 00328 * disconnected automatically from an EmitterArg or SafeEmitterArg 00329 * object when the target class object is destroyed, and is passed as 00330 * one of the arguments to the connect() method of EmitterArg or 00331 * SafeEmitterArg. 00332 * 00333 * All its methods are thread-safe. 00334 * 00335 * For further background, read this: emitter.h 00336 */ 00337 00338 class Releaser { 00339 00340 // from version 2.0.0-rc3 we use std::unordered_set rather than 00341 // std::list in Releaser. We can't do that for 00342 // EmitterArg/SafeEmitterArg objects, as they need to execute 00343 // connected functors in the order in which they were connected. 00344 std::unordered_set<Callback::SafeFunctor> disconnect_set; 00345 Thread::Mutex mutex; 00346 00347 // only an EmitterArg or SafeEmitterArg object can access add(), remove and try_remove() 00348 void add(const Callback::SafeFunctor&); 00349 void remove(const Callback::SafeFunctor&); 00350 void try_remove(const Callback::SafeFunctor&, int*); 00351 public: 00352 template <class... T> friend class EmitterArg; 00353 template <class... T> friend class SafeEmitterArg; 00354 00355 // operator=() and the copy constructor should copy nothing from the 00356 // assignor, because disconnect_set should be empty in the 00357 // assignee, as any class containing us does not acquire as assignee 00358 // any emitter functors representing any of its methods 00359 00360 /** 00361 * See notes on @ref AssignmentAnchor "assignment" to see how this 00362 * operates. This does not throw provided that the destructors of any 00363 * bound arguments of a functor managed by this Releaser object prior 00364 * to assignment do not throw (as they should not do), and assuming 00365 * that merely iterating through a list does not throw (as it would 00366 * not on any sane implementation). 00367 * @param r The assignee. 00368 */ 00369 Releaser& operator=(const Releaser& r); 00370 00371 /** 00372 * This does not copy anything from the Releaser object passed as an 00373 * argument - see the notes on @ref AssignmentAnchor "assignment" for 00374 * an explanation of why. This does not throw. 00375 * @param r A Releaser object. 00376 * @exception std::bad_alloc This constructor might throw 00377 * std::bad_alloc if memory is exhausted and the system throws in that 00378 * case. 00379 * @exception Thread::MutexError This constructor might throw 00380 * Thread::MutexError if initialisation of the contained mutex fails. 00381 * (It is often not worth checking for this, as it means either memory 00382 * is exhausted or pthread has run out of other resources to create 00383 * new mutexes.) 00384 */ 00385 Releaser(const Releaser& r) {} 00386 00387 /** 00388 * @exception std::bad_alloc The default constructor might throw 00389 * std::bad_alloc if memory is exhausted and the system throws in that 00390 * case. 00391 * @exception Thread::MutexError The default constructor might throw 00392 * Thread::MutexError if initialisation of the contained mutex fails. 00393 * (It is often not worth checking for this, as it means either memory 00394 * is exhausted or pthread has run out of other resources to create 00395 * new mutexes.) 00396 */ 00397 Releaser() = default; 00398 00399 /** 00400 * The destructor does not throw provided that the destructors of any 00401 * bound arguments of a functor managed by this Releaser object do not 00402 * throw (as they should not do), and assuming that merely iterating 00403 * through an unordered_set does not throw (as it would not on any 00404 * sane implementation). 00405 */ 00406 ~Releaser(); 00407 00408 /* Only has effect if --with-glib-memory-slices-compat or 00409 * --with-glib-memory-slices-no-compat option picked */ 00410 CGU_GLIB_MEMORY_SLICES_FUNCS 00411 }; 00412 00413 /* the emitter classes */ 00414 00415 /** 00416 * @class EmitterArg emitter.h c++-gtk-utils/emitter.h 00417 * @brief A class to execute callbacks connected to it, with provision 00418 * for automatic disconnection. 00419 * @sa SafeEmitterArg Releaser 00420 * @sa emitter.h 00421 * @sa Callback namespace 00422 * 00423 * Callback::FunctorArg objects may be connected to Emitter classes, 00424 * and will be executed when EmitterArg::emit() or 00425 * EmitterArg::operator()() are called. 00426 * 00427 * One version of the connect() method takes a Releaser object as an 00428 * argument. Such a Releaser object should be a public member of any 00429 * target class which wants functors representing any of its methods 00430 * to be disconnected automatically from the EmitterArg object when 00431 * the target class object is destroyed. 00432 * 00433 * A connection may be explicitly disconnected by calling the 00434 * disconnect() method, and may also be temporarily blocked and 00435 * subsequently unblocked with the block() and unblock() methods. 00436 * 00437 * The template type is the type of the unbound argument, if any. 00438 * EmitterArg<> is typedef'ed to Emitter. 00439 * 00440 * @b Usage 00441 * 00442 * For a class my_obj of type MyClass, with a method void 00443 * MyClass::my_method(int, int, const char*), usage for a fully bound functor 00444 * and emitter would be: 00445 * 00446 * @code 00447 * using namespace Cgu; 00448 * int arg1 = 1, arg2 = 5; 00449 * Emitter e; 00450 * e.connect(Callback::make(my_obj, &MyClass::my_method, arg1, arg2, "Hello\n")); 00451 * e(); 00452 * @endcode 00453 * 00454 * Or for a partially bound functor and emitter: 00455 * 00456 * @code 00457 * using namespace Cgu; 00458 * int arg1 = 1, arg2 = 5; 00459 * EmitterArg<int, const char*> e; 00460 * e.connect(Callback::make(my_obj, &MyClass::my_method, arg1)); 00461 * e(arg2, "Hello\n"); 00462 * @endcode 00463 * 00464 * For further background, including about thread-safety and exception 00465 * safety and other matters, read this: emitter.h, or for more 00466 * information about bound and unbound arguments, read this: 00467 * Cgu::Callback. 00468 */ 00469 00470 template <class... FreeArgs> 00471 class EmitterArg { 00472 00473 #ifndef DOXYGEN_PARSING 00474 // f1 is the functor we execute when we emit() 00475 // f2 is the functor we execute in our destructor if we are destroyed 00476 // before the remote object is 00477 struct ListItem { 00478 Callback::FunctorArg<FreeArgs...> f1; 00479 Callback::Functor f2; 00480 bool blocked; 00481 ListItem(Callback::FunctorArg<FreeArgs...> f1_, Callback::Functor f2_): 00482 f1(f1_), f2(f2_), blocked(false) {} 00483 }; 00484 #endif 00485 00486 std::list<ListItem> emission_list; 00487 00488 // only Releaser objects can access this 00489 void tracking_disconnect(const Callback::FunctorArg<FreeArgs...>&); 00490 00491 public: 00492 friend class Releaser; 00493 00494 /** 00495 * This will execute the connected functors. 00496 * @param args The unbound arguments to be passed to the referenced 00497 * function or class method, if any. 00498 * @exception std::bad_alloc The method might throw std::bad_alloc if 00499 * memory is exhausted and the system throws in that case. In 00500 * addition, it will throw if the functions or class methods 00501 * referenced by the functors throw (or if the copy constructor of a 00502 * free or bound argument throws and it is not a reference argument). 00503 */ 00504 void operator()(typename Cgu::Param<FreeArgs>::ParamType... args) const {emit(args...);} 00505 00506 /** 00507 * This will execute the connected functors. 00508 * @param args The unbound arguments to be passed to the referenced 00509 * function or class method, if any. 00510 * @exception std::bad_alloc The method might throw std::bad_alloc if 00511 * memory is exhausted and the system throws in that case. In 00512 * addition, it will throw if the functions or class methods 00513 * referenced by the functors throw (or if the copy constructor of a 00514 * free or bound argument throws and it is not a reference argument). 00515 */ 00516 void emit(typename Cgu::Param<FreeArgs>::ParamType... args) const; 00517 00518 /** 00519 * This will execute the connected functors, but it also reports 00520 * whether in fact there were any connected functors to execute. (It 00521 * is not necessary to use this function just because it is not known 00522 * whether a functor is connected - if the standard emit() function is 00523 * called when no functor is connected, nothing will happen. The 00524 * feature of this method is that it will report the outcome.) 00525 * @param args The unbound arguments to be passed to the connected 00526 * functions or class methods, if any. 00527 * @return Returns false if there were no functors to execute, or true 00528 * if functors have been executed. 00529 * @exception std::bad_alloc The method might throw std::bad_alloc if 00530 * memory is exhausted and the system throws in that case. In 00531 * addition, it will throw if the functions or class methods 00532 * referenced by the functors throw (or if the copy constructor of a 00533 * free or bound argument throws and it is not a reference argument). 00534 */ 00535 bool test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const; 00536 00537 /** 00538 * Connects a functor. 00539 * @param f The functor to connect. 00540 * @return The functor connected. 00541 * @exception std::bad_alloc The method might throw std::bad_alloc if 00542 * memory is exhausted and the system throws in that case. 00543 */ 00544 Callback::FunctorArg<FreeArgs...> connect(const Callback::FunctorArg<FreeArgs...>& f); 00545 00546 /** 00547 * Connects a functor. 00548 * @param f The functor to connect. 00549 * @param r A Releaser object for automatic disconnection of the 00550 * functor if the object whose method it represents is destroyed. 00551 * @return The functor connected. 00552 * @exception std::bad_alloc The method might throw std::bad_alloc if 00553 * memory is exhausted and the system throws in that case. 00554 */ 00555 Callback::FunctorArg<FreeArgs...> connect(const Callback::FunctorArg<FreeArgs...>& f, Releaser& r); 00556 00557 /** 00558 * Disconnects a functor previously connected. This does not throw 00559 * provided that the destructors of any bound arguments do not throw 00560 * (as they should not do), and assuming that merely iterating through 00561 * a list does not throw (as it would not on any sane implementation). 00562 * @param f The functor to disconnect. 00563 * @note If the same functor has been connected more than once to the 00564 * same EmitterArg object, this call will disconnect all of them. 00565 */ 00566 void disconnect(const Callback::FunctorArg<FreeArgs...>& f); 00567 00568 /** 00569 * Blocks a connected functor from executing when emit() or 00570 * operator()() is called until unblock() is called. This method does 00571 * not throw (assuming that merely iterating through a list does not 00572 * throw, as it would not on any sane implementation). 00573 * @param f The functor to block. 00574 * @note If the same functor has been connected more than once to the 00575 * same EmitterArg object, this call will block all of them. 00576 */ 00577 void block(const Callback::FunctorArg<FreeArgs...>& f); 00578 00579 /** 00580 * Unblocks a previously blocked functor. This method does not throw 00581 * (assuming that merely iterating through a list does not throw, as 00582 * it would not on any sane implementation). 00583 * @param f The functor to unblock. 00584 * @note If the same functor has been connected more than once to the 00585 * same EmitterArg object, this call will unblock all of them. 00586 */ 00587 void unblock(const Callback::FunctorArg<FreeArgs...>& f); 00588 00589 /** 00590 * @exception std::bad_alloc The constructor might throw 00591 * std::bad_alloc if memory is exhausted and the system throws in that 00592 * case. 00593 */ 00594 EmitterArg() = default; 00595 00596 /** 00597 * This class cannot be copied. The copy constructor is deleted. 00598 */ 00599 EmitterArg(const EmitterArg&) = delete; 00600 00601 /** 00602 * This class cannot be copied. The assignment operator is deleted. 00603 */ 00604 EmitterArg& operator=(const EmitterArg&) = delete; 00605 00606 /** 00607 * The destructor does not throw provided that the destructors of any 00608 * bound arguments do not throw (as they should not do), and assuming 00609 * that merely iterating through a list does not throw (as it would 00610 * not on any sane implementation). 00611 */ 00612 ~EmitterArg(); 00613 00614 /* Only has effect if --with-glib-memory-slices-compat or 00615 * --with-glib-memory-slices-no-compat option picked */ 00616 CGU_GLIB_MEMORY_SLICES_FUNCS 00617 }; 00618 00619 template <class... FreeArgs> 00620 EmitterArg<FreeArgs...>::~EmitterArg() { 00621 00622 // gcc-4.4 and 4.5 don't support this: 00623 /* 00624 for(const ListItem& l: emission_list) {l.f2();} 00625 */ 00626 // gcc-4.4 doesn't support this; 00627 /* 00628 std::for_each(emission_list.begin(), emission_list.end(), 00629 [](const ListItem& l){(l.f2)();}); 00630 */ 00631 // So do it the old way: 00632 struct DisconnectReleaserItem { 00633 static void exec(const ListItem& l) {(l.f2)();} 00634 }; 00635 std::for_each(emission_list.begin(), emission_list.end(), 00636 DisconnectReleaserItem::exec); 00637 } 00638 00639 template <class... FreeArgs> 00640 void EmitterArg<FreeArgs...>::emit(typename Cgu::Param<FreeArgs>::ParamType... args) const { 00641 00642 // create a local copy of emission_list, to enable a connected 00643 // function (i) to delete the EmitterArg<> object to which it is 00644 // connected, even if there are other functors still to execute in 00645 // the same emission (which will execute normally provided they do 00646 // not try to call any of the emitter's functions), (ii) to call 00647 // 'delete this' nothwithstanding that the connected function is 00648 // protected by a Releaser object (assuming all the other restraints 00649 // on calling 'delete this' are met), provided that no other access 00650 // would be made to the deleted object in a function call connected 00651 // to the same emitter which is due to execute subsequently in the 00652 // same emission, and (iii) to disconnect itself from the 00653 // EmitterArg object. This design approach has a trade-off: if a 00654 // connected function tries to block, unblock or disconnect another 00655 // function connected to the same EmitterArg<> object which is due 00656 // to execute subsequently in the same emission (or to block, 00657 // unblock or disconnect itself when it is due to execute again 00658 // subsequently in the same emission), the attempted block, unblock 00659 // or disconnection will not have any effect on that emission (it 00660 // will only have effect on a subsequent emission). In addition, a 00661 // connected function may not destroy an object whose non-static 00662 // method is connected to the same emitter and which would execute 00663 // subsequently in the same emission, even if that object is 00664 // protected by a Releaser object (the non-static method will 00665 // unsuccessfully attempt to execute notwithstanding the destruction 00666 // of the object it would be operating on). 00667 00668 // we can't use uniform initialisation here as it would be 00669 // construed as invoking an initialiser list with a list item, 00670 // rather than passing an already formed list 00671 std::list<ListItem> local_list = emission_list; 00672 00673 /* 00674 gcc-4.4 doesn't support lambdas, gcc-4.5 doesn't like lambda 00675 captures which comprise variadic arguments, and neither support 00676 range-based for, so iterate by hand 00677 */ 00678 typename std::list<ListItem>::const_iterator iter; 00679 for (iter = local_list.begin(); iter != local_list.end(); ++iter) { 00680 if (!iter->blocked) iter->f1(args...); 00681 } 00682 } 00683 00684 template <class... FreeArgs> 00685 bool EmitterArg<FreeArgs...>::test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const { 00686 if (emission_list.empty()) return false; 00687 emit(args...); 00688 return true; 00689 } 00690 00691 template <class... FreeArgs> 00692 Callback::FunctorArg<FreeArgs...> EmitterArg<FreeArgs...>::connect(const Callback::FunctorArg<FreeArgs...>& f1) { 00693 emission_list.push_back(ListItem{f1, Callback::Functor()}); 00694 return f1; 00695 } 00696 00697 template <class... FreeArgs> 00698 Callback::FunctorArg<FreeArgs...> EmitterArg<FreeArgs...>::connect(const Callback::FunctorArg<FreeArgs...>& f1, Releaser& r) { 00699 // In this method: 00700 // f1 is the functor we execute when we emit() 00701 // f2 is the functor we execute in our destructor if we are destroyed before the 00702 // remote object is 00703 // f3 is the functor the remote object executes in its Releaser if it is destroyed 00704 // before we are, or if Releaser::operator=() is called 00705 00706 Callback::SafeFunctor f3{Callback::make_ref(*this, &EmitterArg<FreeArgs...>::tracking_disconnect, f1)}; 00707 Callback::Functor f2{Callback::make_ref(r, &Releaser::remove, f3)}; 00708 r.add(f3); 00709 try { 00710 emission_list.push_back(ListItem{f1, f2}); 00711 } 00712 catch (...) { 00713 r.remove(f3); 00714 throw; 00715 } 00716 return f1; 00717 } 00718 00719 template <class... FreeArgs> 00720 void EmitterArg<FreeArgs...>::disconnect(const Callback::FunctorArg<FreeArgs...>& arg) { 00721 // in theory, we could have connected the same functor object 00722 // more than once, so cater for that 00723 auto iter = emission_list.begin(); 00724 for (;;) { 00725 // gcc-4.4 doesn't support lambdas: 00726 /* 00727 iter = std::find_if(iter, emission_list.end(), 00728 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 00729 */ 00730 // so use a local struct and std::bind: 00731 struct Pred { 00732 static bool pred(const ListItem& p, const Callback::FunctorArg<FreeArgs...>& f) { 00733 return (p.f1 == f); 00734 } 00735 }; 00736 iter = std::find_if(iter, emission_list.end(), 00737 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 00738 if (iter != emission_list.end()) { 00739 // remove ourselves from the remote Releaser object 00740 (iter->f2)(); 00741 00742 // remove this item from emission_list 00743 iter = emission_list.erase(iter); 00744 } 00745 else break; 00746 } 00747 } 00748 00749 // tracking disconnect() is the same as disconnect(), except that we do not 00750 // execute f2 as the remote Releaser object will destroy its own functors 00751 // in that case 00752 template <class... FreeArgs> 00753 void EmitterArg<FreeArgs...>::tracking_disconnect(const Callback::FunctorArg<FreeArgs...>& arg) { 00754 auto iter = emission_list.begin(); 00755 for (;;) { 00756 // gcc-4.4 doesn't support lambdas: 00757 /* 00758 iter = std::find_if(iter, emission_list.end(), 00759 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 00760 */ 00761 // so use a local struct and std::bind: 00762 struct Pred { 00763 static bool pred(const ListItem& p, const Callback::FunctorArg<FreeArgs...>& f) { 00764 return (p.f1 == f); 00765 } 00766 }; 00767 iter = std::find_if(iter, emission_list.end(), 00768 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 00769 if (iter != emission_list.end()) { 00770 // remove this item from emission_list 00771 iter = emission_list.erase(iter); 00772 } 00773 else break; 00774 } 00775 } 00776 00777 template <class... FreeArgs> 00778 void EmitterArg<FreeArgs...>::block(const Callback::FunctorArg<FreeArgs...>& arg) { 00779 // in theory, we could have connected the same functor object 00780 // more than once, so cater for that 00781 auto iter = emission_list.begin(); 00782 for (;;) { 00783 // gcc-4.4 doesn't support lambdas: 00784 /* 00785 iter = std::find_if(iter, emission_list.end(), 00786 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 00787 */ 00788 // so use a local struct and std::bind: 00789 struct Pred { 00790 static bool pred(const ListItem& p, const Callback::FunctorArg<FreeArgs...>& f) { 00791 return (p.f1 == f); 00792 } 00793 }; 00794 iter = std::find_if(iter, emission_list.end(), 00795 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 00796 if (iter != emission_list.end()) { 00797 iter->blocked = true; 00798 ++iter; 00799 } 00800 else break; 00801 } 00802 } 00803 00804 template <class... FreeArgs> 00805 void EmitterArg<FreeArgs...>::unblock(const Callback::FunctorArg<FreeArgs...>& arg) { 00806 // in theory, we could have connected the same functor object 00807 // more than once, so cater for that 00808 auto iter = emission_list.begin(); 00809 for (;;) { 00810 // gcc-4.4 doesn't support lambdas: 00811 /* 00812 iter = std::find_if(iter, emission_list.end(), 00813 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 00814 */ 00815 // so use a local struct and std::bind: 00816 struct Pred { 00817 static bool pred(const ListItem& p, const Callback::FunctorArg<FreeArgs...>& f) { 00818 return (p.f1 == f); 00819 } 00820 }; 00821 iter = std::find_if(iter, emission_list.end(), 00822 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 00823 if (iter != emission_list.end()) { 00824 iter->blocked = false; 00825 ++iter; 00826 } 00827 else break; 00828 } 00829 } 00830 00831 /** 00832 * @class SafeEmitterArg emitter.h c++-gtk-utils/emitter.h 00833 * @brief A thread-safe class to execute callbacks connected to it, 00834 * with provision for automatic disconnection. 00835 * @sa EmitterArg Releaser 00836 * @sa emitter.h 00837 * @sa Callback namespace 00838 * 00839 * This is a thread-safe version of the EmitterArg class. 00840 * Callback::SafeFunctorArg objects may be connected to SafeEmitter 00841 * classes, and will be executed when SafeEmitterArg::emit() or 00842 * SafeEmitterArg::operator()() are called. 00843 * 00844 * One version of the connect() method takes a Releaser object as an 00845 * argument. Such a Releaser object should be a public member of any 00846 * target class which wants functors representing any of its methods 00847 * to be disconnected automatically from the SafeEmitterArg object 00848 * when the target class object is destroyed. 00849 * 00850 * A connection may be explicitly disconnected by calling the 00851 * disconnect() method, and may also be temporarily blocked and 00852 * subsequently unblocked with the block() and unblock() methods. 00853 * 00854 * The template type is the type of the unbound argument, if any. 00855 * SafeEmitterArg<> is typedef'ed to SafeEmitter. 00856 * 00857 * @b Usage 00858 * 00859 * For a class my_obj of type MyClass, with a method void 00860 * MyClass::my_method(int, int, const char*), usage for a fully bound 00861 * functor and emitter would be: 00862 * 00863 * @code 00864 * using namespace Cgu; 00865 * int arg1 = 1, arg2 = 5; 00866 * SafeEmitter se; 00867 * se.connect(Callback::make(my_obj, &MyClass::my_method, arg1, arg2, "Hello\n")); 00868 * se(); 00869 * @endcode 00870 * 00871 * Or for a partially bound functor and emitter: 00872 * 00873 * @code 00874 * using namespace Cgu; 00875 * int arg1 = 1, arg2 = 5; 00876 * SafeEmitterArg<int, const char*> se; 00877 * se.connect(Callback::make(my_obj, &MyClass::my_method, arg1)); 00878 * se(arg2, "Hello\n"); 00879 * @endcode 00880 * 00881 * For further background, including about thread-safety and exception 00882 * safety and other matters, read this: emitter.h, or for more 00883 * information about bound and unbound arguments, read this: 00884 * Cgu::Callback. 00885 */ 00886 00887 template <class... FreeArgs> 00888 class SafeEmitterArg { 00889 00890 #ifndef DOXYGEN_PARSING 00891 // f1 is the functor we execute when we emit() 00892 // f2 is the functor we execute in our destructor if we are destroyed 00893 // before the remote object is 00894 struct ListItem { 00895 Callback::SafeFunctorArg<FreeArgs...> f1; 00896 Callback::SafeFunctorArg<int*> f2; 00897 bool blocked; 00898 ListItem(Callback::SafeFunctorArg<FreeArgs...> f1_, Callback::SafeFunctorArg<int*> f2_): 00899 f1(f1_), f2(f2_), blocked(false) {} 00900 }; 00901 #endif 00902 00903 std::list<ListItem> emission_list; 00904 mutable Thread::Mutex mutex; // make this mutable so we can lock/unlock in const methods 00905 00906 // only Releaser objects can access this 00907 void tracking_disconnect(const Callback::SafeFunctorArg<FreeArgs...>&); 00908 00909 public: 00910 friend class Releaser; 00911 00912 /** 00913 * This will execute the connected functors. It is thread safe if the 00914 * functions or class methods referenced by the connected functors are 00915 * thread safe. 00916 * @param args The unbound arguments to be passed to the referenced 00917 * function or class method, if any. 00918 * @exception std::bad_alloc The method might throw std::bad_alloc if 00919 * memory is exhausted and the system throws in that case. In 00920 * addition, it will throw if the functions or class methods 00921 * referenced by the functors throw (or if the copy constructor of a 00922 * free or bound argument throws and it is not a reference argument). 00923 */ 00924 void operator()(typename Cgu::Param<FreeArgs>::ParamType... args) const {emit(args...);} 00925 00926 /** 00927 * This will execute the connected functors. It is thread safe if the 00928 * functions or class methods referenced by the connected functors are 00929 * thread safe. 00930 * @param args The unbound arguments to be passed to the referenced 00931 * function or class method, if any. 00932 * @exception std::bad_alloc The method might throw std::bad_alloc if 00933 * memory is exhausted and the system throws in that case. In 00934 * addition, it will throw if the functions or class methods 00935 * referenced by the functors throw (or if the copy constructor of a 00936 * free or bound argument throws and it is not a reference argument). 00937 */ 00938 void emit(typename Cgu::Param<FreeArgs>::ParamType... args) const; 00939 00940 /** 00941 * This will execute the connected functors, but it also reports 00942 * whether in fact there were any connected functors to execute. It 00943 * is thread safe if the functions or class methods referenced by the 00944 * connected functors are thread safe. (It is not necessary to use 00945 * this function just because it is not known whether a functor is 00946 * connected - if the standard emit() function is called when no 00947 * functor is connected, nothing will happen. The feature of this 00948 * method is that it will report the outcome.) 00949 * @param args The unbound arguments to be passed to the referenced 00950 * function or class method, if any. 00951 * @return Returns false if there were no functors to execute, or true 00952 * if functors have been executed. 00953 * @exception std::bad_alloc The method might throw std::bad_alloc if 00954 * memory is exhausted and the system throws in that case. In 00955 * addition, it will throw if the functions or class methods 00956 * referenced by the functors throw (or if the copy constructor of a 00957 * free or bound argument throws and it is not a reference argument). 00958 */ 00959 bool test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const; 00960 00961 /** 00962 * Connects a functor. It is thread safe. 00963 * @param f The functor to connect. 00964 * @return The functor connected. 00965 * @exception std::bad_alloc The method might throw std::bad_alloc if 00966 * memory is exhausted and the system throws in that case. 00967 */ 00968 Callback::SafeFunctorArg<FreeArgs...> connect(const Callback::SafeFunctorArg<FreeArgs...>& f); 00969 00970 /** 00971 * Connects a functor. It is thread safe. 00972 * @param f The functor to connect. 00973 * @param r A Releaser object for automatic disconnection of the 00974 * functor if the object whose method it represents is destroyed. 00975 * @return The functor connected. 00976 * @exception std::bad_alloc The method might throw std::bad_alloc if 00977 * memory is exhausted and the system throws in that case. 00978 */ 00979 Callback::SafeFunctorArg<FreeArgs...> connect(const Callback::SafeFunctorArg<FreeArgs...>& f, Releaser& r); 00980 00981 /** 00982 * Disconnects a functor previously connected. This does not throw 00983 * provided that the destructors of any bound arguments do not throw 00984 * (as they should not do), and assuming that merely iterating through 00985 * a list does not throw (as it would not on any sane implementation). 00986 * It is thread safe. 00987 * @param f The functor to disconnect. 00988 * @note If the same functor has been connected more than once to the 00989 * same SafeEmitterArg object, this call will disconnect all of them. 00990 */ 00991 void disconnect(const Callback::SafeFunctorArg<FreeArgs...>& f); 00992 00993 /** 00994 * Blocks a connected functor from executing when emit() or 00995 * operator()() is called until unblock() is called. This method does 00996 * not throw (assuming that merely iterating through a list does not 00997 * throw, as it would not on any sane implementation). It is thread 00998 * safe. 00999 * @param f The functor to block. 01000 * @note If the same functor has been connected more than once to the 01001 * same SafeEmitterArg object, this call will block all of them. 01002 */ 01003 void block(const Callback::SafeFunctorArg<FreeArgs...>& f); 01004 01005 /** 01006 * Unblocks a previously blocked functor. This method does not throw 01007 * (assuming that merely iterating through a list does not throw, as 01008 * it would not on any sane implementation). It is thread safe. 01009 * @param f The functor to unblock. 01010 * @note If the same functor has been connected more than once to the 01011 * same SafeEmitterArg object, this call will unblock all of them. 01012 */ 01013 void unblock(const Callback::SafeFunctorArg<FreeArgs...>& f); 01014 01015 /** 01016 * @exception std::bad_alloc The constructor might throw 01017 * std::bad_alloc if memory is exhausted and the system throws in that 01018 * case. 01019 * @exception Thread::MutexError The constructor might throw 01020 * Thread::MutexError if initialisation of the contained mutex fails. 01021 * (It is often not worth checking for this, as it means either memory 01022 * is exhausted or pthread has run out of other resources to create 01023 * new mutexes.) 01024 */ 01025 SafeEmitterArg() = default; 01026 01027 /** 01028 * This class cannot be copied. The copy constructor is deleted. 01029 */ 01030 SafeEmitterArg(const SafeEmitterArg&) = delete; 01031 01032 /** 01033 * This class cannot be copied. The assignment operator is deleted. 01034 */ 01035 SafeEmitterArg& operator=(const SafeEmitterArg&) = delete; 01036 01037 /** 01038 * The destructor does not throw provided that the destructors of any 01039 * bound arguments do not throw (as they should not do), and assuming 01040 * that merely iterating through a list does not throw (as it would 01041 * not on any sane implementation). It is thread-safe as regards the 01042 * dropping of any connected functors and of any relevant Releaser 01043 * objects. 01044 */ 01045 ~SafeEmitterArg(); 01046 01047 /* Only has effect if --with-glib-memory-slices-compat or 01048 * --with-glib-memory-slices-no-compat option picked */ 01049 CGU_GLIB_MEMORY_SLICES_FUNCS 01050 }; 01051 01052 template <class... FreeArgs> 01053 SafeEmitterArg<FreeArgs...>::~SafeEmitterArg() { 01054 01055 // go through emission_list() item by item, popping off the front and erasing 01056 // as we go in case Releaser::try_remove() fails to acquire the lock on one 01057 // of the iterations 01058 Thread::Mutex::Lock lock{mutex}; 01059 while (!emission_list.empty()) { 01060 auto iter = emission_list.begin(); 01061 int result = 0; // f2 might be a no-op 01062 // remove ourselves from the remote Releaser object 01063 (iter->f2)(&result); 01064 if (!result) { // we got the Releaser mutex lock or no-op 01065 // now remove this item from emission_list 01066 emission_list.erase(iter); 01067 } 01068 else { 01069 mutex.unlock(); 01070 // spin nicely 01071 #ifdef CGU_USE_SCHED_YIELD 01072 sched_yield(); 01073 #else 01074 usleep(10); 01075 #endif 01076 mutex.lock(); 01077 } 01078 } 01079 } 01080 01081 template <class... FreeArgs> 01082 void SafeEmitterArg<FreeArgs...>::emit(typename Cgu::Param<FreeArgs>::ParamType... args) const { 01083 01084 // create a local copy of emission_list, to enable a connected 01085 // function (i) to delete the EmitterArg<> object to which it is 01086 // connected, even if there are other functors still to execute in 01087 // the same emission (which will execute normally provided they do 01088 // not try to call any of the emitter's functions), (ii) to call 01089 // 'delete this' nothwithstanding that the connected function is 01090 // protected by a Releaser object (assuming all the other restraints 01091 // on calling 'delete this' are met), provided that no other access 01092 // would be made to the deleted object in a function call connected 01093 // to the same emitter which is due to execute subsequently in the 01094 // same emission, and (iii) to disconnect itself from the 01095 // EmitterArg<> object. This design approach has a trade-off: if a 01096 // connected function tries to block, unblock or disconnect another 01097 // function connected to the same EmitterArg<> object which is due 01098 // to execute subsequently in the same emission (or to block, 01099 // unblock or disconnect itself when it is due to execute again 01100 // subsequently in the same emission), the attempted block, unblock 01101 // or disconnection will not have any effect on that emission (it 01102 // will only have effect on a subsequent emission). In addition, a 01103 // connected function may not destroy an object whose non-static 01104 // method is connected to the same emitter and which would execute 01105 // subsequently in the same emission, even if that object is 01106 // protected by a Releaser object (the non-static method will 01107 // unsuccessfully attempt to execute notwithstanding the destruction 01108 // of the object it would be operating on). 01109 01110 // SafeFunctorArg usage has the additional point that while an 01111 // emission is in course, another thread should not try to do any of 01112 // those things, or the same outcome will result. Another thread 01113 // should leave alone objects connected to a SafeEmitterArg<> object 01114 // from the time of operator()() or emit() beginning to the time of 01115 // it ending, and not try to interfere. 01116 01117 // a side effect of having a local list is that, as required, we 01118 // will not be holding our mutex when executing the functors it 01119 // contains. It is OK having the functors in two different lists 01120 // which are potentially (when our mutex is released) in two 01121 // different threads, because the functors hold their 01122 // Callback::Callback objects by SharedLockPtr so their reference 01123 // count is protected (they are SafeFunctorArg<> functors). 01124 01125 std::list<ListItem> local_list; 01126 { // scope block for mutex lock 01127 Thread::Mutex::Lock lock{mutex}; 01128 local_list = emission_list; 01129 } 01130 01131 /* 01132 gcc-4.4 doesn't support lambdas, gcc-4.5 doesn't like lambda 01133 captures which comprise variadic arguments, and neither support 01134 range-based for, so iterate by hand 01135 */ 01136 typename std::list<ListItem>::const_iterator iter; 01137 for (iter = local_list.begin(); iter != local_list.end(); ++iter) { 01138 if (!iter->blocked) iter->f1(args...); 01139 } 01140 } 01141 01142 template <class... FreeArgs> 01143 bool SafeEmitterArg<FreeArgs...>::test_emit(typename Cgu::Param<FreeArgs>::ParamType... args) const { 01144 01145 std::list<ListItem> local_list; 01146 { // scope block for mutex lock 01147 Thread::Mutex::Lock lock{mutex}; 01148 if (emission_list.empty()) return false; 01149 local_list = emission_list; 01150 } 01151 01152 /* 01153 gcc-4.4 doesn't support lambdas, gcc-4.5 doesn't like lambda 01154 captures which comprise variadic arguments, and neither support 01155 range-based for, so iterate by hand 01156 */ 01157 typename std::list<ListItem>::const_iterator iter; 01158 for (iter = local_list.begin(); iter != local_list.end(); ++iter) { 01159 if (!iter->blocked) iter->f1(args...); 01160 } 01161 return true; 01162 } 01163 01164 template <class... FreeArgs> 01165 Callback::SafeFunctorArg<FreeArgs...> SafeEmitterArg<FreeArgs...>::connect(const Callback::SafeFunctorArg<FreeArgs...>& f1) { 01166 Thread::Mutex::Lock lock{mutex}; 01167 emission_list.push_back(ListItem{f1, Callback::SafeFunctorArg<int*>()}); 01168 return f1; 01169 } 01170 01171 template <class... FreeArgs> 01172 Callback::SafeFunctorArg<FreeArgs...> SafeEmitterArg<FreeArgs...>::connect(const Callback::SafeFunctorArg<FreeArgs...>& f1, Releaser& r) { 01173 // In this method: 01174 // f1 is the functor we execute when we emit() 01175 // f2 is the functor we execute in our destructor if we are destroyed before the 01176 // remote object is 01177 // f3 is the functor the remote object executes in its Releaser if it is destroyed 01178 // before we are, or if Releaser::operator=() is called 01179 01180 Callback::SafeFunctor f3{Callback::make_ref(*this, &SafeEmitterArg<FreeArgs...>::tracking_disconnect, f1)}; 01181 Callback::SafeFunctorArg<int*> f2{Callback::make_ref(r, &Releaser::try_remove, f3)}; 01182 // we can't call Releaser::add() when holding our mutex or we will 01183 // get out of order locking, as Releaser's mutex is acquired in that 01184 // method, and we don't need to do so 01185 r.add(f3); 01186 Thread::Mutex::Lock lock{mutex}; 01187 try { 01188 emission_list.push_back(ListItem{f1, f2}); 01189 } 01190 catch (...) { 01191 mutex.unlock(); 01192 r.remove(f3); 01193 mutex.lock(); 01194 throw; 01195 } 01196 return f1; 01197 } 01198 01199 template <class... FreeArgs> 01200 void SafeEmitterArg<FreeArgs...>::disconnect(const Callback::SafeFunctorArg<FreeArgs...>& arg) { 01201 // in theory, we could have connected the same functor object more than 01202 // once, so cater for that as well as Releaser::try_remove() failing 01203 Thread::Mutex::Lock lock{mutex}; 01204 auto iter = emission_list.begin(); 01205 for(;;) { 01206 /* 01207 // gcc-4.4 doesn't support lambdas: 01208 iter = std::find_if(iter, emission_list.end(), 01209 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 01210 */ 01211 // so use a local struct and std::bind: 01212 struct Pred { 01213 static bool pred(const ListItem& p, const Callback::SafeFunctorArg<FreeArgs...>& f) { 01214 return (p.f1 == f); 01215 } 01216 }; 01217 iter = std::find_if(iter, emission_list.end(), 01218 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 01219 if (iter != emission_list.end()) { 01220 int result = 0; // f2 might be a no-op 01221 // remove ourselves from the remote Releaser object 01222 (iter->f2)(&result); 01223 if (!result) { // we got the Releaser mutex lock or no-op 01224 // now remove this item from emission_list 01225 iter = emission_list.erase(iter); 01226 } 01227 else { 01228 mutex.unlock(); 01229 // spin nicely 01230 #ifdef CGU_USE_SCHED_YIELD 01231 sched_yield(); 01232 #else 01233 usleep(10); 01234 #endif 01235 mutex.lock(); 01236 // start again at the beginning - we have released the mutex 01237 // so our iterator may have become invalid 01238 iter = emission_list.begin(); 01239 } 01240 } 01241 else break; 01242 } 01243 } 01244 01245 // tracking disconnect() is the same as disconnect(), except that we do not 01246 // execute f2 as the remote Releaser object will destroy its own functors 01247 // in that case 01248 template <class... FreeArgs> 01249 void SafeEmitterArg<FreeArgs...>::tracking_disconnect(const Callback::SafeFunctorArg<FreeArgs...>& arg) { 01250 Thread::Mutex::Lock lock{mutex}; 01251 auto iter = emission_list.begin(); 01252 for (;;) { 01253 // gcc-4.4 doesn't support lambdas: 01254 /* 01255 iter = std::find_if(iter, emission_list.end(), 01256 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 01257 */ 01258 // so use a local struct and std::bind: 01259 struct Pred { 01260 static bool pred(const ListItem& p, const Callback::SafeFunctorArg<FreeArgs...>& f) { 01261 return (p.f1 == f); 01262 } 01263 }; 01264 iter = std::find_if(iter, emission_list.end(), 01265 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 01266 if (iter != emission_list.end()) { 01267 // remove this item from emission_list 01268 iter = emission_list.erase(iter); 01269 } 01270 else break; 01271 } 01272 } 01273 01274 template <class... FreeArgs> 01275 void SafeEmitterArg<FreeArgs...>::block(const Callback::SafeFunctorArg<FreeArgs...>& arg) { 01276 // in theory, we could have connected the same functor object 01277 // more than once, so cater for that 01278 Thread::Mutex::Lock lock{mutex}; 01279 auto iter = emission_list.begin(); 01280 for (;;) { 01281 // gcc-4.4 doesn't support lambdas: 01282 /* 01283 iter = std::find_if(iter, emission_list.end(), 01284 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 01285 */ 01286 // so use a local struct and std::bind: 01287 struct Pred { 01288 static bool pred(const ListItem& p, const Callback::SafeFunctorArg<FreeArgs...>& f) { 01289 return (p.f1 == f); 01290 } 01291 }; 01292 iter = std::find_if(iter, emission_list.end(), 01293 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 01294 if (iter != emission_list.end()) { 01295 iter->blocked = true; 01296 ++iter; 01297 } 01298 else break; 01299 } 01300 } 01301 01302 template <class... FreeArgs> 01303 void SafeEmitterArg<FreeArgs...>::unblock(const Callback::SafeFunctorArg<FreeArgs...>& arg) { 01304 // in theory, we could have connected the same functor object 01305 // more than once, so cater for that 01306 Thread::Mutex::Lock lock{mutex}; 01307 auto iter = emission_list.begin(); 01308 for (;;) { 01309 // gcc-4.4 doesn't support lambdas: 01310 /* 01311 iter = std::find_if(iter, emission_list.end(), 01312 [&arg](const ListItem& p) -> bool {return p.f1 == arg;}); 01313 */ 01314 // so use a local struct and std::bind: 01315 struct Pred { 01316 static bool pred(const ListItem& p, const Callback::SafeFunctorArg<FreeArgs...>& f) { 01317 return (p.f1 == f); 01318 } 01319 }; 01320 iter = std::find_if(iter, emission_list.end(), 01321 std::bind(Pred::pred, std::placeholders::_1, std::ref(arg))); 01322 if (iter != emission_list.end()) { 01323 iter->blocked = false; 01324 ++iter; 01325 } 01326 else break; 01327 } 01328 } 01329 01330 } // namespace Cgu 01331 01332 #endif // EMITTER_H