sigx/0000755000175000017500000000000011157535232012726 5ustar triendl.kjtriendl.kjsigx/TODO0000644000175000017500000000170211012004737013405 0ustar triendl.kjtriendl.kj* think thoroughly about sigx++'s exception handling * sigx doesn't work with lambdas yet (lambdas define lambda_type instead of adaptor_type) * don't propagate exceptions across module boundaries! This means that throwing sigx::bad_caller or sigx::bad_dispatcher from within the sigx dll or shared module is a bad idea. possible solution: throw pointer to shared library's exception object, catch this pointer in a inline wrapper method defined in the header. e.g.: tunnel_functor::operator() which calls tunnel_context::tunnel() which in turn might throw a sigx::bad_dispatcher exception should catch the pointer, copy the exception object pointed to to a local object, free the object pointed to and rethrow the local copy * offer handling for system signals (e.g. SIG_HUP) such that they are propagated into the thread's mainloop (I imagine to attach Glib::Source to the Glib::MainContext) * Documentation!: reference, tutorial, manual sigx/sigx/0000755000175000017500000000000011155006445013675 5ustar triendl.kjtriendl.kjsigx/sigx/types.h0000644000175000017500000000235611123532202015206 0ustar triendl.kjtriendl.kj#ifndef _SIGX_TYPES_HPP_ #define _SIGX_TYPES_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ namespace sigx { /** @short specifies the synchronization mode of the tunnel, i.e. * whether the message should be sent asynchronous or synchronous * @note asynchronous tunnels are the default * @code * open_tunnel(&callback)(); * // is the same as: * open_tunnel(&callback)(); * @endcode * @note other types are thinkable like a SYNC_TIMED */ enum sync_type { ASYNC, SYNC }; } #endif // end file guard sigx/sigx/auto_tunneler.h0000644000175000017500000000354711123532204016733 0ustar triendl.kjtriendl.kj#ifndef _SIGX_AUTO_TUNNELER_HPP_ #define _SIGX_AUTO_TUNNELER_HPP_ /* * Copyright 2005 Tim Mayberry * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include namespace sigx { namespace internal { /** @short Automatic creation of a tunnel functor if @e T_functor * is not yet tunneled. * * This general version is used for non-tunneled functors. */ template::value> struct auto_tunneler { static const bool is_tunneled = false; typedef tunnel_functor functor_type; static functor_type auto_open_tunnel(const T_functor& _A_func) { return open_tunnel(_A_func); } }; /** @short This specialization is used for tunneled functors. * * Just returns the functor passed to auto_open_tunnel. */ template struct auto_tunneler { static const bool is_tunneled = true; typedef T_functor functor_type; static const functor_type& auto_open_tunnel(const T_functor& _A_func) { return _A_func; } }; } // namespace internal } // namespace sigx #endif // end file guard sigx/sigx/signal_f_base.h0000644000175000017500000000343011123532203016611 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_F_BASE_HPP_ #define _SIGX_SIGNAL_F_BASE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // std::tr1::shared_ptr #include #include #include #include #include #include namespace sigx { /** @short Base class for signal functors, see signal_f. * @note non-copyable, not constructible on the heap (with new) and can't be * pointer aliased (with operator &) to ensure that it is de-facto bound to * a wrapping object. * * @ingroup signals * @author klaus triendl */ class SIGX_API signal_f_base: nonassignable, nonheapallocatable, nonpointeraliasing { protected: signal_f_base(const shared_dispatchable& _A_disp, signal_source_ptr _A_psigsource); // implicit dtor is fine; non-virtual by design protected: shared_dispatchable m_disp; /** @short Shared signal source */ std::tr1::shared_ptr m_sigsource; }; } // namespace sigx #endif // end file guard sigx/sigx/signal_f.h0000644000175000017500000002037611123532203015627 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_F_HPP_ #define _SIGX_SIGNAL_F_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include namespace sigx { /** @short Functor returning a sigx::signal_wrapper as a threadsafe signal wrapper * * A signal functor is used to expose a thread's signals and replaces a traditional access function. * It acts as a middle tier between two threads, creating a * sigx::signal_wrapper to a signal existing in the server thread's context, * handing it over to the calling thread. * * A signal functor can be created from different signal sources: * - a signal living in a thread private * - a signal from an object's member (also late bound object instances) * - a signal returned by an object's member function (also late bound object * instances) * - a signal returned by a functor * * Here are some examples for signal sources: * From a thread private: * Class MyThread has a signal "did something" in a thread private data. * The class exposes this signal through a threadsafe signal wrapper. * @code * class MyThread: public sigx::glib_threadable { protected: typedef sigc::signal signal_did_something_type; public: MyThread(); // expose signal "did_something" sigx::signal_f signal_did_something; private: struct ThreadData { signal_did_something_type m_sigDidSomething; }; Glib::Private m_threadpriv; }; MyThread::MyThread(): sigx::glib_threadable(), // params: dispatchable, thread private key, signal pointer signal_did_something(this, m_threadpriv, &ThreadData::m_sigDidSomething) {} * @endcode * * From an object's member function, object instance is late bound: * There is a window object that exposes a button's "clicked" signal * through a threadsafe signal wrapper. * @code class TheGUI: public Gtk::Window, public sigx::glib_auto_dispatchable { public: TheGUI(); public: // expose Gtk::Button::signal_clicked sigx::signal_f > signal_button_clicked; private: Gtk::Button* m_btn; }; TheGUI::TheGUI(): Gtk::Window(), sigx::glib_auto_dispatchable(), // set up signal functor with late object instance binding signal_button_clicked(this, sigc::ref(m_btn), &Gtk::Button::signal_clicked), m_btn() { // now object instance m_btn is pointing to is created, // signal_button_clicked now has a valid object instance m_btn = manage(new Gtk::Button("notify thread")); add(*m_btn); show_all_children(); } * @endcode * * @ingroup signals */ template class signal_f: protected signal_f_base { public: typedef T_signal signal_type; typedef signal_f self_type; /** @short Constructs a signal functor from a thread private object's * member signal of type @e T_signal. * @param _A_disp The dispatchable to operate on. * @param _A_priv Key to the thread private data * @param _A_sig pointer to the thread private object's member signal */ template signal_f(const shared_dispatchable& _A_disp, Glib::Private& _A_priv, signal_type T_threadpriv::*_A_sig): signal_f_base(_A_disp, new signal_source_threadprivate(_A_priv, _A_sig)) {} /** @short Constructs a signal functor from a dispatchable's member signal * of type @e T_signal. * @param _A_obj The dispatchable to operate on and the object instance * for @e _A_sig * @param _A_sig Pointer to the @e _A_obj's member signal */ template signal_f(T_dispatchable& _A_obj, signal_type T_dispatchable::*_A_sig): signal_f_base(_A_obj, new signal_source_obj_mem(&_A_obj, _A_sig)) {} /** @short Constructs a signal functor from an object's member signal * of type @e T_signal. * @param _A_disp The dispatchable to operate on. * @param _A_obj The object instance for @e _A_sig * @param _A_sig Pointer to the @e _A_obj's member signal */ template signal_f(const shared_dispatchable& _A_disp, T_obj& _A_obj, signal_type T_obj::*_A_sig): signal_f_base(_A_disp, new signal_source_obj_mem(&_A_obj, _A_sig)) {} /** @short Constructs a signal functor from an object's member signal * of type @e T_signal. * Object instance is late bound. * @param _A_disp The dispatchable to operate on. * @param _A_obj Pointer reference to the object for @e _A_sig * @param _A_sig Pointer to the @e _A_obj's member signal */ template signal_f(const shared_dispatchable& _A_disp, sigc::const_reference_wrapper _A_obj, signal_type T_obj::*_A_sig): signal_f_base(_A_disp, new signal_source_obj_mem(sigc::unwrap(_A_obj), _A_sig)) {} template signal_f(const shared_dispatchable& _A_disp, sigc::reference_wrapper _A_obj, signal_type T_obj::*_A_sig): signal_f_base(_A_disp, new signal_source_obj_mem(sigc::unwrap(_A_obj), _A_sig)) {} /** @short Constructs a signal functor from a member functor returning a signal * of type @e T_signal and a member functor's bound object. * Object instance is late bound. * @param _A_disp The dispatchable to operate on. * @param _A_obj pointer reference to the object for @e _A_sig_func * @param _A_sig_func Functor returning a signal of type @e T_signal; * must take a @e T_obj* as argument, e.g. create the functor with * sigc::mem_fun(&MyObj::signal_did_something) */ template signal_f(const shared_dispatchable& _A_disp, sigc::const_reference_wrapper _A_obj, const T_functor& _A_sig_func): signal_f_base(_A_disp, new signal_source_pobj_mem_fun(sigc::unwrap(_A_obj), _A_sig_func)) {} template signal_f(const shared_dispatchable& _A_disp, sigc::reference_wrapper _A_obj, const T_functor& _A_sig_func): signal_f_base(_A_disp, new signal_source_pobj_mem_fun(sigc::unwrap(_A_obj), _A_sig_func)) {} /** @short Constructs a signal functor from any functor returning a signal * of type @e T_signal. * @param _A_disp The dispatchable to operate on. * @param _A_sig_func Functor returning a signal of type @e T_signal */ template signal_f(const shared_dispatchable& _A_disp, const T_functor& _A_sig_func): signal_f_base(_A_disp, new signal_source_func(_A_sig_func)) {} /** @short Constructs a signal functor from a dispatchable functor (i.e. a * functor on a dispatchable's method) returning a signal of type * @e T_signal. * @param _A_sig_func Dispatchable functor returning a signal of type * @e T_signal */ template explicit signal_f(const T_functor& _A_sig_func): signal_f_base(internal::dispatchable_constraint::find_dispatchable(_A_sig_func), new signal_source_func(_A_sig_func)) {} /** @return A threadsafe representation of a signal of type @e T_signal. * @note Executed by any client thread. */ signal_wrapper operator ()() const { return signal_wrapper(m_disp, m_sigsource); } }; } // namespace sigx #endif // end file guard sigx/sigx/choose_lock.h0000644000175000017500000000360511123644503016340 0ustar triendl.kjtriendl.kj#ifndef _SIGX_CHOOSE_LOCK_TRAIT_H_ #define _SIGX_CHOOSE_LOCK_TRAIT_H_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** @file * lock traits are used to choose the best lock type for a given mutex. * E.g. For a mutex type boost::mutex lock type boost::mutex::scoped_lock * is chosen */ #include namespace sigx { /** @addtogroup threadsafety * @{ */ /*enum locking_policy { readlock, writelock };*/ /** @short Metafunction that chooses an appropriate scoped lock for a mutex. * * The lock type should be a scoped lock because lock_acquirer is a scope-bound * type. * * @note There is no default lock type choosing mechanism because there is no * such thing as a default or commonly used mutex. * This means that the using programmer has to specialize this metafunction * for her mutexes and the locking policy */ template struct choose_lock; #if 0 /** @short r/w lock trait for a CRecMutex */ template struct choose_lock { typedef boost::mutex::scoped_lock type; }; #endif } // namespace sigx #endif // end file guard sigx/sigx/dispatchable.h0000644000175000017500000000745611123532203016474 0ustar triendl.kjtriendl.kj#ifndef _SIGX_DISPATCHABLE_HPP_ #define _SIGX_DISPATCHABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // std::pair #include // need the trackable_callback_list #include #include #include #include namespace sigx { namespace internal { typedef rw_lockable rwlockable_dispatcher_ptr; } // namespace internal /** @short Derived classes designate their ability to dispatch messages * over a sigx::dispatcher. * * This class holds just a thread safe pointer to a dispatcher. * * @ingroup Dispatching */ class SIGX_API dispatchable: noncopyable { // must access members friend class shared_dispatchable; protected: /** * @throw Might throw a std::bad_alloc exception */ dispatchable(); // non-virtual by design ~dispatchable() throw(); private: /** @short Private copy constructor, only accessible by shared_dispatchable. */ dispatchable(const dispatchable& other) throw(); /** @short Private assignment operator, only accessible by shared_dispatchable. */ dispatchable& operator =(const dispatchable& other) throw(); /** @short Release shared stuff. */ void release() throw(); protected: /** @short Invalidate those tunnels (and disconnect them from signals) that have * registered themselves with add_dispatcher_change_notify_callback() * when the validity tracking was activated. */ void invalidate_tunnels(); /** @short non-volatile access to the dispatcher pointer in the current thread */ dispatcher_ptr dispatcher() const throw() { return m_disp_ptr->access_nonvolatile(); } public: typedef void (*func_dispatcher_change_notify)(void* /*handle to internal::validity_trackable*/); /** Add a callback that is executed (notified) when the dispatcher is changed. * @param data Passed into func upon notification. * @param func Callback executed upon destruction of the object. * @attention You must not call dispatchable::remove_dispatcher_change_notify_callback() from * within your callback! */ void add_dispatcher_change_notify_callback(void* data, func_dispatcher_change_notify func) const; /** Remove a callback previously installed with add_dispatcher_change_notify_callback(). * The callback is not executed. * @param data Parameter passed into previous call to add_dispatcher_change_notify_callback(). */ void remove_dispatcher_change_notify_callback(void* data) const; private: /// shared counter for m_disp_ptr and m_dispatcher_change_callback_list volatile int* m_shared_count; /** @short A list of callbacks fired on dispatcher changes. * The callbacks are held in a list of type callback_list_type. * This list is allocated dynamically when the first callback is added. */ typedef std::list > callback_list_type; typedef callback_list_type* callback_list_ptr_type; callback_list_ptr_type* m_dispatcher_change_callback_list; protected: internal::rwlockable_dispatcher_ptr* m_disp_ptr; }; } // namespace sigx #endif // end file guard sigx/sigx/threadable.h0000644000175000017500000000450411123532203016133 0ustar triendl.kjtriendl.kj#ifndef _SIGX_THREADABLE_HPP_ #define _SIGX_THREADABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** @defgroup Threading Threading * @short A group of types helping to facilitate threads with glibmm and * interthread-communication */ #include #include namespace sigx { /** @short Derived classes denote that they are a thread wrapper. * * Additionally, since a threadable is a dispatchable, derived classes denote * their ability to participate automatically in threadsafe messaging. * * @ingroup Threading */ class SIGX_API threadable: public manual_dispatchable { protected: /** @short Initialize thread specific stuff just before entering * the thread's mainloop. * * This method gives derived classes the possibility to initialize * their things like thread private data or connecting to the * idle signal (via mainloop()->signal_idle() in case of a glib_threadable) * just before entering the mainloop. * * @note The sigx::dispatchable baseclass already has a valid dispatcher * and the thread's maincontext and mainloop are already valid, too. */ virtual void on_startup() {} /** @short cleanup other stuff just after quitting the mainloop. * * This method gives derived classes the possibility to clean up * their things like thread private data right after quitting the mainloop. * * @note The sigx::dispatchable baseclass still has a valid dispatcher * reference and the thread's maincontext and mainloop are still valid, too. */ virtual void on_cleanup() {} }; } // namespace sigx #endif // end file guard sigx/sigx/noninstantiatable.h0000644000175000017500000000224611123532203017556 0ustar triendl.kjtriendl.kj#ifndef _SIGX_NONINSTANTIATABLE_HPP_ #define _SIGX_NONINSTANTIATABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { /** @short A Private constructor ensures derived classes cannot be created. * @note Intended use as baseclass only. * @author klaus triendl */ class SIGX_API noninstantiatable { private: noninstantiatable() {} }; } // namespace sigx #endif // #ifndef _SIGX_NONINSTANTIATABLE_HPP_ sigx/sigx/dispatcher.h0000644000175000017500000001565511145375015016211 0ustar triendl.kjtriendl.kj#ifndef _SIGX_DISPATCHER_HPP #define _SIGX_DISPATCHER_HPP /* * Copyright 2005 Tim Mayberry and Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** @defgroup Dispatching Dispatching * @short A group of types involved in dispatching messages between threads. */ #include #include #include // gint #include #include #include #include #include #include namespace sigx { typedef const void* threadhandle_type; namespace dld { /** @short A pair of threads where pair::first is the smaller one and pair::second * the greater one. */ typedef std::pair thread_pair_type; /** @short Creates a pair of thread handles where the first pair::first is the * smaller one of both and pair::second is the greater one, compared with * operator <. */ thread_pair_type make_thread_pair(threadhandle_type threadA, threadhandle_type threadB); /** @short Holds a counter of synchronous messages between two threads. */ class syncmessages_counter { public: /** @short Construct a syncmessages_counter object. * @param threadA handle to thread A as a reference point to find out * which thread is calling syncmessages_counter's methods. */ syncmessages_counter(const threadhandle_type& threadA); public: /** @short Increase the count of synchronous messages to the server thread. * @note Always called by the client thread. */ syncmessages_counter& operator ++(); /** @short Decrease the count of synchronous messages to the server thread. * @note Always called by the server thread. */ syncmessages_counter& operator --(); /** @short Test whether the client thread has some synchronous messages * from the server thread pending. * @note Always called by the client thread. */ operator bool() const; private: const threadhandle_type m_threadA; int m_countThreadA; int m_countThreadB; }; struct thread_compare: public std::binary_function { bool operator ()(const thread_pair_type& threadpair1, const thread_pair_type& threadpair2) const { if (threadpair1.first < threadpair2.first) return true; if (threadpair1.first > threadpair2.first) return false; if (threadpair1.second < threadpair2.second) return true; //if (threadpair1.second > threadpair2.second) // return false; return false; } }; typedef std::map sync_messages_type; typedef static_mutex_lockable lockable_sync_messages_type; } // namespace dld // fwd decl class tunnel_context_base; /** @short base class denoting the ability to dispatch messages between threads. * * A dispatcher holds a list of pointers to sigx::tunnel_context objects. * * @note abstract, use one of the %dispatcher implementations. * @ingroup Dispatching * * @date 2006-08-12, kj moved m_exiting into StandardDispatcher because it * is only needed there - a glib_dispatcher must be * created and destroyed by the same thread * @date 2006-08-27, kj derive from operator_new to ensure heap allocation * in the glibmmx module * @date 2006-09-02, kj added deadlock detection: throw an exception if a * thread sends a synchronous message to itself or to * a thread that in turn has a synchronous message * pending to the sending thread */ class SIGX_API dispatcher: public operator_new { public: /** @short Whether deadlock detection is turned on. * * Set to `true" from the main thread (e.g. after Glib::thread_init()) to * turn on the deadlock detection feature at runtime for synchronous * messages. * Defaults to false. * * @note Set this flag only once and avoid setting it at any other place * than at program start up. * @note Deadlock detection comes with the price of performance there * happens additional synchronization between threads. Use it mainly in * the debug mode of your program. */ static bool deadlock_detection; /** @short constructs the dispatcher */ dispatcher(); /** * @throw bad_caller */ virtual ~dispatcher() = 0; /** @short puts the tunnel context into the list of messages to dispatch */ virtual void send(tunnel_context_base* context); /** @return the count of tunnel contexts in the queue */ gint queued_contexts() const; threadhandle_type creator_thread() const { return m_creator_thread; } protected: /** @short processes the next message in the queue. * @note only called from dispatcher thread. */ bool process_next(); /** * @throw bad_caller */ void test_calling_thread(); private: typedef std::queue context_container_type; typedef mutex_lockable lockable_tunnel_contexts; lockable_tunnel_contexts m_tunnel_contexts; /** @short current number of messages in the queue * @note we could query m_tunnel_context_list for its size but we want to be sure * that querying the number of queued tunnel contexts is as lockfree as * possible. To increment and decrement the counter glib atomic * operations are used. */ volatile gint m_contexts_count; const threadhandle_type m_creator_thread; // deadlock detection private: /** @short Increases the synchronous message count for the server thread and * throws an exception if there are messages pending from the server thread * to the client (sending) thread or if the client thread sends a * synchronous message to itself. * @throw bad_sync_call * @note Call always from the client thread, i.e. execute this method in * the context of the thread sending the message. * * @throw bad_sync_call */ static void increase_sync_messages(const dld::thread_pair_type& threadpair); /** @short Decreases the synchronous message count for the server thread. * @throw bad_sync_call * @note Call always from the server thread, i.e. execute this method * in the context of the thread that has received the synchronous message. */ static void decrease_sync_messages(const dld::thread_pair_type& threadpair); static dld::lockable_sync_messages_type thread_paired_sync_messages; }; } // namespace sigx #endif // end file guard sigx/sigx/glib_lockables.h0000644000175000017500000000755111123532203017001 0ustar triendl.kjtriendl.kj#ifndef _SIGX_GLIB_LOCKABLES_HPP_ #define _SIGX_GLIB_LOCKABLES_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded * Programmer's Best Friend": * http://www.ddj.com/dept/cpp/184403766 */ #include #include #include namespace sigx { /** @addtogroup threadsafety * @{ */ /** @short Makes @e T_type read/write %lockable with a Glib::RWLock */ template struct rw_lockable: public lockable { typedef lockable parent_type; public: rw_lockable(): parent_type() {} rw_lockable(typename parent_type::const_reference_type v): parent_type(v) {} }; /** @short Makes @e T_type %lockable with a Glib::Mutex */ template class mutex_lockable: public lockable { typedef lockable parent_type; public: mutex_lockable(): parent_type() {} mutex_lockable(typename parent_type::const_reference_type v): parent_type(v) {} }; /** @short Makes @e T_type %lockable with a Glib::StaticMutex */ template class static_mutex_lockable: public lockable { typedef lockable parent_type; public: static_mutex_lockable(): parent_type() { g_static_mutex_init(this->m_mutex.gobj()); } static_mutex_lockable(typename parent_type::const_reference_type v): parent_type(v) { g_static_mutex_init(this->m_mutex.gobj()); } }; /** @short Makes @e T_type %lockable with a Glib::RecMutex */ template class recmutex_lockable: public lockable { typedef lockable parent_type; public: recmutex_lockable(): parent_type() {} recmutex_lockable(typename parent_type::const_reference_type v): parent_type(v) {} }; /** @short Makes @e T_type %lockable with a Glib::StaticRecMutex */ template class static_recmutex_lockable: public lockable { typedef lockable parent_type; public: static_recmutex_lockable(): parent_type() { g_static_rec_mutex_init(this->m_mutex.gobj()); } static_recmutex_lockable(typename parent_type::const_reference_type v): parent_type(v) { g_static_rec_mutex_init(this->m_mutex.gobj()); } }; template<> struct choose_lock { typedef Glib::RWLock::ReaderLock type; }; template<> struct choose_lock { typedef Glib::RWLock::WriterLock type; }; template struct choose_lock { typedef Glib::Mutex::Lock type; }; template struct choose_lock { typedef Glib::RecMutex::Lock type; }; template struct choose_lock { typedef Glib::/*Static*/Mutex::Lock type; }; template struct choose_lock { typedef Glib::/*Static*/RecMutex::Lock type; }; // @addtogroup threadsafety /** @} */ } // namespace sigx #endif // end file guard sigx/sigx/tunnel_context.h0000644000175000017500000001440111123532203017106 0ustar triendl.kjtriendl.kj#ifndef _SIGX_TUNNEL_CONTEXT_H_ #define _SIGX_TUNNEL_CONTEXT_H_ /* * Copyright 2007 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // std::auto_ptr #include #include #include #include #include #include #include namespace sigx { /** @short Represents a tunnel message. * * Specializations of this template represent different types of tunnel messages. * tunnel_contextS are typically created on the heap by tunnel_functorS and * manage their lifetime themselves. * * @ingroup Dispatching */ template struct tunnel_context; /** @short Exists solely to make the compiler deduce the meta argument T_adaptor. */ template tunnel_context* make_new_tunnel_context(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker, const T_adaptor& _A_func) { return new tunnel_context(_A_disp, _A_validity_tracker, _A_func); } /** @short An asynchronous tunnel message. * * Asynchronous tunnels store a copy of the passed arguments by value, thus * ensuring valid argument transmission. * * @note Asynchronous tunnels disregard the return value of * the invoked functor and return the return type's default value * @ingroup Dispatching */ template struct tunnel_context: public tunnel_context_base { typedef tunnel_context this_type; typedef T_return result_type; tunnel_context(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker, typename sigc::type_trait::take _A_func): tunnel_context_base(_A_disp, _A_validity_tracker), m_boundmessage(_A_func) {} /** @short dispatches the tunnel_context (itself) over the referenced * dispatcher. */ result_type tunnel() { tunnel_context_base::dispatch_me(); return result_type(); } void invoke() { // async tunnels must delete themselves after dispatching const std::auto_ptr autodelete_this(this); // call functor in the context of the server thread, disregard return value m_boundmessage(); } private: T_unary_functor m_boundmessage; }; /** @short A synchronous tunnel message * * Synchronous tunnels store reference wrappers to the passed arguments, thus * optimizing argument transmission. * * @note Synchronous tunnels lock until the functor at the other side * of the tunnel has completed except for when the dispatcher reference is not * valid anymore (the owner thread of the dispatcher has destroyed its * dispatcher). * @ingroup Dispatching */ template struct tunnel_context: public sync_tunnel_context_base { typedef tunnel_context this_type; typedef T_return result_type; tunnel_context(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker, typename sigc::type_trait::take _A_func): sync_tunnel_context_base(_A_disp, _A_validity_tracker), m_boundmessage(_A_func), m_bound_result(result_type()) {} /** @short dispatches the tunnel_context (itself) over the referenced * dispatcher. */ T_return tunnel() { const std::auto_ptr autodelete_this(this); Glib::Mutex::Lock lock(m_mutex); // rather call tunnel_context_base::dispatch_me() than // sync_tunnel_context_base::dispatch_me() because we want to ensure // that the result is returned while we still hold the lock tunnel_context_base::dispatch_me(); // synchronize with other end of the tunnel m_cond.wait(m_mutex); return m_bound_result.invoke(); } void invoke() { Glib::Mutex::Lock lock(m_mutex); // save result m_bound_result = m_boundmessage(); // tell the one end of the tunnel that we are done m_cond.signal(); } private: T_unary_functor m_boundmessage; sigc::bound_argument::type> m_bound_result; }; /** @short a synchronous tunnel with return type `void". * * Synchronous tunnels store reference wrappers to the passed arguments, thus * optimizing argument transmission. * * @note Synchronous tunnels lock until the functor at the other side * of the tunnel has completed except for when the dispatcher reference is not * valid anymore (the owner thread of the dispatcher has destroyed its * dispatcher). * @ingroup Dispatching */ template struct tunnel_context: public sync_tunnel_context_base { typedef tunnel_context this_type; typedef void result_type; tunnel_context(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker, typename sigc::type_trait::take _A_func): sync_tunnel_context_base(_A_disp, _A_validity_tracker), m_boundmessage(_A_func) {} /** @short dispatches the tunnel_context (itself) over the referenced * dispatcher. */ void tunnel() { const std::auto_ptr autodelete_this(this); sync_tunnel_context_base::dispatch_me(); } void invoke() { Glib::Mutex::Lock lock(m_mutex); m_boundmessage(); // tell the one end of the tunnel that we are done m_cond.signal(); } private: T_unary_functor m_boundmessage; }; } // namespace sigx #endif // file guard sigx/sigx/validity_trackable.h0000644000175000017500000000527411123532202017701 0ustar triendl.kjtriendl.kj#ifndef _SIGX_VALIDITY_TRACKABLE_HPP_ #define _SIGX_VALIDITY_TRACKABLE_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include // gint #include #include #include #include namespace sigx { namespace internal { /** @short Lynchpin to track the validity of a tunnel functor and storing * information about who needs to be notified about dying dispatchers * and tunnel functors. */ struct validity_trackable: public operator_new { validity_trackable(const shared_dispatchable& _A_disp); gint m_refcount; // track the reference count from tunnel functors // (functionality wrapped in tunnel_validity_tracker) // in a separate variable to be able to track those // validity_trackables that don't have a purpose anymore gint m_tunnel_refcount; bool m_valid; /// A connection_wrapper to a signal std::list m_connections; /// The dispatchable guarding the tunnel callback. /// It has us registered shared_dispatchable m_disp; std::vector m_trackables; /// this variable holds the address of the dispatcher /// with which the tunnel functor was originally created; /// this allows to track a change of the dispatcher; /// a change might happen if a thread ends and the threadable /// resets its dispatcher, /// but the threadable starts again and sets up another dispatcher. /// This situation is fine for request functors because they /// only need a valid dispatcher; however, this situation is a problem /// for tunnel functors connected in a server thread because for them /// resetting the dispatcher means that they will get disconnected /// from the server thread's signal. //const dispatcher_ptr m_original_dispatcher; gint m_dispatcher_change_is_cleanup; void* m_creator_thread; }; } // namespace internal } // namespace sigx #endif // _SIGX_VALIDITY_TRACKABLE_HPP_ sigx/sigx/tunnel_functor.h0000644000175000017500000006772311126512655017135 0ustar triendl.kjtriendl.kj// -*- c++ -*- /* Do not edit! -- generated file */ #ifndef _SIGXMACROS_TUNNEL_FUNCTOR_H_ #define _SIGXMACROS_TUNNEL_FUNCTOR_H_ /* * Copyright 2007 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @defgroup Functors Adaptors * @short Useful sigc++ adaptors. */ #include #include #include #include #include #include namespace sigx { template struct tunnel_functor; /** @short creates a tunnel on the given functor. * @note expects the functor to be dispatchable. A functor is dispatchable if * the class the functor operates on is derived from sigx::dispatchable or if the * functor is or contains a SIGX_DISPATCH_WITH_FUNCTOR. * @ingroup Functors * @code * // if class MyThread is dispatchable, sigc::mem_fun creates a dispatchable functor. * open_tunnel(sigc::mem_fun(destobj, &MyThread::dosomething)); * // otherwise, create a dispatchable functor explicitly with dispatch_with * open_tunnel_with(sigc::mem_fun(destobj, &MyThread::dosomething), dispatchable); * open_tunnel_with(sigc::ptr_fun(&MyThread::dosomething_static), dispatchable); * @endcode * @attention Never invoke an asynchronous functor with arguments passed by * reference with sigc::ref() (or at least not if you don't know exactly what * you are doing)! * @note You have to be careful that T_functor, arguments bound to it and * passed arguments are threadsafe. * Asynchronous tunnels copy T_functor and passed arguments on invokation of * the tunnel functor and destroy them in the context of the server thread * (the thread receiving the message which is different from the sender thread!). * e.g. never do this: * @code * struct MyThread * { * void do_something(const GLib::RefPtr& p) {} * }; * * Glib::RefPtr p; * open_tunnel(mythread, &MyThread::do_something)(p); * @endcode * For safety reasons you can apply this rule also for synchronous tunnels, * although the invokation behaves differently: Still T_functor is copied but * passed arguments are sent by reference to the server thread. * The same rules apply for sigx::request_f */ template struct tunnel_functor: public sigc::adapts, public tunnel_base { typedef typename sigc::adapts::adaptor_type adaptor_type; typedef typename adaptor_type::result_type result_type; template struct deduce_result_type { // we could also use sigc::deduce_result_type but this saves another // level of indirection and does what sigc++ does internally typedef typename adaptor_type::template deduce_result_type::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass>::type type; }; result_type operator()() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD result_type sun_forte_workaround() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4, _A_arg5))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4, _A_arg5))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4, _A_arg5, _A_arg6))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4, _A_arg5, _A_arg6))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6, T_arg7 _A_arg7) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4, _A_arg5, _A_arg6, _A_arg7))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6, T_arg7 _A_arg7) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, _A_arg1, _A_arg2, _A_arg3, _A_arg4, _A_arg5, _A_arg6, _A_arg7))->tunnel(); } #endif /** @short Constructs an adaptor that wraps the passed functor. * @param _A_func Functor to invoke at the other end of the tunnel * from operator()(). * @param dispatcher_change_is_cleanup Whether a dispatcher change should be * be treated as reason to destroy the tunnel * @note The passed in functor must be a "dispatchable functor", i.e. * a functor on a dispatchable's method or a functor created by * sigx::dispatch_with. */ explicit tunnel_functor(typename sigc::type_trait::take _A_func): sigc::adapts(_A_func), // find the dispatchable object contained in the functor by // stepping down the functor chain; // dispatchable_constraint finds the dispatchable and issues a compiler // error if the passed in functor is not a functor on a dispatchable's // method or does find a dispatchable in a SIGX_DISPATCH_WITH_FUNCTOR tunnel_base(internal::dispatchable_constraint::find_dispatchable(this->functor_)) {} // implicit copy ctor is fine // implicit dtor is fine // implicit assignment operator is fine /** @short Activates validity tracking for sigc::trackableS and tracking of a dispatcher change * (e.g. when a thread finishes its execution and resets its dispatcher) * @note %activate_validity_tracking() assumes that the tunnel functor, all sigc::trackableS and the dispatcher/dispatchable * are managed and accessed in the context of the calling thread. */ void activate_validity_tracking() const { validity_tracker().activate(); // visit each trackable and bind the validity trackable to the sigc trackable and vice versa sigc::visit_each_type( sigc::mem_fun(validity_tracker(), &tunnel_validity_tracker::do_bind_to_trackable), this->functor_ ); } }; template struct tunnel_functor: public sigc::adapts, public tunnel_base { typedef typename sigc::adapts::adaptor_type adaptor_type; typedef typename adaptor_type::result_type result_type; template struct deduce_result_type { // we could also use sigc::deduce_result_type but this saves another // level of indirection and does what sigc++ does internally typedef typename adaptor_type::template deduce_result_type::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass>::type type; }; result_type operator()() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD result_type sun_forte_workaround() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1)))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2)))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3)))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4)))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4), sigx::ref(_A_arg5)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4), sigx::ref(_A_arg5)))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4), sigx::ref(_A_arg5), sigx::ref(_A_arg6)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4), sigx::ref(_A_arg5), sigx::ref(_A_arg6)))->tunnel(); } #endif template typename deduce_result_type::type operator()(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6, T_arg7 _A_arg7) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4), sigx::ref(_A_arg5), sigx::ref(_A_arg6), sigx::ref(_A_arg7)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(T_arg1 _A_arg1, T_arg2 _A_arg2, T_arg3 _A_arg3, T_arg4 _A_arg4, T_arg5 _A_arg5, T_arg6 _A_arg6, T_arg7 _A_arg7) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, sigx::ref(_A_arg1), sigx::ref(_A_arg2), sigx::ref(_A_arg3), sigx::ref(_A_arg4), sigx::ref(_A_arg5), sigx::ref(_A_arg6), sigx::ref(_A_arg7)))->tunnel(); } #endif /** @short Constructs an adaptor that wraps the passed functor. * @param _A_func Functor to invoke at the other end of the tunnel * from operator()(). * @param dispatcher_change_is_cleanup Whether a dispatcher change should be * be treated as reason to destroy the tunnel * @note The passed in functor must be a "dispatchable functor", i.e. * a functor on a dispatchable's method or a functor created by * sigx::dispatch_with. */ explicit tunnel_functor(typename sigc::type_trait::take _A_func): sigc::adapts(_A_func), // find the dispatchable object contained in the functor by // stepping down the functor chain; // dispatchable_constraint finds the dispatchable and issues a compiler // error if the passed in functor is not a functor on a dispatchable's // method or does find a dispatchable in a SIGX_DISPATCH_WITH_FUNCTOR tunnel_base(internal::dispatchable_constraint::find_dispatchable(this->functor_)) {} // implicit copy ctor is fine // implicit dtor is fine // implicit assignment operator is fine /** @short Activates validity tracking for sigc::trackableS and tracking of a dispatcher change * (e.g. when a thread finishes its execution and resets its dispatcher) * @note %activate_validity_tracking() assumes that the tunnel functor, all sigc::trackableS and the dispatcher/dispatchable * are managed and accessed in the context of the calling thread. */ void activate_validity_tracking() const { validity_tracker().activate(); // visit each trackable and bind the validity trackable to the sigc trackable and vice versa sigc::visit_each_type( sigc::mem_fun(validity_tracker(), &tunnel_validity_tracker::do_bind_to_trackable), this->functor_ ); } }; /** @short Binds a dispatchable explicitly to a functor. * @note Use only with non-dispatchable functors (functors on functions or * methods of classes that do not derive from sigx::dispatchable) * @ingroup Functors */ template SIGX_DISPATCH_WITH_FUNCTOR(T_functor) dispatch_with(const T_functor& _A_func, const shared_dispatchable& d) { return sigc::bind(sigc::hide(_A_func), d); } /** @short Opens an asynchronous tunnel on the specified functor. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_tunnel(const T_functor& _A_func) { return tunnel_functor(_A_func); } /** @short Opens a synchronous tunnel on the specified functor. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_sync_tunnel(const T_functor& _A_func) { return tunnel_functor(_A_func); } /** @short Opens an asynchronous tunnel on the specified functor with the dispatcher of the specified dispatchable. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @param d the dispatchable to operate on * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_tunnel_with(const T_functor& _A_func, const shared_dispatchable& d) { return tunnel_functor(dispatch_with(_A_func, d)); } /** @short Opens a synchronous tunnel on the specified functor with the dispatcher of the specified dispatchable. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @param d the dispatchable to operate on * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_sync_tunnel_with(const T_functor& _A_func, const shared_dispatchable& d) { return tunnel_functor(dispatch_with(_A_func, d)); } } // namespace sigx namespace sigc { /** @short visit_each overload for tunnel functors, completely turning off the visit_each mechanism and thus turning off the trackable mechanism. * * This is necessary because binding a tunnel functor to a slot would access a trackable in a non-threadsafe manner. * sigx++ activates validity tracking for trackables at the call site when the client thread connects to a signal through signal_wrapper<>::connect() */ template void visit_each(const T_action& /*_A_action*/, const sigx::tunnel_functor& /*_A_func*/) { // do nothing } } // namespace sigc #endif /* _SIGXMACROS_TUNNEL_FUNCTOR_H_ */ sigx/sigx/sigx.h0000644000175000017500000000437411123532203015017 0ustar triendl.kjtriendl.kj#ifndef _SIGX_HPP_ #define _SIGX_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // don't impose tr1 onto the programmer //#include #include #include #include #include #include #include #include #include // don't impose boost onto the programmer //#include //#include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include //only used internally //#include //#include //#include //#include //#include //#include #include #include #include #include #include #include #include #endif // end file guard sigx/sigx/signal_wrapper.h0000644000175000017500000022400011126512655017064 0ustar triendl.kjtriendl.kj// -*- c++ -*- /* Do not edit! -- generated file */ #ifndef _SIGXMACROS_SIGNAL_WRAPPER_H_ #define _SIGXMACROS_SIGNAL_WRAPPER_H_ /* * Copyright 2007 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include // std::tr1::shared_ptr, std::auto_ptr #include #include // glibmm signals #include #include #include #include #include #include #include #include /** @defgroup signals Signals * Threadsafe signals on top of the @ref Functors and @ref Dispatching * facilities */ namespace sigx { namespace internal { /** @short Counts a signal's arguments, default class */ template struct count_signal_arguments { static const int value = -1; static const int tspec = -1; }; /** @short Counts the arguments of an unnumbered sigc::signal */ template struct count_signal_arguments > { // forward to count_arguments and not to count_signal_arguments, otherwise // we would get a false count if there is a another signal as the first // argument of a signal, like: sigc::signal > static const int value = count_arguments::value; static const int tspec = value; }; /** @short counts the arguments of a sigc::signal0 */ template struct count_signal_arguments > { static const int value = 0; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal1 */ template struct count_signal_arguments > { static const int value = 1; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal2 */ template struct count_signal_arguments > { static const int value = 2; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal3 */ template struct count_signal_arguments > { static const int value = 3; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal4 */ template struct count_signal_arguments > { static const int value = 4; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal5 */ template struct count_signal_arguments > { static const int value = 5; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal6 */ template struct count_signal_arguments > { static const int value = 6; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a sigc::signal7 */ template struct count_signal_arguments > { static const int value = 7; // template specialization for argument count needed static const int tspec = value; }; /** @short counts the arguments of a Glib::SignalProxy0 */ template struct count_signal_arguments > { static const int value = 0; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short counts the arguments of a Glib::SignalProxy1 */ template struct count_signal_arguments > { static const int value = 1; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short counts the arguments of a Glib::SignalProxy2 */ template struct count_signal_arguments > { static const int value = 2; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short counts the arguments of a Glib::SignalProxy3 */ template struct count_signal_arguments > { static const int value = 3; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short counts the arguments of a Glib::SignalProxy4 */ template struct count_signal_arguments > { static const int value = 4; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short counts the arguments of a Glib::SignalProxy5 */ template struct count_signal_arguments > { static const int value = 5; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short counts the arguments of a Glib::SignalProxy6 */ template struct count_signal_arguments > { static const int value = 6; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; /** @short Counts the arguments of a Glib::SignalIdle */ template<> struct count_signal_arguments { static const int value = 0; static const int tspec = value; }; /** @short Counts the arguments of a Glib::SignalTimeout */ template<> struct count_signal_arguments { static const int value = 0; static const int tspec = value; }; /** @short Counts the arguments of a Glib::SignalIO */ template<> struct count_signal_arguments { static const int value = 1; static const int tspec = value; }; /** @short Counts the arguments of a Glib::SignalChildWatch */ template<> struct count_signal_arguments { static const int value = 2; static const int tspec = value; }; } // namespace internal /** @short A threadsafe wrapper for sigc signals, Glib * signals or theoretically any other type of signal. * * sigx signals have a shared signal source that exists in the context of * another thread. This signal source has access to the signal. Access (e.g. * connecting) is regulated by a dispatcher running in the context of the * thread owning that signal. */ template::type, int I_arg_count = internal::count_signal_arguments::tspec> class signal_wrapper; /** @short A threadsafe wrapper for any sigc signal with 0 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 0)); static const int argument_count = 0; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor0 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit() const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(); } /** @short emits the signal asynchronously. */ result_type emit() const { return emit(); } /** @short emits the signal synchronously. */ result_type emit_sync() const { return emit(); } /** see emit() */ result_type operator()() const { return emit(); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 1 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 1)); static const int argument_count = 1; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor1 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1) const { return emit(_A_a1); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1) const { return emit(_A_a1); } /** see emit(arg1_type_) */ result_type operator()(arg1_type_ _A_a1) const { return emit(_A_a1); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 2 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 2)); static const int argument_count = 2; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef typename slot_type::arg2_type_ arg2_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor2 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1, _A_a2); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2) const { return emit(_A_a1, _A_a2); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1, arg2_type_ _A_a2) const { return emit(_A_a1, _A_a2); } /** see emit(arg1_type_, arg2_type_) */ result_type operator()(arg1_type_ _A_a1, arg2_type_ _A_a2) const { return emit(_A_a1, _A_a2); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 3 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 3)); static const int argument_count = 3; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef typename slot_type::arg2_type_ arg2_type_; typedef typename slot_type::arg3_type_ arg3_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor3 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1, _A_a2, _A_a3); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3) const { return emit(_A_a1, _A_a2, _A_a3); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3) const { return emit(_A_a1, _A_a2, _A_a3); } /** see emit(arg1_type_, arg2_type_, arg3_type_) */ result_type operator()(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3) const { return emit(_A_a1, _A_a2, _A_a3); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 4 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 4)); static const int argument_count = 4; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef typename slot_type::arg2_type_ arg2_type_; typedef typename slot_type::arg3_type_ arg3_type_; typedef typename slot_type::arg4_type_ arg4_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor4 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1, _A_a2, _A_a3, _A_a4); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4); } /** see emit(arg1_type_, arg2_type_, arg3_type_, arg4_type_) */ result_type operator()(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 5 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 5)); static const int argument_count = 5; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef typename slot_type::arg2_type_ arg2_type_; typedef typename slot_type::arg3_type_ arg3_type_; typedef typename slot_type::arg4_type_ arg4_type_; typedef typename slot_type::arg5_type_ arg5_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor5 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5); } /** see emit(arg1_type_, arg2_type_, arg3_type_, arg4_type_, arg5_type_) */ result_type operator()(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 6 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 6)); static const int argument_count = 6; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef typename slot_type::arg2_type_ arg2_type_; typedef typename slot_type::arg3_type_ arg3_type_; typedef typename slot_type::arg4_type_ arg4_type_; typedef typename slot_type::arg5_type_ arg5_type_; typedef typename slot_type::arg6_type_ arg6_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor6 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6); } /** see emit(arg1_type_, arg2_type_, arg3_type_, arg4_type_, arg5_type_, arg6_type_) */ result_type operator()(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for any sigc signal with 7 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == 7)); static const int argument_count = 7; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; typedef typename slot_type::arg1_type_ arg1_type_; typedef typename slot_type::arg2_type_ arg2_type_; typedef typename slot_type::arg3_type_ arg3_type_; typedef typename slot_type::arg4_type_ arg4_type_; typedef typename slot_type::arg5_type_ arg5_type_; typedef typename slot_type::arg6_type_ arg6_type_; typedef typename slot_type::arg7_type_ arg7_type_; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor7 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6, arg7_type_ _A_a7) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6, _A_a7); } /** @short emits the signal asynchronously. */ result_type emit(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6, arg7_type_ _A_a7) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6, _A_a7); } /** @short emits the signal synchronously. */ result_type emit_sync(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6, arg7_type_ _A_a7) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6, _A_a7); } /** see emit(arg1_type_, arg2_type_, arg3_type_, arg4_type_, arg5_type_, arg6_type_, arg7_type_) */ result_type operator()(arg1_type_ _A_a1, arg2_type_ _A_a2, arg3_type_ _A_a3, arg4_type_ _A_a4, arg5_type_ _A_a5, arg6_type_ _A_a6, arg7_type_ _A_a7) const { return emit(_A_a1, _A_a2, _A_a3, _A_a4, _A_a5, _A_a6, _A_a7); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; /** @short A threadsafe wrapper for a Glib::SignalNormalProxy derived signal. * @ingroup signals */ template // have to specialize the argument count explicitly because template arguments // can't be involved as template parameters in further template arguments class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_GLIB_PROXY; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::SlotType slot_type; typedef typename signal_type::VoidSlotType void_slot_type; typedef typename slot_type::result_type result_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, bool after = true) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), after ) ); } /** * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect_notify(const T_functor& _A_func, bool after = false) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect_notify), after ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalIdle. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalIdle signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, int priority = Glib::PRIORITY_DEFAULT_IDLE) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), priority ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalTimeout. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalTimeout signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, unsigned int interval, int priority = Glib::PRIORITY_DEFAULT) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), interval, priority ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalIO. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalIO signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the source of the server * thread's signal. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, Glib::IOCondition condition, int priority = Glib::PRIORITY_DEFAULT) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), condition, priority ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalChildWatch. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalChildWatch signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, GPid pid, int priority = Glib::PRIORITY_DEFAULT) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), pid, priority ) ); } }; typedef signal_wrapper glib_signal_idle; typedef signal_wrapper glib_signal_timeout; typedef signal_wrapper glib_signal_io; typedef signal_wrapper glib_ignal_childwatch; } // namespace sigx #endif /* _SIGXMACROS_SIGNAL_WRAPPER_H_ */ sigx/sigx/tunnel_base.h0000644000175000017500000000356111123532203016341 0ustar triendl.kjtriendl.kj#ifndef _SIGX_TUNNEL_BASE_HPP_ #define _SIGX_TUNNEL_BASE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short A hint to the compiler that the functor is a tunnel_functor. * @note We could derive it from sigc::adaptor_base but then we would end * up with two instances of sigc::adaptor_base and sigc::functor_base because * tunnel functors derive additionally from sigc::adapts that * derives from sigc::adaptor_base, too. * We could define our own intermediate type like * sigx::tunnels in the same way sigc::adapts is * defined but we don't want to break sigc++ functionality. */ class SIGX_API tunnel_base { public: tunnel_base(const shared_dispatchable& _A_disp); // implicit copy ctor is fine // implicit dtor is fine // implicit assignment operator is fine public: tunnel_validity_tracker& validity_tracker() const { return m_validity_tracker; } protected: shared_dispatchable m_disp; mutable tunnel_validity_tracker m_validity_tracker; }; } // namespace sigx #endif // _SIGX_TUNNEL_BASE_HPP_ sigx/sigx/tunnel_validity_tracker.h0000644000175000017500000000662011123532202020765 0ustar triendl.kjtriendl.kj#ifndef _SIGX_TUNNEL_VALIDITY_TRACKER_HPP_ #define _SIGX_TUNNEL_VALIDITY_TRACKER_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short Interface for tracking the validity of a tunnel. * */ class SIGX_API tunnel_validity_tracker { public: tunnel_validity_tracker(const shared_dispatchable& _A_disp); tunnel_validity_tracker(const tunnel_validity_tracker& other); tunnel_validity_tracker& operator =(const tunnel_validity_tracker& other); ~tunnel_validity_tracker(); /** @short Adds a dependency to @p t. * * Increases the reference count of the validity info object. * * @param t The trackable object to add a callback to. * Must be const because functors might have stored const trackables. */ void do_bind_to_trackable(const sigc::trackable* t) const; void add_connection(const connection_wrapper& c); /** @short Whether the callback is still valid (all trackables are still * alive and dispatcher didn't change). * @return true = valid, false = invalid (callback must not be executed) */ bool is_valid() const; /** @short Activate the validity tracking. * @note Called from tunnel_functor<>::activate_validity_tracking() */ void activate(); /** @short This function will be called by the destructor of sigc::trackableS. * * It invalidates the callback associated in a tunnel context. * If it was the last object referencing the validity object that notified * then %notify() destroys the validity info object. * It also disconnects eventually the tunnel functor from a signal and * notifies the dispatchable associated with the tunnel functor that the * tunnel functor is not valid anymore. * @param data Handle to the validity info object. */ static void* notify_from_trackable(void* data); /** @short This function will be called by the dispatchable whenever the dispatcher changes. * * It invalidates the callback associated in a tunnel context. * If it was the last object referencing the validity object that notified * then %notify() destroys the validity info object. * It also disconnects eventually the tunnel functor from a signal and * notifies the dispatchable associated with the tunnel functor that the * tunnel functor is not valid anymore. * @param data Handle to the validity info object. */ static void notify_dispatcher_change(void* data); private: static void clear_connections(internal::validity_trackable* t); static void cleanup(void* data, bool cleanup_dispatcher); static void on_last_functor(tunnel_validity_tracker& data); private: internal::validity_trackable* m_info; }; } // namespace sigx #endif // end file guard sigx/sigx/operator_new.h0000644000175000017500000000243311131222743016547 0ustar triendl.kjtriendl.kj#ifndef _SIGX_OPERATOR_NEW_HPP_ #define _SIGX_OPERATOR_NEW_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short Ensures allocation of derived objects in the sigx module * @note Intended use as baseclass only. */ class SIGX_API operator_new { protected: operator_new() {} ~operator_new() {} public: void* operator new(std::size_t size); void operator delete(void* p); void* operator new[](std::size_t size); void operator delete[](void* p); }; } // namespace sigx #endif // end file guard sigx/sigx/noncopyable.h0000644000175000017500000000245511123532203016354 0ustar triendl.kjtriendl.kj#ifndef _SIGX_NONCOPYABLE_HPP_ #define _SIGX_NONCOPYABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * Inspired by Beman Dawes' boost::noncopyable */ #include namespace sigx { /** @short Private copy constructor and copy assignment ensure derived classes * cannot be copied. * @note Intended use as baseclass only. */ class SIGX_API noncopyable { protected: noncopyable() {} ~noncopyable() {} private: noncopyable(const noncopyable&); noncopyable& operator =(const noncopyable&); }; } // namespace sigx #endif // #ifndef _SIGX_NONCOPYABLE_HPP_ sigx/sigx/bad_caller.h0000644000175000017500000000214211123532204016105 0ustar triendl.kjtriendl.kj#ifndef _SIGX_BAD_CALLER_HPP_ #define _SIGX_BAD_CALLER_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { class bad_caller: public std::exception//, public operator_new { public: bad_caller(): std::exception() {} // virtuals from std::exception virtual const char* what() const throw(); }; } // namespace sigx #endif // end file guard sigx/sigx/private/0000755000175000017500000000000011123532033015337 5ustar triendl.kjtriendl.kjsigx/sigx/private/glib_threadable_p.h0000644000175000017500000000175011123532033021122 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { struct glib_threadable::threaddata { Glib::RefPtr m_pContext; Glib::RefPtr m_pLoop; }; } // namespace sigx sigx/sigx/fwddecl.h0000644000175000017500000000311211123532203015442 0ustar triendl.kjtriendl.kj#ifndef _SIGX_FWDDECL_HPP_ #define _SIGX_FWDDECL_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ namespace sigc { struct trackable; struct connection; } // namespace sigc namespace Glib { template class RefPtr; class MainContext; class SignalIdle; } // namespace Glib namespace sigx { namespace internal { class tunnel_validity_tracker; struct validity_trackable; } // namespace internal // fwd decl class bad_caller; class bad_sync_call; class shared_dispatchable; class signal_source_base; class dispatcher; class dispatchable; class shared_dispatchable; class tunnel_base; class connection_wrapper; // typedefs typedef dispatcher* dispatcher_ptr; typedef signal_source_base* signal_source_ptr; typedef sigc::connection* sigc_connection_ptr; } // namespace sigx #include #endif // end file guard sigx/sigx/glib_dispatcher.h0000644000175000017500000000313511123532203017162 0ustar triendl.kjtriendl.kj#ifndef _SIGX_GLIB_DISPATCHER_HPP #define _SIGX_GLIB_DISPATCHER_HPP /* * Copyright 2005 Tim Mayberry and Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include namespace sigx { /** @short a dispatcher on top of Glib::dispatcher. * * This will work with gtkmm but only glibmm is required. * @ingroup Dispatching */ class glib_dispatcher: public dispatcher { public: glib_dispatcher(const Glib::RefPtr& context = Glib::MainContext::get_default()); /** * @throw bad_caller */ ~glib_dispatcher(); // virtuals from dispatcher virtual void send(tunnel_context_base* tcb); private: void do_work(); ///< the dispatcher doing the interthread communication Glib::Dispatcher m_disp; }; } // namespace sigx #endif // _SIGX_GLIB_DISPATCHER_HPP sigx/sigx/nonassignable.h0000644000175000017500000000241711123532203016664 0ustar triendl.kjtriendl.kj#ifndef _SIGX_NONASSIGNABLE_HPP_ #define _SIGX_NONASSIGNABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { /** @short Private assignment operator (operator =) ensures that derived classes * can't be copied by assignment. * @note Intended use as a baseclass only. * @author klaus triendl */ class SIGX_API nonassignable { protected: nonassignable() {} ~nonassignable() {} private: nonassignable& operator =(const nonassignable&); }; } // namespace sigx #endif // #ifndef _SIGX_NONASSIGNABLE_HPP_ sigx/sigx/glib_threadable.h0000644000175000017500000002730111123532203017130 0ustar triendl.kjtriendl.kj#ifndef _SIGX_GLIB_THREADABLE_HPP_ #define _SIGX_GLIB_THREADABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include namespace sigx { /** @short A useful and convenient thread wrapper for Glib threads. * * A glib_threadable is used as a baseclass handling the major part of dealing with * Glib threads in a threadsafe manner. * It encapsulates starting and ending the thread, setting and cleaning up a * Glib::MainContext and Glib::MainLoop for the thread and a sigx::dispatcher. * * Derived classes just need a request interface and a signal interface * other threads can connect to. * The request interface consists of methods instructing the thread to do * something by * tunneling a message with sigx::open_tunnel() to a thread private request * handler method that gets called when the message gets dispatched. * * The thread in turn emits a signal that it has successfully (or not) completed * the task. All thread's connected to that signal then know of the thread's * attempt to execute the request. * * A glib_threadable uses a sigx::glib_dispatcher (that in turn uses a * Glib::Dispatcher) to dispatch requests in a threadsafe manner. * * See the following code example to get an idea how to derive from glib_threadable and its usage. * * @code * class MyThread: public sigx::glib_threadable * { * protected: * typedef sigc::signal signal_did_something_t; * * private: * struct ThreadPrivate * { * signal_did_something_t m_sigDidSomething; * }; * * * private: * Glib::Private m_threadpriv; * * public: * MyThread(); * * // request interface * sigx::request_f<> do_something; * * // signal interface; * // return a sigx::signal_wrapper for threadsafe access to the signal did_something * sigx::signal_f signal_did_something; * * protected: * // virtuals from threadable * virtual void on_startup(); * * // dispatcher methods, get called when requests of the request interface * // get dispatched * void on_do_something(); * }; * * * MyThread::MyThread(): * m_threadpriv(), * // initialize request interface * do_something(sigc::mem_fun(this, &MyThread::on_do_something)), * // initialize signal interface * signal_did_something(this, m_threadpriv, &ThreadPrivate::m_sigDidSomething) * {} * * void MyThread::on_startup() * { * m_threadpriv.set(new ThreadPrivate); * } * * void MyThread::on_do_something() * { * // do something * // ... * * // broadcast that I have done something * const success = true; * ThreadPrivate* privdata = m_threadpriv.get(); * privdata->m_sigDidSomething.emit(success); * } * @endcode * * When a glib_threadable is instantiated the thread does not immediately start its * execution. You have to start it explicitly by calling run(). * * @note The thread must have finished before the destructor is called. * * @ingroup Threading */ class SIGX_API glib_threadable: public threadable { public: /** @short Constructs the threadable object. * @note The thread must be started explicitly by calling run(). */ glib_threadable(); /** @short dtor. * @attention Thread must have finished before dtor is called. */ virtual ~glib_threadable(); /** @short Creates a joinable thread. * * Start the main loop of the thread. * The function returns as soon as the thread is created which does not * mean that it is already in a running state. * To get notified that it is running you pass in a functor * (@e func_on_thread_ready) that gets called as soon as the thread is in * a running state. * * @attention Multiple calls from multiple threads are not threadsafe; * Call %run() only once from one thread, otherwise there are * unpredictable results. * * @param func_on_thread_ready a functor that gets called as soon * as the thread is idle and ready. The passed in functor is tunneled * automatically if not yet a tunnel_functor. * Must be convertible to a sigc::slot. * * @note In your on_thread_ready handler you can connect to the thread's * signals. * @code * MyThread mythread; * mythread.run(sigc::mem_fun(this, &TheGui::on_mythread_ready)); * * void TheGUI::on_mythread_ready() * { * // now, the thread if fully set up, idle and ready * mythread.signal_did_something().connect( * sigc::mem_fun(this, &TheGUI::on_mythread_did_something) * ); * } * @endcode */ template void run(const T_functor& func_on_thread_ready); /** @short Creates a joinable thread. * * Start the main loop of the thread, this will block until the thread has * been created and is in a running state. * * @attention Multiple calls from multiple threads are not threadsafe; * Call %run() only once from one thread, otherwise there are * unpredictable results. * * Afterwards you can connect to the thread's signals. */ void run(); /** @short Ends the thread, joins it and frees all its resources. * * Waits for the main loop to quit and joins the thread and in the process * deleting all the thread private data associated with this thread and * all the internal resources. * You MUST call %finish() before deleting a class derived from glib_threadable. * * Calling finish() from multiple threads is thread safe; * * @note Ends the thread's mainloop immediately (as soon as the message * gets dispatched). * If your thread still must complete things before actually quitting the * mainloop then you have to create another request in your derived class * like "stop_working()" that signals the thread to stop its work. * "stop_working()" could then send back the answer that the thread has * completed its work and is ready to get the "finish" signal. */ void finish(); private: /** @short Common entry point for run() and run(const T_functor&). */ void create_thread(const sigc::slot& slot_on_thread_ready); /** @short The function the new thread executes. * * Creates and starts the thread's mainloop. * * Also sets up a dispatcher and sets the sigx::dispatchable baseclass' * dispatcher reference. */ void on_run(const sigc::slot& slot_on_thread_ready); /** @short Called when the thread is idle and ready * @pre run() was called. */ void on_idle_and_ready(Glib::Mutex& mtx, Glib::Cond& cond); protected: /** @short access the thread's maincontext */ Glib::RefPtr maincontext(); /** @short access the thread's mainloop */ Glib::RefPtr mainloop(); /** @short Make a signal functor that returns the glib idle signal. */ signal_f make_idle_signal_f() { return signal_f( // the dispatchable *this, // the signal source is a functor executing // this->maincontext()->signal_idle() sigc::compose( // setter sigc::mem_fun(&Glib::MainContext::signal_idle), // getter sigc::compose( // setter sigc::mem_fun(&Glib::RefPtr::operator ->), // getter sigc::mem_fun(this, &glib_threadable::maincontext) ) ) ); } /** @short Make a signal functor that returns the glib timeout signal. */ signal_f make_timeout_signal_f() { return signal_f( // the dispatchable *this, // the signal source is a functor executing // this->maincontext()->signal_timeout() sigc::compose( // setter sigc::mem_fun(&Glib::MainContext::signal_timeout), // getter sigc::compose( // setter sigc::mem_fun(&Glib::RefPtr::operator ->), // getter sigc::mem_fun(this, &glib_threadable::maincontext) ) ) ); } /** @short Make a signal functor that returns the glib IO signal. */ signal_f make_io_signal_f() { return signal_f( // the dispatchable *this, // the signal source is a functor executing // this->maincontext()->signal_io() sigc::compose( // setter sigc::mem_fun(&Glib::MainContext::signal_io), // getter sigc::compose( // setter sigc::mem_fun(&Glib::RefPtr::operator ->), // getter sigc::mem_fun(this, &glib_threadable::maincontext) ) ) ); } /** @short Make a signal functor that returns the glib childwatch signal. */ signal_f make_childwatch_signal_f() { return signal_f( // the dispatchable *this, // the signal source is a functor executing // this->maincontext()->signal_childwatch() sigc::compose( // setter sigc::mem_fun(&Glib::MainContext::signal_child_watch), // getter sigc::compose( // setter sigc::mem_fun(&Glib::RefPtr::operator ->), // getter sigc::mem_fun(this, &glib_threadable::maincontext) ) ) ); } private: struct threaddata; Glib::Private m_threaddata; typedef mutex_lockable mutex_lockable_thread; mutex_lockable_thread m_thread; }; /** @example ipresolver/main.cpp * The IPResolver example shows a way how to delegate IP to hostname resolving * to a thread. * * Starting with the IPResolverThread * @include ipresolver/resolver.h * *
.. its thread private data * @include ipresolver/resolver_p.h * *
.. and its implementation * @include ipresolver/resolver.cpp * *
The user interface * @include ipresolver/thegui.h * *
.. the user interface implementation * @include ipresolver/thegui.cpp * *
and finally the main entry point */ } // namespace sigx #include #include namespace sigx { template void glib_threadable::run(const T_functor& func_on_thread_ready) { typedef internal::auto_tunneler auto_tunneler_t; // passed in functor must not be a slot or adapt a slot; // we have to apply this restriction because slots might have bound // trackables that can cause non-threadsafe access to the passed in slot // which will live in the context of the server thread SIGX_STATIC_ASSERT((sigx::internal::is_or_adapts_slot::value == false)); // toplevel functor must be a tunnel functor SIGX_STATIC_ASSERT((sigc::is_base_and_derived::value == true)); const typename auto_tunneler_t::functor_type& functor2callback = auto_tunneler_t::auto_open_tunnel(func_on_thread_ready); // a sigc::slot is created out of the functor func_on_thread_ready and bound // to another functor suitable for Glib::Thread::create. // this still happens in the context of the calling thread and is therefore // threadsafe create_thread(sigc::slot(functor2callback)); } } // namespace sigx #endif // end file guard sigx/sigx/glib_auto_dispatchable.h0000644000175000017500000000232411123532203020506 0ustar triendl.kjtriendl.kj#ifndef _SIGX_GLIB_AUTO_DISPATCHABLE_HPP_ #define _SIGX_GLIB_AUTO_DISPATCHABLE_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include namespace sigx { /** * * @ingroup Dispatching */ class SIGX_API glib_auto_dispatchable: public auto_dispatchable { public: glib_auto_dispatchable(); glib_auto_dispatchable(const Glib::RefPtr& context); }; } // namespace sigx #endif // end file guard sigx/sigx/lock_acquirer.h0000644000175000017500000003223611123532203016666 0ustar triendl.kjtriendl.kj#ifndef _SIGX_LOCK_ACQUIRER_H_ #define _SIGX_LOCK_ACQUIRER_H_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded * Programmer's Best Friend": * http://www.ddj.com/dept/cpp/184403766 */ #include #include #include #include //#include #include #include #include namespace sigx { /** @addtogroup threadsafety * @{ */ /** @short Locks the given mutex and ensures threadsafe write * access to the given locked type. * * Collects acquisition of a mutex lock and a volatile_cast from a * volatile object. * A lock_acquirer object is initialized with a lock from an associated mutex * and a volatile object. * The appropriate lock is chosen by the metafunction choose_lock according to the * mutex and the locking policy (read/write). Note that because the lock_acquirer is * scope bound choose_lock must only choose scoped lock types. * * During its lifetime, a lock_acquirer keeps the lock acquired. Also, lock_acquirer * offers read or write access (according to the locking policy) to the volatile-stripped object. * Access is granted by a protected friend template function access_acquiree(). * The volatile_cast is performed by access_acquiree(). * The cast is semantically valid because lock_acquirer keeps the lock acquired * for its lifetime. * * If the locking policy is readlock then the lock_acquirer grants only const access to the * protected variable. * * The following template arguments are used: * - @e T_type The type to be protected by the lock, e.g. an int. * - @e T_mutex The lock, e.g. a Glib::Mutex. * - @e I_islockable Whether T_type derives from lockable_base * * @note The locked type can only be accessed with access_acquiree() * @code * // somewhere * boost::mutex mtx; * int x; * * // a scope somewhere else * { * lock_acquirer l(x, mtx); * int& i = access_acquiree(l); * i = 42; * } * @endcode */ template class lock_acquirer: noncopyable/*, nonheapallocatable*/, nonpointeraliasing { protected: typedef T_type acquired_type; typedef T_mutex mutex_type; // value_type = acquired_type with top-level reference stripped off typedef typename std::tr1::remove_reference::type value_type; // const_or_value_type = unchanged value_type if policy is writelock, const value_type if readlock typedef typename boost::mpl::eval_if_c< I_policy == readlock, std::tr1::add_const, boost::mpl::identity >::type const_or_value_type; typedef typename std::tr1::add_reference::type>::type volatile_reference_type; typedef typename std::tr1::add_reference::type>::type reference_type; /** @short Gives non-volatile access to the locked type * * Forces the programmer to pass a previously named lock_acquirer object thus * ensuring that the lock is active throughout the usage of the locked object. */ friend reference_type access_acquiree(lock_acquirer& l) throw() { return l.access_acquiree(); } public: /** @short Constructs a lock_acquirer from a volatile type to protect and a lock. * @note Acquires the lock immediately, unlocks when it goes out of scope. * @attention We rely here on the fact that members are initialized according * to the order in which they are declared in a class, such that * the lock is acquired before _a_value is accessed non-volatile. */ lock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex): m_lock(_a_mutex), // volatile_cast m_acquiree(const_cast(_a_value)) {} /** @short Constructs a lock_acquirer from a volatile type to protect, a lock and * an additional argument forwarded to the lock constructor. * @note Acquires the lock immediately, unlocks when it goes out of scope */ template lock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1): m_lock(_a_mutex, lockfwd_arg1), // volatile_cast m_acquiree(const_cast(_a_value)) {} protected: /** @return The locked type with the `volatile" qualifier removed */ reference_type access_acquiree() throw() { return m_acquiree; } protected: /** @short lock manager appropriate for the lock type */ typename choose_lock::type m_lock; /** @short non-const reference to the locked object */ reference_type m_acquiree; }; template class writelock_acquirer: public lock_acquirer { typedef lock_acquirer parent_type; typedef typename parent_type::mutex_type mutex_type; typedef typename parent_type::volatile_reference_type volatile_reference_type; public: /** @short Constructs a lock_acquirer from a volatile type to lock and a lock. * @note Acquires the lock immediately, unlocks when it goes out of scope */ writelock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex): parent_type(_a_value, _a_mutex) {} /** @short Constructs a lock_acquirer from a volatile type to protect, a lock and * an additional argument forwarded to the lock constructor. * @note Acquires the lock immediately, unlocks when it goes out of scope */ template writelock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1): parent_type(_a_value, _a_mutex, lockfwd_arg1) {} }; template class readlock_acquirer: public lock_acquirer { typedef lock_acquirer parent_type; typedef typename parent_type::mutex_type mutex_type; typedef typename parent_type::volatile_reference_type volatile_reference_type; public: /** @short Constructs a lock_acquirer from a volatile type to lock and a lock. * @note Acquires the lock immediately, unlocks when it goes out of scope */ readlock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex): parent_type(_a_value, _a_mutex) {} /** @short Constructs a lock_acquirer from a volatile type to protect, a lock and * an additional argument forwarded to the lock constructor. * @note Acquires the lock immediately, unlocks when it goes out of scope */ template readlock_acquirer(volatile_reference_type _a_value, mutex_type& _a_mutex, T_lockfwd_arg1 lockfwd_arg1): parent_type(_a_value, _a_mutex, lockfwd_arg1) {} }; /** @short Specialization for a lockable_base derived object; locks the given * lockable object (e.g. a mutex_lockable) and ensures * threadsafe write access to the locked type. * * Collects acquisition of a mutex lock and a volatile_cast from the volatile * object contained in the lockable. * A lock_acquirer object is initialized with a lockable object. * During its lifetime, a lock_acquirer keeps the lock acquired. Also, lock_acquirer * offers write access to the volatile-stripped object. The access is offered * with a related access_acquiree() function. The volatile_cast is performed by access_acquiree(). * The cast is semantically valid because lock_acquirer keeps the lock acquired * for its lifetime. * * The following template arguments are used: * - @e T_lockable A lockable_base derived type, e.g. a mutex_lockable. * * The lock_acquirer chooses the appropriate lock manager for the lock automatically * by applying the choose_lock. * * @note The locked type can only be accessed with access_acquiree() * @code * // somewhere * mutex_lockable lockable_int; * * // a scope somewhere else * { * lock_acquirer > l(lockable_int); * int& i = access_acquiree(l); * i = 42; * } * @endcode */ template class lock_acquirer: // derive from lock_acquirer for the locked type (which is lockable::acquired_type); public lock_acquirer< I_policy, // if the lockable is const ... typename boost::mpl::eval_if< std::tr1::is_const, // ... then transfer constness to the type to protect (constness for lockables and the locked type is transitive) std::tr1::add_const, // ... otherwise keep it as specified boost::mpl::identity >::type, T_mutex // let compiler deduce whether acquired_type is again a lockable /*, std::tr1::false_type*/ > { typedef lock_acquirer< I_policy, typename boost::mpl::eval_if< std::tr1::is_const, std::tr1::add_const, boost::mpl::identity >::type, T_mutex /*, std::tr1::false_type*/ > parent_type; typedef T_type lockable_type; public: /** @short Constructs a lock_acquirer from a lockable. * @note Acquires the lock immediately, unlocks when it goes out of scope */ explicit lock_acquirer(lockable_type& _a_lockable): parent_type(_a_lockable.access_volatile(), _a_lockable.mutex()) {} /** @short Constructs a lock_acquirer from a volatile type to protect, a lock and * an additional argument forwarded to the lock constructor. * @note Acquires the lock immediately, unlocks when it goes out of scope */ template lock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1): parent_type(_a_lockable.access_volatile(), _a_lockable.mutex(), lockfwd_arg1) {} }; /** @short writelock_acquirer specialization for lockable's. */ template class writelock_acquirer: public lock_acquirer { typedef lock_acquirer parent_type; typedef T_type lockable_type; public: /** @short Constructs a lock_acquirer from a lockable. * @note Acquires the lock immediately, unlocks when it goes out of scope */ explicit writelock_acquirer(lockable_type& _a_lockable): parent_type(_a_lockable) {} /** @short Constructs a lock_acquirer from a volatile type to protect, a lock and * an additional argument forwarded to the lock constructor. * @note Acquires the lock immediately, unlocks when it goes out of scope */ template writelock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1): parent_type(_a_lockable, lockfwd_arg1) {} }; /** @short readlock_acquirer specialization for lockable's. */ template class readlock_acquirer: public lock_acquirer { typedef lock_acquirer parent_type; typedef T_type lockable_type; public: /** @short Constructs a lock_acquirer from a lockable. * @note Acquires the lock immediately, unlocks when it goes out of scope */ explicit readlock_acquirer(lockable_type& _a_lockable): parent_type(_a_lockable) {} /** @short Constructs a lock_acquirer from a volatile type to protect, a lock and * an additional argument forwarded to the lock constructor. * @note Acquires the lock immediately, unlocks when it goes out of scope */ template readlock_acquirer(lockable_type& _a_lockable, T_lockfwd_arg1 lockfwd_arg1): parent_type(_a_lockable, lockfwd_arg1) {} }; // @addtogroup threadsafety /** @} */ } // namespace mbox #endif // end file guard sigx/sigx/request_f.h0000644000175000017500000001036011126512655016046 0ustar triendl.kjtriendl.kj// -*- c++ -*- /* Do not edit! -- generated file */ #ifndef _SIGXMACROS_REQUEST_F_H_ #define _SIGXMACROS_REQUEST_F_H_ /* * Copyright 2007 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include namespace sigx { /** @short Asynchronous request functor for a sigx::threadable. * * It saves you writing request methods that have to call a handler method * for the request through a tunnel,like: * * @code * class IPResolverThread: public sigx::threadable * { * public: * void resolve(in_addr_t nIP); * void stop_resolving(); * }; * * void IPResolverThread::resolve(in_addr_t nIP) * { * sigx::open_tunnel(sigc::mem_fun(this, &IPResolverThread::on_resolve))(nIP); * } * * void IPResolverThread::stop_resolving() * { * sigx::open_tunnel(sigc::mem_fun(this, &IPResolverThread::on_stop_resolving))(); * } * @endcode * * Instead,delegate it to the request functor: * * @code * class IPResolverThread: public sigx::threadable * { * public: * sigx::request_f resolve; * sigx::request_f<> stop_resolving; * }; * * IPResolverThread::IPResolverThread(): * resolve(sigc::mem_fun(this, &IPResolverThread::on_resolve)),* stop_resolving(sigc::mem_fun(this, &IPResolverThread::on_stop_resolving)) * {} * @endcode * * It is derived from %sigc::slot because a slot provides already all the * necessary functionalities: takes a functor and creates a untyped slot * representation,has function invokation operator (). * * @attention Do not specify a return type as the first template parameter. * As asynchronous tunnels actually do not have a return type,@e request_f * omits it,thus the return type is always `void". * * @note non-copyable,not constructible on the heap (with new) and can't be * pointer aliased (with operator &) to ensure that it is de-facto bound to * a wrapping object. * * @ingroup signals */ template class request_f: noncopyable, nonheapallocatable, nonpointeraliasing, protected sigc::slot { public: typedef sigc::slot parent_type; // allow function operator to be used using parent_type::operator (); /** @short Constructs the request functor. * * @note The passed in functor must not be a sigc::slot and must not be * a tunnel functor. * The passed in functor gets tunneled automatically. * * @param _A_func A dispatchable functor,i.e. a functor on a dispatchable's * method or one explicitly created with dispatch_with(). */ template explicit request_f(const T_functor& _A_func): parent_type(tunnel_functor(_A_func)) { // passed in functor must not be tunneled SIGX_STATIC_ASSERT((internal::is_functor_tunneled::value == false)); // passed in functor must not be a slot or adapt a slot; // we have to apply this restriction because slots might have bound // trackables that can cause non-threadsafe access to the passed in slot // which will live in the context of the server thread SIGX_STATIC_ASSERT((sigx::internal::is_or_adapts_slot::value == false)); } }; } // namespace sigx #endif /* _SIGXMACROS_REQUEST_F_H_ */ sigx/sigx/ref.h0000644000175000017500000000342511123532203014615 0ustar triendl.kjtriendl.kj#ifndef _SIGX_AUTO_REF_H_ #define _SIGX_AUTO_REF_H_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** @file Template function "ref" exactly the same as sigc::ref but * overloaded for types already being wrapped in a * sigc::reference_wrapper such that ref() returns a new * reference_wrapper for the type to be wrapped instead of * wrapping the reference_wrapper itself. */ #include namespace sigx { template sigc::reference_wrapper ref(T_type& v) { return sigc::reference_wrapper(v); } template sigc::const_reference_wrapper ref(const T_type& v) { return sigc::const_reference_wrapper(v); } template sigc::reference_wrapper ref(const sigc::reference_wrapper& v) { return sigc::reference_wrapper(v); } template sigc::const_reference_wrapper ref(const sigc::const_reference_wrapper& v) { return sigc::const_reference_wrapper(v); } } // namespace sigx #endif // file guard sigx/sigx/static_assert.h0000644000175000017500000000307311123532203016710 0ustar triendl.kjtriendl.kj#ifndef _SIGX_STATIC_ASSERT_HPP_ #define _SIGX_STATIC_ASSERT_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** @file Simplified version of boost's static assert. * Can only be used at function scope. * @todo To be removed if C++09 is out (has a static_assert) */ namespace sigx { // HP aCC cannot deal with missing names for template value parameters template struct static_assert; template<> struct static_assert {}; // Not used; boost does many workarounds for different compilers to allow // using a static assertion in namespace, template and class scope #if 0 // HP aCC cannot deal with missing names for template value parameters template struct static_assert_test {}; #endif } // namespace sigx #define SIGX_STATIC_ASSERT( expr ) \ sizeof(::sigx::static_assert< (bool)( expr ) >) #endif // end file guard sigx/sigx/nonheapallocatable.h0000644000175000017500000000250311123532203017651 0ustar triendl.kjtriendl.kj#ifndef _SIGX_NONHEAPALLOCATABLE_HPP_ #define _SIGX_NONHEAPALLOCATABLE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short Private operator new and delete ensure derived classes cannot be * created with new on the heap. * @note Intended use as baseclass only. * @author klaus triendl */ class SIGX_API nonheapallocatable { protected: nonheapallocatable() {} ~nonheapallocatable() {} private: void* operator new(std::size_t); void operator delete(void*); }; } // namespace sigx #endif // #ifndef _SIGX_NONHEAPALLOCATABLE_HPP_ sigx/sigx/signal_source_base.h0000644000175000017500000000312711123532203017667 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_SOURCE_BASE_HPP_ #define _SIGX_SIGNAL_SOURCE_BASE_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short Represents a source for any type of signal. * * Signal sources are proxies for a concrete signal and offer * different ways of accessing a signal: * - from thread private data * - through an object's method * - through a functor */ class signal_source_base: public operator_new { public: /// An untyped function pointer typedef void (*hook)(); protected: hook m_getter; signal_source_base(hook _A_getter): m_getter(_A_getter) {} public: virtual ~signal_source_base() { m_getter = 0; } hook getter() const { return m_getter; } }; typedef signal_source_base* signal_source_ptr; } // namespace sigx #endif // _SIGX_SIGNAL_SOURCE_BASE_HPP_ sigx/sigx/lockable.h0000644000175000017500000002272711123644170015632 0ustar triendl.kjtriendl.kj#ifndef _SIGX_LOCKABLE_H_ #define _SIGX_LOCKABLE_H_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded * Programmer's Best Friend": * http://www.ddj.com/dept/cpp/184403766 */ #include #include #include #include #include namespace sigx { /** @addtogroup threadsafety * @{ */ /** @short The base for all lockables, template specialized for a specific * lock, e.g. a boost::mutex. * * Lockables are wrapper objects pairing a certain type together with a mutex type. * Mutex objects of type T_mutex must be default constructible. * */ template struct lockable_base: noncopyable { typedef T_mutex mutex_type; mutex_type& mutex() const throw() { return m_mutex; } protected: lockable_base(): m_mutex() {} /** @note mutable in case that lockable_base is const. */ mutable mutex_type m_mutex; }; /** @short Makes @e T_type %lockable. * * The "safe" in safe_lockable means that access to the mutex and the locked type is denied, they are only accessible through a lock_acquirer. * * The following template arguments are used: * - @e T_type The type to be protected, e.g. an int * - @e T_mutex The mutex type to protect @e T_type, e.g. a boost::mutex * * @code * typedef lockable mutex_lockable_int; * @endcode * * @note lockables are inseparably tied together and constness for lockables and the locked type is transitive, i.e * no matter whether the type to protect (@e T_type) or the lockable itself is somewhere declared const you get only * const access to the variable to protect */ template struct safe_lockable: public lockable_base { // lock_acquirer can use interface methods template friend class lock_acquirer; typedef lockable_base parent_type; // acquired_type = type to protect, 1:1 from T_type typedef T_type acquired_type; // volatile_type = make T_type volatile, even if T_type is a reference // volatile T_type or volatile T_type& typedef typename volatile_trait::add volatile_type; // reference_type = reference to volatile-stripped T_type // T_type& typedef typename std::tr1::add_reference::remove>::type reference_type; // volatile_reference_type = reference to volatile T_type, even if T_type is a reference // volatile T_type& typedef typename std::tr1::add_reference::type volatile_reference_type; // reference_type = reference to volatile-stripped T_type, even if T_type is a reference // const T_type& typedef typename std::tr1::add_reference::add>::type const_reference_type; // cv_reference_type = reference to cv-qualified T_type, even if T_type is a reference // const volatile T_type& typedef typename std::tr1::add_reference::add>::type cv_reference_type; // apply const qualifier and reference to toplevel type, unchanged if toplevel type is a reference typedef typename std::tr1::add_reference::type>::type toplevel_const_reference_type; /** @short Default constructor. * * @e T_type is initialized with its default ctor or its default value */ safe_lockable(): parent_type(), m_obj() {} /** @short Constructs a lockable initializing @e T_type with @e _a_value */ safe_lockable(toplevel_const_reference_type _a_value): parent_type(), m_obj(_a_value) {} protected: /** @return reference to volatile @e T_type */ volatile_reference_type access_volatile() throw() { return m_obj; } /** @return reference to non-volatile @e T_type */ reference_type access_nonvolatile() throw() { // volatile_cast m_obj return const_cast(m_obj); } /** @return reference to volatile @e T_type */ cv_reference_type access_volatile() const throw() { return m_obj; } /** @return reference to non-volatile @e T_type */ const_reference_type access_nonvolatile() const throw() { // volatile_cast m_obj return const_cast(m_obj); } private: /** @short store volatile @e T_type */ volatile_type m_obj; }; /** @short Refinement of safe_lockable, open access to mutex and locked type. */ template struct lockable: public safe_lockable { typedef safe_lockable parent_type; typedef typename parent_type::toplevel_const_reference_type toplevel_const_reference_type; public: /** @short Default constructor. * * @e T_type is initialized with its default ctor or its default value */ lockable(): parent_type() {} /** @short Constructs a lockable initializing @e T_type with @e _a_value */ lockable(toplevel_const_reference_type _a_value): parent_type(_a_value) {} // make safe_lockable's interface publicly available using parent_type::access_volatile; using parent_type::access_nonvolatile; }; #if 0 // specializations for pointers /** @short Makes a void pointer %lockable. * * The following template arguments are used: * - @e T_mutex The lock to protect @e void*, e.g. a boost::mutex * * @code * typedef lockable mutex_lockable_void_ptr; * @endcode */ template struct lockable: public lockable_base { typedef void* acquired_type; typedef T_mutex mutex_type; typedef lockable_base parent_type; typedef lockable type; typedef typename volatile_trait::add volatile_type; typedef typename std::tr1::add_reference::remove>::type reference_type; typedef typename std::tr1::add_reference::add>::type volatile_reference_type; typedef typename std::tr1::add_reference::type>::type take_type; /** @short Default constructor. * * The void pointer is initialized with the provided pointer or to 0 */ lockable(take_type _a_value = 0): parent_type(), m_obj(_a_value) {} /** @return reference to volatile void* */ volatile_reference_type access_volatile() { return m_obj; } /** @return reference to volatile @e T_type */ reference_type access_nonvolatile() { // volatile_cast m_obj return const_cast(m_obj); } private: /** @short volatile void* */ volatile_type m_obj; }; /** @short Makes any type of pointer %lockable. * * The following template arguments are used: * - @e T_type The pointer type to be protected, e.g. an int* * - @e T_mutex The lock to protect @e T_type, e.g. a boost::mutex * * @code * typedef lockable mutex_lockable_int_ptr; * @endcode */ template struct lockable: public lockable { typedef lockable parent_type; typedef T_type* acquired_type; typedef lockable type; typedef typename volatile_trait::add volatile_type; typedef typename std::tr1::add_reference::remove>::type reference_type; typedef typename std::tr1::add_reference::add>::type volatile_reference_type; typedef typename std::tr1::add_reference::type>::type take_type; /** @short default ctor. * * @e T_type is initialized with the provided pointer or to 0 */ lockable(take_type _a_value = 0): parent_type((void*&) _a_value) {} /** @return reference to volatile @e T_type problem by now: void* volatile p = 0; const int* volatile& p1 = reinterpret_cast(p); */ volatile_reference_type access_volatile() { return (volatile_reference_type) parent_type::access_volatile(); } /** @return reference to volatile @e T_type */ reference_type access_acquiree() { return (reference_type) parent_type::access_acquiree(); } }; #endif // @addtogroup threadsafety /** @} */ } // namespace sigx #endif // end file guard sigx/sigx/const_trait.h0000644000175000017500000000635411123532203016376 0ustar triendl.kjtriendl.kj#ifndef _SIGX_CONST_TRAIT_HPP_ #define _SIGX_CONST_TRAIT_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded * Programmer's Best Friend": * http://www.ddj.com/dept/cpp/184403766 */ namespace sigx { /** @addtogroup threadsafety * @{ */ /** @short Traits for adding/removing the const qualifier from a type */ template struct const_trait { typedef const T_type add; typedef T_type remove; }; /** @short Specialization for const types */ template struct const_trait { typedef const T_type add; typedef T_type remove; }; /** @short Specialization for references to non-const types. * * Specializations for references do not consider a reference as a "top level" * type qualifer unlike pointers; therefore, they add or remove the * volatileness to/from the referenced type: * const_trait::add -> const int& * const_trait::remove -> int& * const_trait::add -> const int& * const_trait::remove -> int& * * ( * a different placing of the qualifier, same type: * const_trait::add -> int const& * const_trait::remove -> int& * const_trait::add -> int const& * const_trait::remove -> int& * ) * * whereas pointers themselves are treated like "top level" type qualifiers. * Hence, they add or remove the volatileness from the pointer type qualifier: * const_trait::add -> const int* * const_trait::remove -> int* * const_trait::add -> const int* * const_trait::remove -> int* * const_trait::add -> int* const * const_trait::remove -> int* * * ( * a different placing of the qualifier, same type: * const_trait::add -> int const* * const_trait::remove -> int* * const_trait::add -> int const* * const_trait::remove -> int* * const_trait::add -> int* const * const_trait::remove -> int* * ) * * This is a major difference to boost::type_traits that consider a reference * as a top level type qualifier */ template struct const_trait { typedef const T_type& add; typedef T_type& remove; }; /** @short Specialization for references to const types */ template struct const_trait { typedef const T_type& add; typedef T_type& remove; }; // @addtogroup threadsafety /** @} */ } // namespace sigx #endif // end file guard sigx/sigx/internal_types.h0000644000175000017500000002607511126512654017122 0ustar triendl.kjtriendl.kj// -*- c++ -*- /* Do not edit! -- generated file */ #ifndef _SIGXMACROS_INTERNAL_TYPES_H_ #define _SIGXMACROS_INTERNAL_TYPES_H_ /* * Copyright 2007 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include // sigc::is_base_and_derived #include // sigc::nil #include // sigc::adaptor_base #include // sigc::adaptor_functor #include // sigc::bind_functor #include // sigc::hide_functor #include // sigc::slot_base #include #include #include // functor attaching a shared_dispatchable to another functor by binding // the shared_dispatchable and hiding it #define SIGX_DISPATCH_WITH_FUNCTOR(T_functor)\ sigc::bind_functor<-1, sigc::hide_functor<-1, T_functor>, shared_dispatchable> namespace sigx { namespace internal { /** @short counts the provided template arguments. There are specializations * for 1 to (7-1) template arguments that are not sigc::nil */ template struct count_arguments { static const int value = 7; }; template <> struct count_arguments<> { static const int value = 0; }; template struct count_arguments { static const int value = 1; }; template struct count_arguments { static const int value = 2; }; template struct count_arguments { static const int value = 3; }; template struct count_arguments { static const int value = 4; }; template struct count_arguments { static const int value = 5; }; template struct count_arguments { static const int value = 6; }; /** @short finds out whether @e T_functor is tunneled, i.e. * whether the functor chain contains a functor derived from sigx::tunnel_base. * * To investigate the fact that there exists one functor derived from * sigx::tunnel_base, this template struct cascades down the functor chain. * e.g. bind_functor - tunnel_functor - member_functor * * The template argument @e T_functor is the functor type. * @e I_isadaptor indicates whether @e T_functor inherits from sigc::adaptor_base. * @e I_istunnel indicates whether @e T_functor inherits from sigx::tunnel_base. */ template::value, bool I_isadaptor = sigc::is_base_and_derived::value> struct is_functor_tunneled; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for tunneled adaptors. */ template struct is_functor_tunneled { static const bool value = true; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for tunneled arbitrary functors. */ template struct is_functor_tunneled { static const bool value = true; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for arbitrary functors, static and member * function pointers. */ template struct is_functor_tunneled { // no chance to investigate further, probably a static or member function // pointer static const bool value = false; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for adaptors */ template struct is_functor_tunneled { // investigate further by cascading the functor chain // functor must define adaptor_type; // T_functor is probably derived from sigc::adapts; defines // adaptor_type typedef typename T_functor::adaptor_type adaptor_type; static const bool value = is_functor_tunneled::value; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for sigc::adaptor_functors wrapping * static and arbitrary functors. * This specialization is needed because sigc::adaptor_functor does not define * its wrapped functor as adaptor_type */ template struct is_functor_tunneled, false, true> { static const bool value = is_functor_tunneled::value; }; /** @short finds out whether @e T_functor is tunneled, i.e. * whether the functor chain contains a functor derived from sigx::tunnel_base. * * To investigate the fact that there exists one functor derived from * sigx::tunnel_base, this template struct cascades down the functor chain. * e.g. bind_functor - tunnel_functor - member_functor * * The template argument @e T_functor is the functor type. * @e I_isadaptor indicates whether @e T_functor inherits from sigc::adaptor_base. * @e I_isslot indicates whether @e T_functor inherits from sigc::slot_base. */ template< typename T_functor, bool I_isslot = sigc::is_base_and_derived::value, bool I_isadaptor = sigc::is_base_and_derived::value> struct is_or_adapts_slot; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for tunneled adaptors. */ template struct is_or_adapts_slot { static const bool value = true; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for arbitrary functors, static and member * function pointers. */ template struct is_or_adapts_slot { // no chance to investigate further, probably a static or member function // pointer static const bool value = false; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for adaptors */ template struct is_or_adapts_slot { // investigate further by cascading the functor chain // functor must define adaptor_type; // T_functor is probably derived from sigc::adapts; defines // adaptor_type typedef typename T_functor::adaptor_type adaptor_type; static const bool value = is_or_adapts_slot::value; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for sigc::adaptor_functors wrapping * static and arbitrary functors. * This specialization is needed because sigc::adaptor_functor does not define * its wrapped functor as adaptor_type */ template struct is_or_adapts_slot, false, true> { static const bool value = is_or_adapts_slot::value; }; /** @short Used to find a dispatchable out of the functor/adaptor chain, * i.e. the dispatchable object of a mem_functor or the shared_dispatchable * stored by dispatch_with(). * * It additionally checks at compile time that T_functor is really a functor on a * dispatchable's method by accessing the member variable obj_ of mem_functors * and converting the object to a sigx::dispatchable; * hence, the compiler will issue error messages if it is not a mem_functor or the object * is not convertible to a sigx::dispatchable */ template::value> struct dispatchable_constraint; template struct dispatchable_constraint { static const dispatchable& find_dispatchable(typename sigc::type_trait::take _A_func) { // if the compiler reports an error there are only 2 possibilities: // 1) you connected a static function to a signal or opened a tunnel on a // static signal without specifying the dispatchable to operate on. // 2) you connected a member function to a signal or opened a tunnel on a // member function where the member function is not from a dispatchable // solution: call 'open_tunnel_with' or 'open_sync_tunnel_with' and specify the dispatachable! // access obj_ of the functor; // this issues a compile time error if _A_func is not a functor // on an object's member function (only sigc member functors have this) // obj_ is a (const_)limit_reference type; must call invoke() to // ensure that we get the bound member type instead of a sigc::trackable return _A_func.obj_.invoke(); } }; // walks down the adaptor chain template struct dispatchable_constraint { static const dispatchable& find_dispatchable(typename sigc::type_trait::take _A_func) { return is_adaptor_dispatchable(_A_func); } private: // takes T_functor and matches it again to find // special types and walk down the adaptor chain template static const dispatchable& is_adaptor_dispatchable(const sigc::adaptor_functor& _A_func) { return dispatchable_constraint::find_dispatchable(_A_func.functor_); } // match the sigx special dispatchable adaptor chain template static const dispatchable& is_adaptor_dispatchable(const SIGX_DISPATCH_WITH_FUNCTOR(T_adapted_functor)& _A_func) { // no need to proceed as we found out that the functor is dispatchable return _A_func.bound1_.visit(); } // match all other apaptors, must define adaptor_type template static const dispatchable& is_adaptor_dispatchable(const T_adapted_functor& _A_func) { // T_adapted_functor must define adaptor_type; typedef typename T_adapted_functor::adaptor_type adaptor_type; // _A_func.functor_ is always an adaptor_type return is_adaptor_dispatchable(_A_func.functor_); } }; } // namespace internal } // namespace sigx #endif /* _SIGXMACROS_INTERNAL_TYPES_H_ */ sigx/sigx/shared_dispatchable.h0000644000175000017500000000615211123532203020012 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SHARED_DISPATCHABLE_HPP_ #define _SIGX_SHARED_DISPATCHABLE_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include namespace sigx { /** @short thread safe dispatcher reference that can be passed around. * * A shared dispatchable holds either a copy of another dispatchable * or * the dispatcher itself is only accessible by constructing a * shared_dispatchable::DispatcherPtr. * * @note Multiple reads of the same object are threadsafe, multiple writes not: * @code * // threadsafe * shared_dispatchable::DispatcherPtr dispatcher(shareddisp); * * // not threadsafe * shareddisp = mydisp; * @endcode * * @ingroup Dispatching */ class SIGX_API shared_dispatchable: public dispatchable { friend struct DispatcherPtr; // must get the dispatcher ptr over dispatcher() for assertions friend class tunnel_validity_tracker; public: ///** @short behaves like a dispatcher pointer, ensures threadsafe access to the dispatcher reference. // * // * A DispatcherPtr is constructed from a dispatchable and references the // * dispatcher of the dispatchable. A read lock ensures threadsafe access to // * the reference (the owner thread sets a read/write lock when it sets // * the reference to 0). // * After you have constructed a DispatcherPtr, you *must* test for null. // */ //class DispatcherPtr //{ //public: // explicit DispatcherPtr(shared_dispatchable& _A_disp): // m_locker(*_A_disp.m_disp_ptr) // {} // // /** @short Returns a plain dispatcher* // */ // dispatcher_ptr operator ->() // { return access_acquiree(m_locker); } // operator bool() // { return access_acquiree(m_locker); } // bool operator !() // { return !access_acquiree(m_locker); } // bool operator !=(dispatcher_ptr other) // { return other != access_acquiree(m_locker); } // //private: // readlock_acquirer m_locker; //}; class DispatcherPtr; public: /** * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ shared_dispatchable(); /** @short Copy construct from any dispatchable. */ shared_dispatchable(const dispatchable& d) throw(); /** @short Assign from any dispatchable. */ shared_dispatchable& operator =(const dispatchable& d) throw(); }; } // namespace sigx #endif // end file guard sigx/sigx/bad_sync_call.h0000644000175000017500000000212711123532204016615 0ustar triendl.kjtriendl.kj#ifndef _SIGX_BAD_SYNC_CALL_HPP_ #define _SIGX_BAD_SYNC_CALL_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { class bad_sync_call: public std::exception { public: bad_sync_call(): std::exception() {} // virtuals from std::exception virtual const char* what() const throw(); }; } // namespace sigx #endif // end file guard sigx/sigx/tunnel_context_base.h0000644000175000017500000000545311123532202020106 0ustar triendl.kjtriendl.kj#ifndef _SIGX_TUNNEL_CONTEXT_BASE_HPP_ #define _SIGX_TUNNEL_CONTEXT_BASE_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include namespace sigx { /** @short the base class for all tunnel_context classes. * * A tunnel context represents the tunnel and all facilities involved: * the dispatcher, the message, the functor to invoke, whether the message * is dispatched asynchronously or synchronously. * * @ingroup Dispatching */ class SIGX_API tunnel_context_base: public operator_new { public: tunnel_context_base(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker, bool sync = false); virtual ~tunnel_context_base(); /** @short invokes the intended functor at the other end of the tunnel */ virtual void invoke() = 0; bool is_sync() const { return m_sync; } bool is_valid() const { return m_validity_tracker.is_valid(); } const void* creator_thread() const { return m_creator_thread; } protected: /** @short sends the tunnel context over the dispatcher. * @throw bad_dispatcher If dispatcher is invalid. */ void dispatch_me(); protected: tunnel_validity_tracker m_validity_tracker; shared_dispatchable m_disp; bool m_sync; const void* const m_creator_thread; }; /** @short Specialities for synchronous tunnel context. * @ingroup Dispatching */ class SIGX_API sync_tunnel_context_base: public tunnel_context_base { public: sync_tunnel_context_base(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker); protected: /** @short sends the tunnel context over the dispatcher. * * Locks until invoke() has completed. * * @return whether the tunnel context is dispatchable, i.e. the dispatcher * reference was still valid. * @throw bad_dispatcher If dispatcher is invalid. */ void dispatch_me(); protected: Glib::Cond m_cond; Glib::Mutex m_mutex; }; } // namespace sigx #endif // end file guard sigx/sigx/signal_source_func.h0000644000175000017500000000373311123532203017713 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_SOURCE_FUNC_HPP_ #define _SIGX_SIGNAL_SOURCE_FUNC_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include namespace sigx { /** @short signal source is a signal of type T_signal returned by a * functor. * * @note First I had the idea to use a slot to store the functor instead of * storing the functor itself. But a slot has one caveat: It expects * @e T_signal to be default constructable (T_signal()), * see sigc::slotN::operator (). Not all signals have a default constructor, * e.g. Glib signals like SignalIdle. */ template struct signal_source_func: public signal_source_base { typedef signal_source_func self_type; typedef typename sigc::functor_trait::functor_type functor_type; signal_source_func(const T_functor& _A_func): signal_source_base(reinterpret_cast(&self_type::get_signal)), m_func(_A_func) {} static T_signal get_signal(signal_source_ptr base) { self_type* const this_ = static_cast(base); return this_->m_func(); } functor_type m_func; }; } // namespace sigx #endif // _SIGX_SIGNAL_SOURCE_FUNC_HPP_ sigx/sigx/signal_source_threadprivate.h0000644000175000017500000000356211123532203021622 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_SOURCE_THREADPRIVATE_HPP_ #define _SIGX_SIGNAL_SOURCE_THREADPRIVATE_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // Glib::Private #include #include namespace sigx { /** @short signal source is a signal of type T_signal from a thread * private data object's member. */ template struct signal_source_threadprivate: public signal_source_base { typedef signal_source_threadprivate self_type; typedef T_signal T_threadpriv::*typed_signal_ptr; signal_source_threadprivate(Glib::Private& _A_priv, typed_signal_ptr _A_sig): signal_source_base(reinterpret_cast(&self_type::get_signal)), m_threadpriv(_A_priv), m_sig(_A_sig) {} static T_signal get_signal(signal_source_ptr base) { self_type* this_ = static_cast(base); const typed_signal_ptr sig = this_->m_sig; return this_->m_threadpriv.get()->*sig; } Glib::Private& m_threadpriv; typed_signal_ptr m_sig; }; } // namespace sigx #endif // _SIGX_SIGNAL_SOURCE_THREADPRIVATE_HPP_ sigx/sigx/signal_traits.h0000644000175000017500000000762411123532203016711 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_TYPE_TRAIT_HPP_ #define _SIGX_SIGNAL_TYPE_TRAIT_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { namespace internal { struct derivation_helper { typedef char sm; struct middle { char memory[32]; }; struct big { char memory[64]; }; enum Type { NOBASE = sizeof(sm), BASE1 = sizeof(middle), BASE2 = sizeof(big) }; }; /** @short Compile-time determination of base-class relationship in C++. * * Tests from what base class @e T_derived derives. T_derived must not derive * from both classes. * @note inspired by sigc::is_base_and_derived * @author klaus triendl * @date 2006-09-11, kj created */ template struct is_derived_from { private: #ifndef SIGC_SELF_REFERENCE_IN_MEMBER_INITIALIZATION //Certain compilers, notably GCC 3.2, require these functions to be inside an inner class. struct internal_class { static derivation_helper::sm is_base_class_(...); static derivation_helper::middle is_base_class_(typename sigc::type_trait::pointer); static derivation_helper::big is_base_class_(typename sigc::type_trait::pointer); }; public: static const int value = sizeof(internal_class::is_base_class_(reinterpret_cast::pointer>(0))); #else //SIGC_SELF_REFERENCE_IN_MEMBER_INITIALIZATION //The AIX xlC compiler does not like these 2 functions being in the inner class. //It says "The incomplete type "test" must not be used as a qualifier. //It does not seem necessary anyway. murrayc. static derivation_helper::sm is_base_class_(...); static derivation_helper::middle is_base_class_(typename sigc::type_trait::pointer); static derivation_helper::big is_base_class_(typename sigc::type_trait::pointer); public: static const int value = sizeof(is_base_class_(reinterpret_cast::pointer>(0))); #endif //SIGC_SELF_REFERENCE_IN_MEMBER_INITIALIZATION void avoid_gcc3_warning_(); //Not implemented. g++ 3.3.5 (but not 3.3.4, and not 3.4) warn that there are no public methods, even though there is a public variable. }; enum signal_group { SIGGROUP_IRRELEVANT, SIGGROUP_SIGC, SIGGROUP_GLIB_PROXY }; /** @short Trait to group signal types. * @note We could use specializations for all signals like * count_signal_arguments does. But by finding the baseclass we can reduce * the specializations. */ template::value> struct signal_type_trait { static const signal_group type = SIGGROUP_IRRELEVANT; }; /** @short Specialization for sigc::signal_base derived signals */ template struct signal_type_trait { static const signal_group type = SIGGROUP_SIGC; }; /** @short Specialization for Glib::SignalProxyNormal derived signals */ template struct signal_type_trait { static const signal_group type = SIGGROUP_GLIB_PROXY; }; } // namespace internal } // namespace sigx #endif // end file guard sigx/sigx/connection_handler.h0000644000175000017500000002006211145620724017703 0ustar triendl.kjtriendl.kj#ifndef _SIGX_CONNECTION_HANDLER_HPP_ #define _SIGX_CONNECTION_HANDLER_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // std::tr1::shared_ptr #include #include #include // message macros #include // Glib::StaticPrivate #include #include #include #include #include #include #include namespace sigx { /** @short Stores connections of any client thread to a server thread's signal and destroys them along with the * thread's lifetime. * @note A static class only. */ class SIGX_API connection_handler: noninstantiatable { public: /** @short Destroys a sigc::connection in the context of the server thread. * * Called when the last connection sharing a sigc::connection * goes out of scope and tunnels a message. * * @note message handler for sigx::connection_wrapper::~connection_wrapper(). */ static void destroy(const sigc_connection_ptr* handle); /** @short Stores a sigc::connection in the context of the server thread. * @param _A_refconn Shared connection pointer * @param c The connection */ static void store( const std::tr1::shared_ptr& _A_refconn, const sigc::connection& c); protected: /** A wrapper for a container of sigc::connectionS. * This wrapper is necessary because the destructor ensures * disconnecting the connections when the owner thread * finishes. * Disconnecting the connections explicitly is only necessary if the signals * don't live in the server thread's local storage but in the thread managed * dispatchable which is a wrapper object surviving the thread itself. */ struct connections_container_wrapper { /** @short a map of connections living in the context of the * owner thread. * @note We must use a shared_ptr because auto_ptr doesn't meet the copy-constructible requirement */ typedef std::map > container_type; container_type m_connections; ~connections_container_wrapper(); }; static Glib::StaticPrivate thread_specific_connections; }; template class typed_connection_handler; template class typed_connection_handler: noninstantiatable { public: typedef T_signal signal_type; typedef typename signal_type::slot_type slot_type; /** @param _A_refconnptr A prepared connection pointer * @param psigsource Shared signal source * @note Executed by the server thread only. */ static void connect(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); const fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect(_A_slot); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } }; /** @short Specialization for a Glib::SignalProxyN */ template class typed_connection_handler: noninstantiatable { public: typedef T_signal signal_type; typedef typename signal_type::SlotType slot_type; typedef typename signal_type::VoidSlotType void_slot_type; /** @note Executed by the server thread only. */ static void connect(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, bool after) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); const fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect(_A_slot, after); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } /** @note Executed by the server thread only. */ static void connect_notify(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const void_slot_type& _A_slot, bool after) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); const fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect_notify(_A_slot, after); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } }; /** @short Specialization for a Glib::SignalIdle */ template<> class SIGX_API typed_connection_handler: noninstantiatable { public: typedef Glib::SignalIdle signal_type; typedef sigc::slot slot_type; /** @note Executed by the server thread only. */ static void connect(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, int priority); }; /** @short Specialization for a Glib::SignalTimeout */ template<> class SIGX_API typed_connection_handler: noninstantiatable { public: typedef Glib::SignalTimeout signal_type; typedef sigc::slot slot_type; /** @note Executed by the server thread only. */ static void connect(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, unsigned int interval, int priority); }; /** @short Specialization for a Glib::SignalIO */ template<> class SIGX_API typed_connection_handler: noninstantiatable { public: typedef Glib::SignalIO signal_type; typedef sigc::slot slot_type; /** @note Executed by the server thread only. */ static void connect(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, int fd, Glib::IOCondition condition, int priority); }; /** @short Specialization for a Glib::SignalChildWatch */ template<> class SIGX_API typed_connection_handler: noninstantiatable { public: typedef Glib::SignalChildWatch signal_type; typedef sigc::slot slot_type; /** @note Executed by the server thread only. */ static void connect(const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, GPid pid, int priority); }; } // namespace sigx #endif // end file guard sigx/sigx/nonpointeraliasing.h0000644000175000017500000000264311123532203017745 0ustar triendl.kjtriendl.kj#ifndef _SIGX_NONPOINTERALIASING_HPP_ #define _SIGX_NONPOINTERALIASING_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { /** @short Private address operator (operator &) ensures that the address of * derived objects can't be taken. * @note Intended use as a baseclass only. * @author klaus triendl */ class SIGX_API nonpointeraliasing { protected: nonpointeraliasing() {} ~nonpointeraliasing() {} private: nonpointeraliasing* operator &(); nonpointeraliasing* operator &() const; nonpointeraliasing* operator &() volatile; nonpointeraliasing* operator &() const volatile; }; } // namespace sigx #endif // #ifndef _SIGX_NONPOINTERALIASING_HPP_ sigx/sigx/locking_dispatcher_ptr.h0000644000175000017500000000371611123532203020565 0ustar triendl.kjtriendl.kj#ifndef _SIGX_LOCKING_DISPATCHER_PTR_H_ #define _SIGX_LOCKING_DISPATCHER_PTR_H_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include namespace sigx { /** @short behaves like a dispatcher pointer, ensures threadsafe access to the dispatcher reference. * * A DispatcherPtr is constructed from a dispatchable and references the * dispatcher of the dispatchable. A read lock ensures threadsafe access to * the reference (the owner thread sets a read/write lock when it sets * the reference to 0). * After you have constructed a DispatcherPtr, you *must* test for null. */ class shared_dispatchable::DispatcherPtr { public: explicit DispatcherPtr(shared_dispatchable& _A_disp): m_locker(*_A_disp.m_disp_ptr) {} /** @short Returns a plain dispatcher* */ dispatcher_ptr operator ->() { return access_acquiree(m_locker); } operator bool() { return access_acquiree(m_locker); } bool operator !() { return !access_acquiree(m_locker); } bool operator !=(dispatcher_ptr other) { return other != access_acquiree(m_locker); } private: readlock_acquirer m_locker; }; } // namespace sigx #endif // file guard sigx/sigx/auto_dispatchable.h0000644000175000017500000000320311123532204017507 0ustar triendl.kjtriendl.kj#ifndef _SIGX_AUTO_DISPATCHABLE_HPP_ #define _SIGX_AUTO_DISPATCHABLE_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short A dispatchable managing the pointer to the dispatcher. * * the dispatcher reference is initialized with a dispatcher automatically in the ctor, * thus, an auto-dispatchable is especially useful for classes running in the * default glib main context. if you need manual control over which dispatcher your * derived class should use (like for threads), then use the manual_dispatchable * @note non-copyable. If you want to pass around the dispatchable then use * a sigx::shared_dispatchable instead * * @ingroup Dispatching */ class SIGX_API auto_dispatchable: public dispatchable { protected: auto_dispatchable(dispatcher_ptr disp); ~auto_dispatchable(); }; } // namespace sigx #endif // end file guard sigx/sigx/connection_wrapper.h0000644000175000017500000000651511155006445017754 0ustar triendl.kjtriendl.kj#ifndef _SIGX_CONNECTION_HPP_ #define _SIGX_CONNECTION_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // std::tr1::shared_ptr #include #include #include namespace sigx { /** @short A threadsafe representation of a sigc::connection. * @ingroup signals */ class SIGX_API connection_wrapper { private: // volatile because the value should be always read from the variable itself; // this is necessary because the sigc::connection* is "late bound", i.e. // it is set by the server thread after an asynchronous "connect" message. // When the next tunnel functor is created (let's say with disconnect()) // then m_sigc_conn is dereferenced (*m_sigc_conn) and the actual pointer // value (the sigc::connection*) is treated volatile at the other side of // the tunnel (at the server thread's side). // It is const because the connection_wrapper object doesn't modify the pointer. typedef std::tr1::shared_ptr shared_sigc_conn_ptr; public: /** @short Construct an empty connection_wrapper. */ connection_wrapper(); /** @short Construct from a dispatchable and a late bound pointer to the server thread's * sigc::connection. */ connection_wrapper(const shared_dispatchable& _A_disp, const shared_sigc_conn_ptr& _A_conn); /** @short Copy construct from another connection_wrapper */ connection_wrapper(const connection_wrapper& other) throw(); /** * @note destroying is asynchronous */ ~connection_wrapper() throw(); /** @note nonvolatile, may only be executed by a single thread. */ connection_wrapper& operator =(const connection_wrapper& other); public: /** * @note synchronous */ bool empty() const; /** * @note synchronous */ bool connected() const; /** * @note synchronous */ bool blocked() const; /** * @note synchronous */ bool block(bool should_block = true); /** * @note synchronous */ bool unblock(); /** * @note synchronous */ void disconnect(); /** * @note non-const because sigc::connection::operator bool is non-const * @note synchronous */ operator bool(); protected: void destroy_self(); private: /// the sigc::connection living in the context of the server thread shared_sigc_conn_ptr m_sigc_conn; /// the dispatchable over which we are sending the messages to the /// server thread's sigc::connection shared_dispatchable m_shared_disp; /// how many times the sigc::connection is shared by multiple /// connection_wrapper objects volatile int* m_sigcconn_refcount; }; } // namespace sigx #endif // end file guard sigx/sigx/bad_dispatcher.h0000644000175000017500000000263411123532204016777 0ustar triendl.kjtriendl.kj#ifndef _SIGX_BAD_DISPATCHER_HPP_ #define _SIGX_BAD_DISPATCHER_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { class bad_dispatcher: public std::exception//, public operator_new { public: bad_dispatcher(): std::exception() {} // virtuals from std::exception virtual const char* what() const throw(); }; /** @short Catcher for a sigc::exception_catch_functor ignoring exceptions * of type sigx::bad_dispatcher. */ template struct bad_dispatcher_catcher { T_return operator ()() const { try { throw; } catch (const ::sigx::bad_dispatcher&) {} return T_return(); } }; } // namespace sigx #endif // end file guard sigx/sigx/signal_source_obj_mem.h0000644000175000017500000000634711123532203020374 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_SOURCE_OBJ_MEM_HPP_ #define _SIGX_SIGNAL_SOURCE_OBJ_MEM_HPP_ /* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include namespace sigx { /** @short signal source is a object's member of type T_signal. */ template struct signal_source_obj_mem: public signal_source_base { typedef signal_source_obj_mem self_type; typedef T_signal T_obj::*typed_signal_ptr; signal_source_obj_mem(T_obj* _A_obj, typed_signal_ptr _A_sig): signal_source_base(reinterpret_cast(&self_type::get_signal)), m_obj(_A_obj), m_sig(_A_sig) {} static T_signal get_signal(signal_source_ptr base) { self_type* const this_ = static_cast(base); const typed_signal_ptr sig = this_->m_sig; return this_->m_obj->*sig; } T_obj* m_obj; typed_signal_ptr m_sig; }; /** @short signal source is a object's member of type T_signal. * Object instance is late bound. */ template struct signal_source_pobj_mem: public signal_source_base { typedef signal_source_pobj_mem self_type; typedef T_signal T_obj::*typed_signal_ptr; signal_source_pobj_mem(T_obj* const& _A_obj, typed_signal_ptr _A_sig): signal_source_base(reinterpret_cast(&self_type::get_signal)), m_obj(_A_obj), m_sig(_A_sig) {} static T_signal get_signal(signal_source_ptr base) { self_type* const this_ = static_cast(base); const typed_signal_ptr sig = this_->m_sig; return this_->m_obj->*sig; } T_obj* const& m_obj; typed_signal_ptr m_sig; }; /** @short signal source is a object's member function returning a signal of * type T_signal. * Object instance is late bound. */ template struct signal_source_pobj_mem_fun: public signal_source_base { typedef signal_source_pobj_mem_fun self_type; typedef typename sigc::functor_trait::functor_type functor_type; signal_source_pobj_mem_fun(T_obj* const& _A_obj, const T_functor& _A_mem_func): signal_source_base(reinterpret_cast(&self_type::get_signal)), m_obj(_A_obj), m_mem_func(_A_mem_func) {} static T_signal get_signal(signal_source_ptr base) { self_type* this_ = static_cast(base); return this_->m_mem_func(this_->m_obj); } T_obj* const& m_obj; functor_type m_mem_func; }; } // namespace sigx #endif // _SIGX_SIGNAL_SOURCE_OBJ_MEM_HPP_ sigx/sigx/manual_dispatchable.h0000644000175000017500000000303111123532203020012 0ustar triendl.kjtriendl.kj#ifndef _SIGX_THREADMANAGED_DISPATCHABLE_HPP_ #define _SIGX_THREADMANAGED_DISPATCHABLE_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include namespace sigx { /** @short A dispatchable whose dispatcher pointer is managed by derived classes. * * The dispatcher must be set manually with set_dispatcher() * in the context of the running thread, the best point is after creating the * main context for the thread. * * @note non-copyable. If you want to pass around the dispatchable then use * a sigx::shared_dispatchable instead */ class SIGX_API manual_dispatchable: public dispatchable { public: manual_dispatchable(); virtual ~manual_dispatchable(); protected: void set_dispatcher(dispatcher_ptr disp); }; } // namespace sigx #endif // file guard sigx/sigx/signal_wrapper_base.h0000644000175000017500000001320211127240120020040 0ustar triendl.kjtriendl.kj#ifndef _SIGX_SIGNAL_BASE_HPP_ #define _SIGX_SIGNAL_BASE_HPP_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include // std::pair #include #include #include #include #include #include #include namespace sigx { /** @short The base for a sigx::signal_wrapper. * * It holds a shared_dispatchable and a shared signal source. * * @ingroup signals */ class SIGX_API signal_wrapper_base: nonheapallocatable { protected: /** * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper_base(); // non-virtual by design ~signal_wrapper_base() throw(); signal_wrapper_base(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(); // implicit copy ctor is fine // implicit assignment operator is fine /** @short Prepare a shared sigc::connection pointer and a connection_wrapper. * * The sigc::connection itself will be created in the context of the server thread */ std::pair > prepare_connection(const tunnel_base& _A_tunnel) const; /** @short Call _A_func_conn_handler in the context of the server thread, _A_func_conn_handler * resolves to typed_connection_handler<>::connect[_notify] connecting _A_func to the server * thread's signal */ template connection_wrapper connect(const T_functor& _A_func, const T_functor_conn_handler& _A_func_conn_handler) const; protected: /// The server thread's shared dispatchable to operate on for making connections or /// emitting the signal shared_dispatchable m_disp; /// The source for the server thread's signal std::tr1::shared_ptr m_sigsource; }; template connection_wrapper signal_wrapper_base::connect(const T_functor& _A_func, const T_functor_conn_handler& _A_func_conn_handler) const { typedef internal::auto_tunneler auto_tunneler_t; // passed in functor must not be a slot or adapt a slot; // we have to apply this restriction because slots might have bound // trackables that can cause non-threadsafe access to the passed in slot // which will live in the context of the server thread SIGX_STATIC_ASSERT((sigx::internal::is_or_adapts_slot::value == false)); // toplevel functor must be a tunnel functor SIGX_STATIC_ASSERT((sigc::is_base_and_derived::value == true)); typename auto_tunneler_t::functor_type functor2connect = auto_tunneler_t::auto_open_tunnel(_A_func); // the validity of tunnel functors doesn't get tracked by the sigc++ default visit_each mechanism, // we activate sigx' own validity tracking, which is threadsafe functor2connect.activate_validity_tracking(); const std::pair >& ret = signal_wrapper_base::prepare_connection(functor2connect); try { // now send a message to the server thread (holding the signal the client thread wants // to connect to); // the message gets handled by a special function handling the connection open_tunnel_with( _A_func_conn_handler, m_disp ) // transfer: // - the prepared connection pointer // - the signal source // - the functor to connect // // The functor to connect is the tunnel functor wrapped in an exception catcher // that catches a bad_dispatcher error. // This is necessary because the dispatcher of the tunnel functor (that is // probably the dispatcher running in the context of the calling thread) // could go out of scope (e.g. because the calling thread finishes), but // the tunnel functor is still connected to the server thread's signal. // Before the server thread gets the disconnect message (which is // triggered by the dispatcher or by trackable objects of the calling // thread going out of scope) it might emit the signal // on this tunnel functor and gets a bad_dispatcher error thrown. // Because the programmer can't really influence this situation, sigx // catches the exception. ( ret.second, m_sigsource, sigc::exception_catch(functor2connect, // use a catcher here because the signal might get emitted // while the dispatcher the tunnel functor operates on dies // before the tunnel functor is disconnected from that signal // (btw: this is done internally by the validity trackable bad_dispatcher_catcher() ) ); } catch (...) { // message dispatching failed at the call site; // reset pointer to the sigc connection to make the connection invalid *ret.second = 0; throw; } return ret.first; } } // namespace sigx #endif // end file guard sigx/sigx/lockable_fwddecl.h0000644000175000017500000000350511123644471017317 0ustar triendl.kjtriendl.kj#ifndef _SIGX_LOCKABLE_FWDDECL_HPP_ #define _SIGX_LOCKABLE_FWDDECL_HPP_ /* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include namespace sigx { //enum locking_policy; enum locking_policy { readlock, writelock }; template struct choose_lock; template struct lockable_base; template struct lockable; template struct safe_lockable; template, T_type>::type> class lock_acquirer; template, T_type>::type> class writelock_acquirer; template, T_type>::type> class readlock_acquirer; } #endif // end file guard sigx/sigx/volatile_trait.h0000644000175000017500000000677411123532204017076 0ustar triendl.kjtriendl.kj#ifndef _SIGX_VOLATILE_TRAIT_H_ #define _SIGX_VOLATILE_TRAIT_H_ /* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ /* * Inspired by Andrei Alexandrescu's article "volatile - Multithreaded * Programmer's Best Friend": * http://www.ddj.com/dept/cpp/184403766 */ namespace sigx { /** @addtogroup threadsafety * @{ */ /** @short Traits for adding/removing the volatile qualifier from a type */ template struct volatile_trait { typedef volatile T_type add; typedef T_type remove; }; /** @short Specialization for volatile types */ template struct volatile_trait { typedef volatile T_type add; typedef T_type remove; }; /** @short Specialization for references to non-volatile types. * * Specializations for references do not consider a reference as a "top level" * type qualifer unlike pointers; therefore, they add or remove the * volatileness to/from the referenced type: * volatile_trait::add -> volatile int& * volatile_trait::remove -> int& * volatile_trait::add -> volatile int& * volatile_trait::remove -> int& * * ( * a different placing of the qualifier, same type: * volatile_trait::add -> int volatile& * volatile_trait::remove -> int& * volatile_trait::add -> int volatile& * volatile_trait::remove -> int& * ) * * whereas pointers themselves are treated like "top level" type qualifiers. * Hence, they add or remove the volatileness from the pointer type qualifier: * volatile_trait::add -> volatile int* * volatile_trait::remove -> int* * volatile_trait::add -> volatile int* * volatile_trait::remove -> int* * volatile_trait::add -> int* volatile * volatile_trait::remove -> int* * * ( * a different placing of the qualifier, same type: * volatile_trait::add -> int volatile* * volatile_trait::remove -> int* * volatile_trait::add -> int volatile* * volatile_trait::remove -> int* * volatile_trait::add -> int* volatile * volatile_trait::remove -> int* * ) * * This is a major difference to boost::type_traits that consider a reference * as a top level type qualifier */ template struct volatile_trait { typedef volatile T_type& add; typedef T_type& remove; }; /** @short Specialization for references to volatile types */ template struct volatile_trait { typedef volatile T_type& add; typedef T_type& remove; }; template T volatile_cast(T_src& tsrc) { return const_cast(tsrc); } // @addtogroup threadsafety /** @} */ } // namespace sigx #endif // end file guard sigx/tests/0000755000175000017500000000000011126513503014061 5ustar triendl.kjtriendl.kjsigx/tests/SConscript0000644000175000017500000000177111126513503016101 0ustar triendl.kjtriendl.kj# -*- python -*- Import('env') localenv = env.Clone() localenv.Prepend(CPPPATH = "#") localenv.Prepend(LIBPATH = localenv['BUILDDIR']) localenv.Append(LIBS = localenv['VERSIONED_NAME']) #localenv.Append(PKG_CONFIG_TOP_BUILD_DIR = "#"); #env.Append(CXXFLAGS = ['-g']) glibmm_env = localenv.Clone() gtkmm_env = localenv.Clone() glibmm_env.ParseConfig('pkg-config --cflags --libs glibmm-2.4 gthread-2.0') gtkmm_env.ParseConfig('pkg-config --cflags --libs gtkmm-2.4 gthread-2.0') test_signal_idle = glibmm_env.Program('test_signal_idle.cpp') test_validity_tracking = glibmm_env.Program('test_validity_tracking.cpp') test_sync_async_argument_passing = glibmm_env.Program('test_sync_async_argument_passing.cpp') test_connection_handling = glibmm_env.Program('test_connection_handling.cpp') test_button_click = gtkmm_env.Program('test_button_click.cpp') test_programs = [ test_signal_idle, test_button_click, test_validity_tracking, test_connection_handling, test_sync_async_argument_passing ] Return('test_programs') sigx/tests/test_validity_tracking.cpp0000644000175000017500000001125111124235413021332 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include using namespace std; // fwd decl class MainThread; class MyThread: public sigx::glib_threadable { public: MyThread(MainThread* mainthread); protected: // virtuals from sigx::threadable virtual void on_startup(); private: void on_ready(); void on_test(); private: MainThread* m_mainthread; // signal api public: // expose the idle signal sigx::signal_f signal_idle; }; class MainThread: public sigx::glib_auto_dispatchable { public: MainThread(); void run(); protected: void on_self_ready(); void on_mythread_idle(); void on_end_mainthread(); protected: Glib::RefPtr m_mainloop; sigc::signal m_test_signal; MyThread m_mythread; // threadsafe signal api public: // expose a test signal sigx::signal_f > signal_test; }; using namespace std; MyThread::MyThread(MainThread* mainthread): sigx::glib_threadable(), m_mainthread(mainthread), signal_idle(make_idle_signal_f()) {} //virtual void MyThread::on_startup() { maincontext()->signal_idle().connect( sigc::bind_return(sigc::mem_fun(this, &MyThread::on_ready), false) ); } void MyThread::on_ready() { m_mainthread->signal_test().connect( sigc::mem_fun(this, &MyThread::on_test) ); } void MyThread::on_test() { cout << "MyThread received test signal." << endl; } MainThread::MainThread(): sigx::glib_auto_dispatchable(), m_mainloop(), m_test_signal(), m_mythread(this), // thread safe signal api signal_test(*this, &MainThread::m_test_signal) {} void MainThread::run() { m_mainloop = Glib::MainLoop::create(); // one-shot idle handler Glib::signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &MainThread::on_self_ready), false ) ); m_mainloop->run(); } void MainThread::on_self_ready() { m_mythread.run(); // connect to the thread's idle signal m_mythread.signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &MainThread::on_mythread_idle), bool() ) ); } void MainThread::on_mythread_idle() { cout << "slots connected to the test signal: " << m_test_signal.size() << endl; m_test_signal.emit(); // end the thread, should disconnect its functors from the test signal m_mythread.finish(); // by this point mythread's functor is still connected but the "disconnect" // message is already queued in MainThread's dispatcher cout << "slots connected to the test signal after ending MyThread is still: " << m_test_signal.size() << endl; // there will be 2 messages many times: MyThread's emitted idle signal and MyThread's emitted disconnect message // to disconnect from MainThread's test signal cout << "messages in MainThread's dispatcher queue: " << dispatcher()->queued_contexts() << endl; // mythread's dispatcher died and mythread's functor is still connected but // that won't do any harm, because the bad_dispatcher exception is caught // when calling the tunnel on an invalid dispatcher when emitting a signal; // test the signal m_test_signal.emit(); // now, connect to the idle signal; // this gives MainThread's dispatcher the chance to execute the // disconnection of MyThread's functor before on_end_mainthread() is called Glib::signal_idle().connect( sigc::bind_return(sigc::mem_fun(this, &MainThread::on_end_mainthread), false) ); } void MainThread::on_end_mainthread() { // m_mythread should have disconnected its functors // at the time it finished cout << "slots connected to the test signal after ending MyThread: " << m_test_signal.size() << endl; // test the signal m_test_signal.emit(); m_mainloop->quit(); } int main() { Glib::thread_init(); MainThread app; app.run(); cout << "press ."; cin.get(); return 0; } sigx/tests/test_button_click.cpp0000644000175000017500000000652611124235142020313 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include // fwd decl class TheGUI; class TheThread: public sigx::glib_threadable { public: TheThread(TheGUI* thegui); protected: // virtuals from sigx::threadable virtual void on_startup(); void on_first_idle(); void on_button_clicked(); private: TheGUI* m_thegui; }; class TheGUI: public Gtk::Window, public sigx::glib_auto_dispatchable { public: TheGUI(); public: // expose Gtk::Button::signal_clicked of m_btn sigx::signal_f > signal_button_clicked; private: void on_first_idle(); void on_thethread_ready(); private: TheThread m_thethread; Gtk::Button* m_btn; }; #include TheThread::TheThread(TheGUI* thegui): m_thegui(thegui) {} //virtual void TheThread::on_startup() { // one-shot idle handler maincontext()->signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &TheThread::on_first_idle), false ) ); } void TheThread::on_first_idle() { std::cout << "TheTread connects to the button_clicked signal." << std::endl; // connect to TheGUI::signal_button_clicked m_thegui->signal_button_clicked().connect_notify( sigc::mem_fun(this, &TheThread::on_button_clicked) ); } void TheThread::on_button_clicked() { std::cout << "TheThread got notified that the button was clicked" << std::endl; } TheGUI::TheGUI(): Gtk::Window(), sigx::glib_auto_dispatchable(), // set up signal functor with late object instance binding (because m_btn is still invalid // but will be constructed later) signal_button_clicked(*this, sigc::ref(m_btn), &Gtk::Button::signal_clicked), m_thethread(this), m_btn() { m_btn = Gtk::manage(new Gtk::Button("notify thread")); m_btn->set_sensitive(false); add(*m_btn); // end the thread if close button is clicked signal_delete_event().connect( // hide parameter GdkEvent* sigc::hide(sigc::bind_return(sigc::mem_fun(m_thethread, &TheThread::finish), false)) ); // one-shot idle handler to start the thread Glib::signal_idle().connect( sigc::bind_return(sigc::mem_fun(this, &TheGUI::on_first_idle), false) ); show_all_children(); } void TheGUI::on_first_idle() { std::cout << "starting TheThread." << std::endl; // start the thread m_thethread.run(); // it's not yet correct to activate the "notify thread" button because we don't // know exactly when the thread will have connected to our signal unless we in turn // let us notify but this is ok for this test example m_btn->set_sensitive(true); } int main(int arg_count, char** args) { Glib::thread_init(); Gtk::Main main(arg_count, args); TheGUI thegui; main.run(thegui); } sigx/tests/test_static_assert.cpp0000644000175000017500000000317511124235374020507 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include class MyClass: public sigx::glib_auto_dispatchable { public: void test() {} }; sigx::signal_wrapper > the_signal; int main() { MyClass x1; // ok the_signal.connect(sigc::mem_fun(x1, &MyClass::test)); // ok the_signal.connect(sigx::open_tunnel(sigc::mem_fun(x1, &MyClass::test))); // tunnel functor is not toplevel the_signal.connect(sigc::bind(sigc::hide(sigx::open_tunnel(sigc::mem_fun(x1, &MyClass::test))), 1)); // cannot connect slots the_signal.connect(sigc::slot(sigc::mem_fun(x1, &MyClass::test))); // cannot pass a functor adapting a slot the_signal.connect(sigx::open_tunnel(sigc::slot(sigc::mem_fun(x1, &MyClass::test)))); // cannot pass a functor adapting a slot the_signal.connect(sigc::bind(sigc::hide(sigc::slot(sigc::mem_fun(x1, &MyClass::test))), 1)); } sigx/tests/test_signal_idle.cpp0000644000175000017500000000665711124235331020112 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include using namespace std; class MyThread: public sigx::glib_threadable { public: MyThread(); // expose the idle signal sigx::signal_f signal_idle; }; class MainThread: public sigx::glib_auto_dispatchable { public: MainThread(); void run(); protected: void quit(); void on_self_ready(); void on_mythread_idle_sync(); void on_mythread_idle_async(); protected: Glib::RefPtr m_loop; MyThread m_mythread; // store the thread's idle signal sigx::glib_signal_idle m_sigThreadIdle; sigx::connection_wrapper m_connMyThreadIdle; }; using namespace std; MainThread::MainThread(): m_loop(), m_mythread(), m_sigThreadIdle(), m_connMyThreadIdle() {} void MainThread::run() { m_loop = Glib::MainLoop::create(); // one-shot idle handler Glib::signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &MainThread::on_self_ready), false ) ); m_loop->run(); } void MainThread::quit() { m_mythread.finish(); m_loop->quit(); } void MainThread::on_self_ready() { m_mythread.run(); m_sigThreadIdle = m_mythread.signal_idle(); m_connMyThreadIdle = m_sigThreadIdle.connect( sigx::open_sync_tunnel( sigc::bind_return( sigc::mem_fun(this, &MainThread::on_mythread_idle_sync), true ) ) ); } void MainThread::on_mythread_idle_sync() { static int count = 0; cout << "mythread is idle" << endl; ++count; if (count == 3) { m_connMyThreadIdle.disconnect(); // create a one-shot mythread idle handler; m_sigThreadIdle.connect( // bind_return is used to satisfy the compiler, the bound result // can't be used with async tunnels; // async tunnels return a type's default value which is false for a // bool and therefore we get disconnected automatically from // mythread's idle signal sigc::bind_return( sigc::mem_fun(this, &MainThread::on_mythread_idle_async), bool() ) ); } } void MainThread::on_mythread_idle_async() { cout << "mythread is idle the last time" << endl; // one-shot idle handler to end the program Glib::signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &MainThread::quit), false ) ); } MyThread::MyThread(): signal_idle(make_idle_signal_f()) {} int main() { Glib::thread_init(); MainThread app; app.run(); cout << "press ."; cin.get(); return 0; } sigx/tests/test_sync_async_argument_passing.cpp0000644000175000017500000000557111124235403023431 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include class string_wrapper { std::string m_str; public: string_wrapper(const char* s); string_wrapper(const string_wrapper& other); // implicit dtor is fine const std::string& str() const { return m_str; } private: // not implemented string_wrapper& operator =(const string_wrapper& other); }; class MyThread: public sigx::glib_threadable { public: MyThread(); // async request sigx::request_f do_sg_async; // sync request void do_sg_sync(const string_wrapper& s) const; protected: /// message handler for sync and async void on_do_sg(const string_wrapper s) const; }; using namespace std; string_wrapper::string_wrapper(const char* s): m_str(s) { cout << "ctor string_wrapper" << endl; } string_wrapper::string_wrapper(const string_wrapper& other): m_str(other.m_str) { cout << "copy ctor string_wrapper" << endl; } MyThread::MyThread(): sigx::glib_threadable(), // request api // note: use *this instead of this because this leads to ambiguous overloads for mem_fun do_sg_async(sigc::mem_fun(*this, &MyThread::on_do_sg)) {} void MyThread::do_sg_sync(const string_wrapper& s) const { // note: use *this instead of this because this leads to ambigous overloads for mem_fun sigx::open_sync_tunnel(sigc::mem_fun(*this, &MyThread::on_do_sg))(sigc::ref(s)); } void MyThread::on_do_sg(const string_wrapper s) const { cout << "got message: " << s.str() << endl; } int main(int argc, char* argv[]) { Glib::thread_init(); MyThread thethread; thethread.run(); // message is copied only once when MyThread::on_do_sg() is called in the context of thethread thethread.do_sg_sync("sync"); cout << endl; // message is copied several times because it is stored inside the asynchronous tunnel_context before MyThread::on_do_sg() is called in the context of thethread thethread.do_sg_async("async"); thethread.finish(); cin.get(); return 0; } sigx/tests/test_connection_handling.cpp0000644000175000017500000000664111124235316021637 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include // sigc::var #include #include #include #include #include #include #include using namespace std; // fwd decl class MainThread; class MyThread: public sigx::glib_threadable { public: MyThread(); protected: // virtuals from sigx::threadable virtual void on_startup(); private: struct ThreadData; Glib::Private m_ThreadData; // signal api public: // expose the 'nothing' signal sigx::signal_f > signal_nothing; }; struct MyThread::ThreadData { sigc::signal m_sigNothing; }; class MainThread: public sigx::glib_auto_dispatchable { public: MainThread(); void run(); protected: void on_self_ready(); void on_end_mainthread(); protected: Glib::RefPtr m_mainloop; MyThread m_mythread; sigx::connection_wrapper m_connMyThreadNothing; }; using namespace std; MyThread::MyThread(): sigx::glib_threadable(), // initialize the signal api signal_nothing(*this, m_ThreadData, &ThreadData::m_sigNothing) {} //virtual void MyThread::on_startup() { m_ThreadData.set(new ThreadData); } MainThread::MainThread(): sigx::glib_auto_dispatchable(), m_mainloop(), m_mythread(), m_connMyThreadNothing() {} void MainThread::run() { m_mainloop = Glib::MainLoop::create(); // one-shot idle handler Glib::signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &MainThread::on_self_ready), false ) ); m_mainloop->run(); } void MainThread::on_end_mainthread() { // disconnecting after restarting mythread shouldn't work (connection invalid) but yield no errors m_connMyThreadNothing.disconnect(); // destroying after restarting mythread shouldn't (connection invalid) work but yield no errors m_connMyThreadNothing = sigx::connection_wrapper(); m_mythread.finish(); m_mainloop->quit(); } void do_nothing_dummy() {} void MainThread::on_self_ready() { // start mythread m_mythread.run(); // connect to the thread's 'nothing' signal m_connMyThreadNothing = m_mythread.signal_nothing().connect( sigx::open_tunnel_with(&do_nothing_dummy, *this) ); // wait and test the connection status m_connMyThreadNothing.connected(); // restart the thread m_mythread.finish(); m_mythread.run(); // one-shot idle handler to Glib::signal_idle().connect( sigc::bind_return( sigc::mem_fun(this, &MainThread::on_end_mainthread), false ) ); } int main() { Glib::thread_init(); MainThread app; app.run(); cout << "press ."; cin.get(); return 0; } sigx/macros/0000755000175000017500000000000011126342406014205 5ustar triendl.kjtriendl.kjsigx/macros/template.macros.m40000644000175000017500000000654710773477750017603 0ustar triendl.kjtriendl.kjdnl Copyright 2007, Klaus Triendl dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public dnl License as published by the Free Software Foundation; either dnl version 2.1 of the License, or (at your option) any later version. dnl dnl This library is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl Lesser General Public License for more details. dnl dnl You should have received a copy of the GNU Lesser General Public dnl License along with this library; if not, write to the Free Software dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA dnl define(__t_div__,divnum)divert(-1) dnl dnl M4 macros for building large files quickly dnl divert(0)// -*- c++ -*- /* Do not edit! -- generated file */ divert(-1) changequote([, ]) changecom() dnl dnl Macros for sigx specifically. dnl Originally copied from sigc++, but modified to meet special sigx++ needs. dnl define([CALL_SIZE],7) #Generate header guards: define([__FIREWALL__],[dnl dnl change the macro file path '../macros/file.h.m4' define(__hfile_temp__, [patsubst(__file__, ^\.\..macros)])dnl define(__hfile__,[_SIGX[]patsubst(translit(__hfile_temp__, a-z./\+-, A-Z_____), _M4$)_])dnl #ifndef __hfile__ #define __hfile__[]dnl divert(1)dnl #endif /* __hfile__ */ divert(0)dnl ]) define([_R_],[typename sigc::type_trait<$1>::take]) define([_P_],[typename sigc::type_trait<$1>::pass]) define([_T_],[typename sigc::type_trait<$1>::type]) define([COPYRIGHT_NOTICE],[[ /* * Copyright 2007 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */]]) dnl dnl General macros dnl define([UPPER],[translit([$*],[a-z],[A-Z])]) define([LOWER],[translit([$*],[A-Z],[a-z])]) define([PROT],[[$*]]) define([_LOOP], [ifelse(eval($1<$2),0, [indir([_LOOP_FORMAT], $1)], [indir([_LOOP_FORMAT], $1)[]_LOOP_SEP[ ]_LOOP(eval($1+1), $2)])]) define([LOOP], [pushdef([_LOOP_FORMAT], translit([$1],%, $))dnl pushdef([_LOOP_SEP], ifelse([$3], [], [[, ]], [$3]))dnl ifelse(eval($2>0),1,[PROT(_LOOP(1, $2))],[PROT()])dnl popdef([_LOOP_SEP])dnl popdef([_LOOP_FORMAT])dnl ]) define([NUM],[eval(ifelse([$1],,0,1)ifelse($#,0,0, $#,1,,[+NUM(shift($@))]))]) define([LIST],[ifelse($#,0,, $#,1,[$1],[$1],,[LIST(shift($@))],[__LIST($@)])]) define([__LIST],[ifelse($#,0,, $#,1,[$1],[$1[]ifelse([$2],,,[[, ]])__LIST(shift($@))])]) dnl define([_NL_],[ ]) define([FOR], [pushdef([_FOR_FUNC],PROT(translit([$3],%, $)))dnl _FOR($1, $2)[]dnl popdef([_FOR_FUNC])dnl ]) define([_FOR],[ifelse(eval($1>$2),1,[],[_FOR_FUNC($1)[]_FOR(eval($1+1), $2)])]) divert(__t_div__)dnl sigx/macros/request_f.h.m40000644000175000017500000001007711123532235016675 0ustar triendl.kjtriendl.kjdnl Copyright 2006, Klaus Triendl dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public dnl License as published by the Free Software Foundation; either dnl version 2.1 of the License, or (at your option) any later version. dnl dnl This library is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl Lesser General Public License for more details. dnl dnl You should have received a copy of the GNU Library General Public dnl License along with this library; if not, write to the Free dnl Software Foundation, 51 Franklin Street, Fifth Floor, dnl Boston, MA 02110-1301, USA. dnl divert(-1) include(template.macros.m4) define([REQUEST_F],[dnl /** @short Asynchronous request functor for a sigx::threadable. * * It saves you writing request methods that have to call a handler method * for the request through a tunnel, like: * * @code * class IPResolverThread: public sigx::threadable * { * public: * void resolve(in_addr_t nIP); * void stop_resolving(); * }; * * void IPResolverThread::resolve(in_addr_t nIP) * { * sigx::open_tunnel(sigc::mem_fun(this, &IPResolverThread::on_resolve))(nIP); * } * * void IPResolverThread::stop_resolving() * { * sigx::open_tunnel(sigc::mem_fun(this, &IPResolverThread::on_stop_resolving))(); * } * @endcode * * Instead, delegate it to the request functor: * * @code * class IPResolverThread: public sigx::threadable * { * public: * sigx::request_f resolve; * sigx::request_f<> stop_resolving; * }; * * IPResolverThread::IPResolverThread(): * resolve(sigc::mem_fun(this, &IPResolverThread::on_resolve)), * stop_resolving(sigc::mem_fun(this, &IPResolverThread::on_stop_resolving)) * {} * @endcode * * It is derived from %sigc::slot because a slot provides already all the * necessary functionalities: takes a functor and creates a untyped slot * representation, has function invokation operator (). * * @attention Do not specify a return type as the first template parameter. * As asynchronous tunnels actually do not have a return type, @e request_f * omits it, thus the return type is always `void". * * @note non-copyable, not constructible on the heap (with new) and can't be * pointer aliased (with operator &) to ensure that it is de-facto bound to * a wrapping object. * * @ingroup signals */ template class request_f: LIST(noncopyable, nonheapallocatable, nonpointeraliasing, protected sigc::slot<[LIST(void, [LOOP(T_arg%1, CALL_SIZE)]]))> { public: typedef sigc::slot parent_type; // allow function operator to be used using parent_type::operator (); /** @short Constructs the request functor. * * @note The passed in functor must not be a sigc::slot and must not be * a tunnel functor. * The passed in functor gets tunneled automatically. * * @param _A_func A dispatchable functor, i.e. a functor on a dispatchable's * method or one explicitly created with dispatch_with(). */ template explicit request_f(const T_functor& _A_func): parent_type(tunnel_functor(_A_func)) { // passed in functor must not be tunneled SIGX_STATIC_ASSERT((internal::is_functor_tunneled::value == false)); // passed in functor must not be a slot or adapt a slot; // we have to apply this restriction because slots might have bound // trackables that can cause non-threadsafe access to the passed in slot // which will live in the context of the server thread SIGX_STATIC_ASSERT((sigx::internal::is_or_adapts_slot::value == false)); } }; ]) divert(0) __FIREWALL__ COPYRIGHT_NOTICE #include #include #include #include #include #include namespace sigx { PROT(REQUEST_F) } // namespace sigx sigx/macros/SConscript0000644000175000017500000000043111126342406016215 0ustar triendl.kjtriendl.kj# -*- python -*- Import('env') m4 = [ env.M4('#sigx/internal_types.h', 'internal_types.h.m4'), env.M4('#sigx/tunnel_functor.h', 'tunnel_functor.h.m4'), env.M4('#sigx/signal_wrapper.h', 'signal_wrapper.h.m4'), env.M4('#sigx/request_f.h', 'request_f.h.m4') ] Return('m4') sigx/macros/internal_types.h.m40000644000175000017500000002413011123532235017733 0ustar triendl.kjtriendl.kjdnl Copyright 2008, Klaus Triendl dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public dnl License as published by the Free Software Foundation; either dnl version 2.1 of the License, or (at your option) any later version. dnl dnl This library is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl Lesser General Public License for more details. dnl dnl You should have received a copy of the GNU Library General Public dnl License along with this library; if not, write to the Free dnl Software Foundation, 51 Franklin Street, Fifth Floor, dnl Boston, MA 02110-1301, USA. dnl divert(-1) include(template.macros.m4) define([COUNT_ARGUMENTS], [dnl template struct count_arguments { static const int value = $1; }; ]) divert(0) __FIREWALL__ COPYRIGHT_NOTICE #include // sigc::is_base_and_derived #include // sigc::nil #include // sigc::adaptor_base #include // sigc::adaptor_functor #include // sigc::bind_functor #include // sigc::hide_functor #include // sigc::slot_base #include #include #include // functor attaching a shared_dispatchable to another functor by binding // the shared_dispatchable and hiding it #define SIGX_DISPATCH_WITH_FUNCTOR(T_functor)\ sigc::bind_functor<-1, sigc::hide_functor<-1, T_functor>, shared_dispatchable> namespace sigx { namespace internal { /** @short counts the provided template arguments. There are specializations * for 1 to (CALL_SIZE-1) template arguments that are not sigc::nil */ template struct count_arguments { static const int value = CALL_SIZE; }; FOR(0, CALL_SIZE-1, [[COUNT_ARGUMENTS(%1)]]) /** @short finds out whether @e T_functor is tunneled, i.e. * whether the functor chain contains a functor derived from sigx::tunnel_base. * * To investigate the fact that there exists one functor derived from * sigx::tunnel_base, this template struct cascades down the functor chain. * e.g. bind_functor - tunnel_functor - member_functor * * The template argument @e T_functor is the functor type. * @e I_isadaptor indicates whether @e T_functor inherits from sigc::adaptor_base. * @e I_istunnel indicates whether @e T_functor inherits from sigx::tunnel_base. */ template::value, bool I_isadaptor = sigc::is_base_and_derived::value> struct is_functor_tunneled; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for tunneled adaptors. */ template struct is_functor_tunneled { static const bool value = true; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for tunneled arbitrary functors. */ template struct is_functor_tunneled { static const bool value = true; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for arbitrary functors, static and member * function pointers. */ template struct is_functor_tunneled { // no chance to investigate further, probably a static or member function // pointer static const bool value = false; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for adaptors */ template struct is_functor_tunneled { // investigate further by cascading the functor chain // functor must define adaptor_type; // T_functor is probably derived from sigc::adapts; defines // adaptor_type typedef typename T_functor::adaptor_type adaptor_type; static const bool value = is_functor_tunneled::value; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for sigc::adaptor_functors wrapping * static and arbitrary functors. * This specialization is needed because sigc::adaptor_functor does not define * its wrapped functor as adaptor_type */ template struct is_functor_tunneled, false, true> { static const bool value = is_functor_tunneled::value; }; /** @short finds out whether @e T_functor is tunneled, i.e. * whether the functor chain contains a functor derived from sigx::tunnel_base. * * To investigate the fact that there exists one functor derived from * sigx::tunnel_base, this template struct cascades down the functor chain. * e.g. bind_functor - tunnel_functor - member_functor * * The template argument @e T_functor is the functor type. * @e I_isadaptor indicates whether @e T_functor inherits from sigc::adaptor_base. * @e I_isslot indicates whether @e T_functor inherits from sigc::slot_base. */ template< typename T_functor, bool I_isslot = sigc::is_base_and_derived::value, bool I_isadaptor = sigc::is_base_and_derived::value> struct is_or_adapts_slot; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for tunneled adaptors. */ template struct is_or_adapts_slot { static const bool value = true; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for arbitrary functors, static and member * function pointers. */ template struct is_or_adapts_slot { // no chance to investigate further, probably a static or member function // pointer static const bool value = false; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for adaptors */ template struct is_or_adapts_slot { // investigate further by cascading the functor chain // functor must define adaptor_type; // T_functor is probably derived from sigc::adapts; defines // adaptor_type typedef typename T_functor::adaptor_type adaptor_type; static const bool value = is_or_adapts_slot::value; }; /** @short finds out whether the functor chain contains a tunnel functor. * This specialization is used for sigc::adaptor_functors wrapping * static and arbitrary functors. * This specialization is needed because sigc::adaptor_functor does not define * its wrapped functor as adaptor_type */ template struct is_or_adapts_slot, false, true> { static const bool value = is_or_adapts_slot::value; }; /** @short Used to find a dispatchable out of the functor/adaptor chain, * i.e. the dispatchable object of a mem_functor or the shared_dispatchable * stored by dispatch_with(). * * It additionally checks at compile time that T_functor is really a functor on a * dispatchable's method by accessing the member variable obj_ of mem_functors * and converting the object to a sigx::dispatchable; * hence, the compiler will issue error messages if it is not a mem_functor or the object * is not convertible to a sigx::dispatchable */ template::value> struct dispatchable_constraint; template struct dispatchable_constraint { static const dispatchable& find_dispatchable(typename sigc::type_trait::take _A_func) { // if the compiler reports an error there are only 2 possibilities: // 1) you connected a static function to a signal or opened a tunnel on a // static signal without specifying the dispatchable to operate on. // 2) you connected a member function to a signal or opened a tunnel on a // member function where the member function is not from a dispatchable // solution: call 'open_tunnel_with' or 'open_sync_tunnel_with' and specify the dispatachable! // access obj_ of the functor; // this issues a compile time error if _A_func is not a functor // on an object's member function (only sigc member functors have this) // obj_ is a (const_)limit_reference type; must call invoke() to // ensure that we get the bound member type instead of a sigc::trackable return _A_func.obj_.invoke(); } }; // walks down the adaptor chain template struct dispatchable_constraint { static const dispatchable& find_dispatchable(typename sigc::type_trait::take _A_func) { return is_adaptor_dispatchable(_A_func); } private: // takes T_functor and matches it again to find // special types and walk down the adaptor chain template static const dispatchable& is_adaptor_dispatchable(const sigc::adaptor_functor& _A_func) { return dispatchable_constraint::find_dispatchable(_A_func.functor_); } // match the sigx special dispatchable adaptor chain template static const dispatchable& is_adaptor_dispatchable(const SIGX_DISPATCH_WITH_FUNCTOR(T_adapted_functor)& _A_func) { // no need to proceed as we found out that the functor is dispatchable return _A_func.bound1_.visit(); } // match all other apaptors, must define adaptor_type template static const dispatchable& is_adaptor_dispatchable(const T_adapted_functor& _A_func) { // T_adapted_functor must define adaptor_type; typedef typename T_adapted_functor::adaptor_type adaptor_type; // _A_func.functor_ is always an adaptor_type return is_adaptor_dispatchable(_A_func.functor_); } }; } // namespace internal } // namespace sigx sigx/macros/tunnel_functor.h.m40000644000175000017500000003726311123532235017753 0ustar triendl.kjtriendl.kjdnl Copyright 2006, Klaus Triendl dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public dnl License as published by the Free Software Foundation; either dnl version 2.1 of the License, or (at your option) any later version. dnl dnl This library is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl Lesser General Public License for more details. dnl dnl You should have received a copy of the GNU Library General Public dnl License along with this library; if not, write to the Free dnl Software Foundation, 51 Franklin Street, Fifth Floor, dnl Boston, MA 02110-1301, USA. dnl divert(-1) include(template.macros.m4) define([TUNNEL_FUNCTOR_OPERATOR_N],[dnl template typename deduce_result_type::type operator()(LOOP(T_arg%1 _A_arg%1, $1)) { typedef typename deduce_result_type::type deduced_result_type; typedef tunnel_context tunnel_context_type; tunnel_context_type* context = new tunnel_context_type(m_disp, m_validity_tracker, this->functor_, LOOP(_A_arg%1, $1)); return context->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(LOOP(T_arg%1 _A_arg%1, $1)) { typedef typename deduce_result_type::type deduced_result_type; typedef tunnel_context tunnel_context_type; tunnel_context_type* context = new tunnel_context_type(m_disp, m_validity_tracker, this->functor_, LOOP(_A_arg%1, $1)); return context->tunnel(); } #endif ]) define([ASYNC_TUNNEL_FUNCTOR_OPERATOR_N],[dnl template typename deduce_result_type::type operator()(LOOP(T_arg%1 _A_arg%1, $1)) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, LOOP(_A_arg%1, $1)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(LOOP(T_arg%1 _A_arg%1, $1)) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, LOOP(_A_arg%1, $1)))->tunnel(); } #endif ]) define([SYNC_TUNNEL_FUNCTOR_OPERATOR_N],[dnl template typename deduce_result_type::type operator()(LOOP(T_arg%1 _A_arg%1, $1)) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, LOOP(sigx::ref(_A_arg%1), $1)))->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD template typename deduce_result_type::type sun_forte_workaround(LOOP(T_arg%1 _A_arg%1, $1)) { typedef typename deduce_result_type::type deduced_result_type; return make_new_tunnel_context(m_disp, m_validity_tracker, sigc::bind(this->functor_, LOOP(sigx::ref(_A_arg%1), $1)))->tunnel(); } #endif ]) divert(0) __FIREWALL__ COPYRIGHT_NOTICE /** @defgroup Functors Adaptors * @short Useful sigc++ adaptors. */ #include #include #include #include #include #include namespace sigx { template struct tunnel_functor; /** @short creates a tunnel on the given functor. * @note expects the functor to be dispatchable. A functor is dispatchable if * the class the functor operates on is derived from sigx::dispatchable or if the * functor is or contains a SIGX_DISPATCH_WITH_FUNCTOR. * @ingroup Functors * @code * // if class MyThread is dispatchable, sigc::mem_fun creates a dispatchable functor. * open_tunnel(sigc::mem_fun(destobj, &MyThread::dosomething)); * // otherwise, create a dispatchable functor explicitly with dispatch_with * open_tunnel_with(sigc::mem_fun(destobj, &MyThread::dosomething), dispatchable); * open_tunnel_with(sigc::ptr_fun(&MyThread::dosomething_static), dispatchable); * @endcode * @attention Never invoke an asynchronous functor with arguments passed by * reference with sigc::ref() (or at least not if you don't know exactly what * you are doing)! * @note You have to be careful that T_functor, arguments bound to it and * passed arguments are threadsafe. * Asynchronous tunnels copy T_functor and passed arguments on invokation of * the tunnel functor and destroy them in the context of the server thread * (the thread receiving the message which is different from the sender thread!). * e.g. never do this: * @code * struct MyThread * { * void do_something(const GLib::RefPtr& p) {} * }; * * Glib::RefPtr p; * open_tunnel(mythread, &MyThread::do_something)(p); * @endcode * For safety reasons you can apply this rule also for synchronous tunnels, * although the invokation behaves differently: Still T_functor is copied but * passed arguments are sent by reference to the server thread. * The same rules apply for sigx::request_f */ template struct tunnel_functor: public sigc::adapts, public tunnel_base { typedef typename sigc::adapts::adaptor_type adaptor_type; typedef typename adaptor_type::result_type result_type; template struct deduce_result_type { // we could also use sigc::deduce_result_type but this saves another // level of indirection and does what sigc++ does internally typedef typename adaptor_type::template deduce_result_type::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass>::type type; }; result_type operator()() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD result_type sun_forte_workaround() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #endif FOR(1, CALL_SIZE,[[ASYNC_TUNNEL_FUNCTOR_OPERATOR_N(%1)]]) /** @short Constructs an adaptor that wraps the passed functor. * @param _A_func Functor to invoke at the other end of the tunnel * from operator()(). * @param dispatcher_change_is_cleanup Whether a dispatcher change should be * be treated as reason to destroy the tunnel * @note The passed in functor must be a "dispatchable functor", i.e. * a functor on a dispatchable's method or a functor created by * sigx::dispatch_with. */ explicit tunnel_functor(_R_(T_functor) _A_func): sigc::adapts(_A_func), // find the dispatchable object contained in the functor by // stepping down the functor chain; // dispatchable_constraint finds the dispatchable and issues a compiler // error if the passed in functor is not a functor on a dispatchable's // method or does find a dispatchable in a SIGX_DISPATCH_WITH_FUNCTOR tunnel_base(internal::dispatchable_constraint::find_dispatchable(this->functor_)) {} // implicit copy ctor is fine // implicit dtor is fine // implicit assignment operator is fine /** @short Activates validity tracking for sigc::trackableS and tracking of a dispatcher change * (e.g. when a thread finishes its execution and resets its dispatcher) * @note %activate_validity_tracking() assumes that the tunnel functor, all sigc::trackableS and the dispatcher/dispatchable * are managed and accessed in the context of the calling thread. */ void activate_validity_tracking() const { validity_tracker().activate(); // visit each trackable and bind the validity trackable to the sigc trackable and vice versa sigc::visit_each_type( sigc::mem_fun(validity_tracker(), &tunnel_validity_tracker::do_bind_to_trackable), this->functor_ ); } }; template struct tunnel_functor: public sigc::adapts, public tunnel_base { typedef typename sigc::adapts::adaptor_type adaptor_type; typedef typename adaptor_type::result_type result_type; template struct deduce_result_type { // we could also use sigc::deduce_result_type but this saves another // level of indirection and does what sigc++ does internally typedef typename adaptor_type::template deduce_result_type::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass, typename sigc::type_trait::pass>::type type; }; result_type operator()() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #ifndef SIGC_TEMPLATE_SPECIALIZATION_OPERATOR_OVERLOAD result_type sun_forte_workaround() { return make_new_tunnel_context(m_disp, m_validity_tracker, this->functor_)->tunnel(); } #endif FOR(1, CALL_SIZE,[[SYNC_TUNNEL_FUNCTOR_OPERATOR_N(%1)]]) /** @short Constructs an adaptor that wraps the passed functor. * @param _A_func Functor to invoke at the other end of the tunnel * from operator()(). * @param dispatcher_change_is_cleanup Whether a dispatcher change should be * be treated as reason to destroy the tunnel * @note The passed in functor must be a "dispatchable functor", i.e. * a functor on a dispatchable's method or a functor created by * sigx::dispatch_with. */ explicit tunnel_functor(_R_(T_functor) _A_func): sigc::adapts(_A_func), // find the dispatchable object contained in the functor by // stepping down the functor chain; // dispatchable_constraint finds the dispatchable and issues a compiler // error if the passed in functor is not a functor on a dispatchable's // method or does find a dispatchable in a SIGX_DISPATCH_WITH_FUNCTOR tunnel_base(internal::dispatchable_constraint::find_dispatchable(this->functor_)) {} // implicit copy ctor is fine // implicit dtor is fine // implicit assignment operator is fine /** @short Activates validity tracking for sigc::trackableS and tracking of a dispatcher change * (e.g. when a thread finishes its execution and resets its dispatcher) * @note %activate_validity_tracking() assumes that the tunnel functor, all sigc::trackableS and the dispatcher/dispatchable * are managed and accessed in the context of the calling thread. */ void activate_validity_tracking() const { validity_tracker().activate(); // visit each trackable and bind the validity trackable to the sigc trackable and vice versa sigc::visit_each_type( sigc::mem_fun(validity_tracker(), &tunnel_validity_tracker::do_bind_to_trackable), this->functor_ ); } }; /** @short Binds a dispatchable explicitly to a functor. * @note Use only with non-dispatchable functors (functors on functions or * methods of classes that do not derive from sigx::dispatchable) * @ingroup Functors */ template SIGX_DISPATCH_WITH_FUNCTOR(T_functor) dispatch_with(const T_functor& _A_func, const shared_dispatchable& d) { return sigc::bind(sigc::hide(_A_func), d); } /** @short Opens an asynchronous tunnel on the specified functor. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_tunnel(const T_functor& _A_func) { return tunnel_functor(_A_func); } /** @short Opens a synchronous tunnel on the specified functor. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_sync_tunnel(const T_functor& _A_func) { return tunnel_functor(_A_func); } /** @short Opens an asynchronous tunnel on the specified functor with the dispatcher of the specified dispatchable. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @param d the dispatchable to operate on * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_tunnel_with(const T_functor& _A_func, const shared_dispatchable& d) { return tunnel_functor(dispatch_with(_A_func, d)); } /** @short Opens a synchronous tunnel on the specified functor with the dispatcher of the specified dispatchable. * @ingroup Functors * @param _A_func the functor on which the tunnel should be created * @param d the dispatchable to operate on * @note @p _A_func must be a dispatchable functor, i.e. a member function * of a class derived from sigx::dispatchable or a dispatchable functor explicitly created with * dispatch_with() * @return Functor that executes @e _A_func on invokation in the context of the server thread. * @ingroup Functors */ template tunnel_functor open_sync_tunnel_with(const T_functor& _A_func, const shared_dispatchable& d) { return tunnel_functor(dispatch_with(_A_func, d)); } } // namespace sigx namespace sigc { /** @short visit_each overload for tunnel functors, completely turning off the visit_each mechanism and thus turning off the trackable mechanism. * * This is necessary because binding a tunnel functor to a slot would access a trackable in a non-threadsafe manner. * sigx++ activates validity tracking for trackables at the call site when the client thread connects to a signal through signal_wrapper<>::connect() */ template void visit_each(const T_action& /*_A_action*/, const sigx::tunnel_functor& /*_A_func*/) { // do nothing } } // namespace sigc sigx/macros/signal_wrapper.h.m40000644000175000017500000006221711123532235017720 0ustar triendl.kjtriendl.kjdnl Copyright 2006, Klaus Triendl dnl dnl This library is free software; you can redistribute it and/or dnl modify it under the terms of the GNU Lesser General Public dnl License as published by the Free Software Foundation; either dnl version 2.1 of the License, or (at your option) any later version. dnl dnl This library is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl Lesser General Public License for more details. dnl dnl You should have received a copy of the GNU Library General Public dnl License along with this library; if not, write to the Free dnl Software Foundation, 51 Franklin Street, Fifth Floor, dnl Boston, MA 02110-1301, USA. dnl divert(-1) include(template.macros.m4) define([COUNT_SIGNAL_ARGUMENTS_FOR_NUMBERED_SIGGROUP_SIGCS], [dnl /** @short counts the arguments of a sigc::signal$1 */ template struct count_signal_arguments > { static const int value = $1; // template specialization for argument count needed static const int tspec = value; }; ]) define([COUNT_SIGNAL_ARGUMENTS_FOR_NUMBERED_GLIB_SIGNALS], [dnl /** @short counts the arguments of a Glib::SignalProxy$1 */ template struct count_signal_arguments > { static const int value = $1; // template specialization for argument count not needed; // this allows us to group all SignProxyN signals together in one template // class static const int tspec = -1; }; ]) define([ARG_N_TYPE_], [dnl typedef typename slot_type::arg$1_type_ arg$1_type_; ]) define([SIGNAL], [dnl /** @short A threadsafe wrapper for any sigc signal with $1 argument(s). * * @ingroup signals */ template class signal_wrapper: public signal_wrapper_base { public: //BOOST_STATIC_ASSERT((internal::count_signal_arguments::value == $1)); static const int argument_count = $1; static const internal::signal_group signal_group = internal::SIGGROUP_SIGC; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::slot_type slot_type; typedef typename signal_type::result_type result_type; FOR(1, $1, [[ARG_N_TYPE_(%1)]]) typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); protected: typedef sigc::bound_const_mem_functor0 make_slot_f1; typedef sigc::retype_return_functor make_slot_f2; typedef sigc::const_mem_functor0 > make_slot_f3; typedef sigc::bind_functor<-1, make_slot_f3, std::tr1::shared_ptr > make_slot_f4; typedef sigc::compose1_functor make_slot_composed1_functor_type; typedef sigc::const_mem_functor$1 make_slot_emit_functor_type; typedef sigc::compose1_functor make_slot_composed2_functor_type; typedef SIGX_DISPATCH_WITH_FUNCTOR(make_slot_composed2_functor_type) make_slot_functor_type; public: /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A shared pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread. * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func) const { return signal_wrapper_base::connect( _A_func, sigc::ptr_fun(&typed_connection_handler::connect) ); } /** @short emits the signal on the other side of the tunnel. */ template result_type emit(LOOP(arg%1_type_ _A_a%1, $1)) const { return open_tunnel_with( // calls T_signal::*emit sigc::compose( sigc::mem_fun(&signal_type::emit), // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), // this makes a copy of the shared signal source and thus // shares it within the tunnel functor ensuring the lifetime // of the shared signal source sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )(LOOP(_A_a%1, $1)); } /** @short emits the signal asynchronously. */ result_type emit(LOOP(arg%1_type_ _A_a%1, $1)) const { return emit(LOOP(_A_a%1, $1)); } /** @short emits the signal synchronously. */ result_type emit_sync(LOOP(arg%1_type_ _A_a%1, $1)) const { return emit(LOOP(_A_a%1, $1)); } /** see emit(LOOP(arg%1_type_, $1)) */ result_type operator()(LOOP(arg%1_type_ _A_a%1, $1)) const { return emit(LOOP(_A_a%1, $1)); } /** @short creates a tunnel_functor that emits the signal when invoked */ template tunnel_functor make_slot() const { typedef tunnel_functor tunnel_funtor_type; return tunnel_funtor_type( dispatch_with( // calls T_signal::*emit sigc::compose( &signal_type::emit, // getter for the T_signal sigc::compose( sigc::retype_return( sigc::mem_fun(m_sigsource.get(), &signal_source_base::getter) ), sigc::bind( sigc::mem_fun(&std::tr1::shared_ptr::operator *), m_sigsource ) ) ), m_disp )); } /** @short creates an asynchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot() const { return make_slot(); } /** @short creates a synchronous tunnel_functor that emits the signal * when invoked */ tunnel_functor make_slot_sync() const { return make_slot(); } }; ]) divert(0) __FIREWALL__ COPYRIGHT_NOTICE #include // std::tr1::shared_ptr, std::auto_ptr #include #include // glibmm signals #include #include #include #include #include #include #include #include /** @defgroup signals Signals * Threadsafe signals on top of the @ref Functors and @ref Dispatching * facilities */ namespace sigx { namespace internal { /** @short Counts a signal's arguments, default class */ template struct count_signal_arguments { static const int value = -1; static const int tspec = -1; }; /** @short Counts the arguments of an unnumbered sigc::signal */ template struct count_signal_arguments > { // forward to count_arguments and not to count_signal_arguments, otherwise // we would get a false count if there is a another signal as the first // argument of a signal, like: sigc::signal > static const int value = count_arguments::value; static const int tspec = value; }; FOR(0, CALL_SIZE, [[COUNT_SIGNAL_ARGUMENTS_FOR_NUMBERED_SIGGROUP_SIGCS(%1)]]) FOR(0, 6, [[COUNT_SIGNAL_ARGUMENTS_FOR_NUMBERED_GLIB_SIGNALS(%1)]]) /** @short Counts the arguments of a Glib::SignalIdle */ template<> struct count_signal_arguments { static const int value = 0; static const int tspec = value; }; /** @short Counts the arguments of a Glib::SignalTimeout */ template<> struct count_signal_arguments { static const int value = 0; static const int tspec = value; }; /** @short Counts the arguments of a Glib::SignalIO */ template<> struct count_signal_arguments { static const int value = 1; static const int tspec = value; }; /** @short Counts the arguments of a Glib::SignalChildWatch */ template<> struct count_signal_arguments { static const int value = 2; static const int tspec = value; }; } // namespace internal /** @short A threadsafe wrapper for sigc signals, Glib * signals or theoretically any other type of signal. * * sigx signals have a shared signal source that exists in the context of * another thread. This signal source has access to the signal. Access (e.g. * connecting) is regulated by a dispatcher running in the context of the * thread owning that signal. */ template::type, int I_arg_count = internal::count_signal_arguments::tspec> class signal_wrapper; FOR(0, CALL_SIZE, [[SIGNAL(%1)]]) /** @short A threadsafe wrapper for a Glib::SignalNormalProxy derived signal. * @ingroup signals */ template // have to specialize the argument count explicitly because template arguments // can't be involved as template parameters in further template arguments class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_GLIB_PROXY; typedef T_signal signal_type; typedef signal_wrapper this_type; typedef typename signal_type::SlotType slot_type; typedef typename signal_type::VoidSlotType void_slot_type; typedef typename slot_type::result_type result_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, bool after = true) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), after ) ); } /** * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect_notify(const T_functor& _A_func, bool after = false) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect_notify), after ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalIdle. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalIdle signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, int priority = Glib::PRIORITY_DEFAULT_IDLE) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), priority ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalTimeout. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalTimeout signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, unsigned int interval, int priority = Glib::PRIORITY_DEFAULT) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), interval, priority ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalIO. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalIO signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the source of the server * thread's signal. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, Glib::IOCondition condition, int priority = Glib::PRIORITY_DEFAULT) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), condition, priority ) ); } }; /** @short A threadsafe wrapper for a Glib::SignalChildWatch. * @ingroup signals */ template<> class signal_wrapper: public signal_wrapper_base { public: static const int argument_count = internal::count_signal_arguments::value; static const internal::signal_group signal_group = internal::SIGGROUP_IRRELEVANT; typedef Glib::SignalChildWatch signal_type; typedef signal_wrapper this_type; typedef bool result_type; typedef sigc::slot slot_type; typedef signal_type (*fp_sig_getter_type)(signal_source_ptr); /** @short Constructs an empty signal_wrapper. * @throw Might throw a std::bad_alloc exception (from dispatchable's ctor) */ signal_wrapper(): signal_wrapper_base() {} /** @short Creates a signal_wrapper from a signal source. * @param _A_disp The dispatchable to operate on * @param _A_sigsource A double pointer to the server * thread's signal source. */ signal_wrapper(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource): signal_wrapper_base(_A_disp, _A_sigsource) {} /** @short Connects a functor, tunnels it automatically if not yet * tunneled and activates validity tracking for sigc::trackableS. * * auto tunneling is successful only if the passed in functor is a * "dispatchable" functor, i.e. a functor on a dispatchable's method * or one explicitly created with "dispatch_with". * You will get compiler errors if the dispatchable can't be deduced from the * passed in functor. * * @note At the moment it is only possible to pass in a non-tunneled functor or * a toplevel tunneled functor due to the fact that the visit_each mechanism * is turned off for the tunnel functor (otherwise there would be the problem * of not threadsafe access to the sigc::trackable base of the of a * dispatchable object.. * * @note passed in functor must not be a slot or adapt a slot; * we have to apply this restriction because slots might have bound * trackables that can cause non-threadsafe access to the passed in slot * which will live in the context of the server thread * * @attention All sigc::trackableS and the original dispatchable contained * in the passed functor must belong to the context of the calling thread. * * @return sigx::connection_wrapper A threadsafe connection wrapper * @note asynchronous */ template connection_wrapper connect(const T_functor& _A_func, GPid pid, int priority = Glib::PRIORITY_DEFAULT) const { return signal_wrapper_base::connect( _A_func, sigc::bind( sigc::ptr_fun(&typed_connection_handler::connect), pid, priority ) ); } }; typedef signal_wrapper glib_signal_idle; typedef signal_wrapper glib_signal_timeout; typedef signal_wrapper glib_signal_io; typedef signal_wrapper glib_ignal_childwatch; } // namespace sigx sigx/src/0000755000175000017500000000000011157533367013524 5ustar triendl.kjtriendl.kjsigx/src/glib_threadable.cpp0000644000175000017500000001114311130210042017265 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // message macros #include "sigx/glib_dispatcher.h" #include "sigx/tunnel_functor.h" #include "sigx/glib_threadable.h" #include "__sigx_pchfence__.h" #include "sigx/private/glib_threadable_p.h" #include "sigx/lock_acquirer.h" namespace sigx { glib_threadable::glib_threadable(): threadable(), m_threaddata(), m_thread() {} // virtual glib_threadable::~glib_threadable() { // 2006-07-02, klaus triendl: // we could finish() ourselves (in the context of the calling thread) // but the problem is that finish() quits the mainloop and right after // on_cleanup() (a virtual method) is called; // By that time the virtual function pointers are probably not set anymore // (?) and the derived object has been already destructed. // // For now, just assert that the thread is not running anymore g_return_if_fail(!m_thread.access_nonvolatile()); } Glib::RefPtr glib_threadable::maincontext() { return m_threaddata.get()->m_pContext; } Glib::RefPtr glib_threadable::mainloop() { return m_threaddata.get()->m_pLoop; } void glib_threadable::run() { Glib::Mutex mtx; // condition to wait until the thread is in a running state Glib::Cond cond; const Glib::Mutex::Lock lock(mtx); create_thread(sigc::slot( sigc::bind( sigc::mem_fun(this, &glib_threadable::on_idle_and_ready), sigc::ref(mtx), sigc::ref(cond) ) )); // now, wait for the thread to be idle and ready cond.wait(mtx); } void glib_threadable::create_thread(const sigc::slot& slot_on_thread_ready) { const sigc::slot run_func( sigc::bind( sigc::mem_fun(this, &glib_threadable::on_run), // bind makes a copy of the slot; // threadsafe as the copy is created and destroyed in the context // of the calling thread slot_on_thread_ready ) ); m_thread.access_nonvolatile() = Glib::Thread::create(run_func, true); } void glib_threadable::on_idle_and_ready(Glib::Mutex& mtx, Glib::Cond& cond) { const Glib::Mutex::Lock lock(mtx); // now, the thread is idle and ready, signal the calling thread that invoked // thread.run() before cond.signal(); } void glib_threadable::finish() { writelock_acquirer locker(m_thread); Glib::Thread*& refthread = access_acquiree(locker); // end thread if not yet finished if (refthread) { // this creates an asynchronous tunnel to // this->mainloop()->quit() open_tunnel_with( sigc::compose( sigc::mem_fun(&Glib::MainLoop::quit), // getter for Glib::MainLoop sigc::compose( &Glib::RefPtr::operator ->, // getter for Glib::RefPtr sigc::mem_fun(this, &glib_threadable::mainloop) ) ), *this )(); // a joinable thread object lives as long as join() hasn't been called; // join() frees all resources and the object itself refthread->join(); refthread = 0; } } void glib_threadable::on_run(const sigc::slot& slot_on_thread_ready) { // pdata will be freed when the thread ends according to glib docs; // see the online docs: glib-Threads.html#g-private-new threaddata* const pdata = new threaddata; m_threaddata.set(pdata); pdata->m_pContext = Glib::MainContext::create(); pdata->m_pLoop = Glib::MainLoop::create(pdata->m_pContext); // scope for glib_disp (not necessary but easy to understand) { glib_dispatcher glib_disp(pdata->m_pContext); // register the dispatcher in the manual_dispatchable set_dispatcher(&glib_disp); // one-shot idle handler calling slot_on_thread_ready pdata->m_pContext->signal_idle().connect( sigc::bind_return(slot_on_thread_ready, false)); // give derived classes the possibility to initialize their own stuff on_startup(); pdata->m_pLoop->run(); // give derived classes the possibility to cleanup their own stuff on_cleanup(); // unregister dispatcher set_dispatcher(0); } } } // namespace sigx sigx/src/SConscript0000644000175000017500000000126711157535113015533 0ustar triendl.kjtriendl.kj# -*- python -*- import re, SCons.Util, versionedlibrary Import('env') sigx_sources = Split(""" dispatcher.cpp glib_dispatcher.cpp connection_wrapper.cpp signal_wrapper_base.cpp signal_f_base.cpp dispatchables.cpp glib_threadable.cpp tunnel_base.cpp tunnel_context_base.cpp tunnel_validity_tracker.cpp operator_new.cpp connection_handler.cpp bad_dispatcher.cpp bad_caller.cpp bad_sync_call.cpp """) if env['SHAREDLIB']: sigxlib = env.VersionedLibrary(target = env['VERSIONED_NAME'], major = int(env['MAJOR']), minor = int(env['MINOR']), micro = int(env['MICRO']), source = sigx_sources) else: sigxlib = env.StaticLibrary(env['VERSIONED_NAME'], sigx_sources) sigx = sigxlib Return('sigx') sigx/src/tunnel_context_base.cpp0000644000175000017500000000370311124202477020263 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/tunnel_context_base.h" #include "sigx/dispatcher.h" #include "sigx/bad_dispatcher.h" #include "__sigx_pchfence__.h" //#include "sigx/lock_acquirer.h" //#include "sigx/glib_lockables.h" #include "sigx/locking_dispatcher_ptr.h" namespace sigx { tunnel_context_base::tunnel_context_base(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker, bool sync /*= false*/): m_validity_tracker(_A_validity_tracker), m_disp(_A_disp), m_sync(sync), m_creator_thread(Glib::Thread::self()) {} //virtual tunnel_context_base::~tunnel_context_base() {} void tunnel_context_base::dispatch_me() { shared_dispatchable::DispatcherPtr dispatcher(m_disp); if (!dispatcher) throw bad_dispatcher(); dispatcher->send(this); } sync_tunnel_context_base::sync_tunnel_context_base(const shared_dispatchable& _A_disp, const tunnel_validity_tracker& _A_validity_tracker): tunnel_context_base(_A_disp, _A_validity_tracker, true), m_cond(), m_mutex() {} void sync_tunnel_context_base::dispatch_me() { Glib::Mutex::Lock lock(m_mutex); tunnel_context_base::dispatch_me(); // synchronize with other end of the tunnel m_cond.wait(m_mutex); } } // namespace sigx sigx/src/connection_handler.cpp0000644000175000017500000001471511157533367020074 0ustar triendl.kjtriendl.kj/* * Copyright 2005 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // message macros #include #include "sigx/connection_handler.h" #include "sigx/shared_dispatchable.h" #include "__sigx_pchfence__.h" // needed for using g_atomic_pointer_set to cast a typed pointer pointer to // a void** typedef void** pptr; namespace sigx { // statics Glib::StaticPrivate connection_handler::thread_specific_connections = GLIBMM_STATIC_PRIVATE_INIT; //static void connection_handler::store( const std::tr1::shared_ptr& _A_refconnptr, const sigc::connection& c ) { connections_container_wrapper* pcont_wrapper = thread_specific_connections.get(); if (!pcont_wrapper) { pcont_wrapper = new connections_container_wrapper; thread_specific_connections.set(pcont_wrapper); } connections_container_wrapper::container_type& conns = pcont_wrapper->m_connections; sigc_connection_ptr& pc = *_A_refconnptr; // create a copy of c on the heap; // must create on the heap because we need control in the current thread over the connection's lifetime g_atomic_pointer_set(pptr(&pc), new sigc::connection(c)); conns[_A_refconnptr.get()] = _A_refconnptr; } //static void connection_handler::destroy(const sigc_connection_ptr* handle) { connections_container_wrapper* const pcont_wrapper = thread_specific_connections.get(); g_return_if_fail(pcont_wrapper != 0); // go searching the sigc connection connections_container_wrapper::container_type& conns = pcont_wrapper->m_connections; const connections_container_wrapper::container_type::iterator it = conns.find(handle); // silently ignore connections not found anymore if (it == conns.end()) return; sigc_connection_ptr& pc = *it->second; // delete the sigc connection object delete pc; // reset the sig connection pointer such that client threads know that // no connection exists anymore g_atomic_pointer_set(pptr(&pc), 0); // note that this doesn't necessarily delete the sigc connection pointer itself // because it is a shared pointer, and some client threads might have it shared // within a connection_wrapper conns.erase(it); } connection_handler::connections_container_wrapper::~connections_container_wrapper() { // disconnect all connections const container_type::iterator itEnd = m_connections.end(); for (container_type::iterator it = m_connections.begin(); it != itEnd; ++it) { sigc_connection_ptr& pc = *it->second; pc->disconnect(); // delete the sigc connection object delete pc; g_atomic_pointer_set(pptr(&pc), 0); } } //template<> //static void typed_connection_handler:: connect( const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, int priority) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect(_A_slot, priority); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } void typed_connection_handler:: connect( const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, unsigned int interval, int priority) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); const fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect(_A_slot, interval, priority); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } void typed_connection_handler:: connect( const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, int fd, Glib::IOCondition condition, int priority) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); const fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect(_A_slot, fd, condition, priority); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } void typed_connection_handler:: connect( const std::tr1::shared_ptr& _A_refconnptr, const std::tr1::shared_ptr& psigsource, const slot_type& _A_slot, GPid pid, int priority) { // must have a valid signal source g_return_if_fail(psigsource.get()); // get the signal from the signal source ... typedef signal_type (*fp_sig_getter)(signal_source_ptr); const fp_sig_getter getsig = reinterpret_cast(psigsource->getter()); // ... and connect the slot const sigc::connection& c = getsig(psigsource.get()).connect(_A_slot, pid, priority); // ... store the resulting connection in the container of the thread's connections connection_handler::store(_A_refconnptr, c); } } // namespace sigx sigx/src/dispatcher.cpp0000644000175000017500000001310311124202477016341 0ustar triendl.kjtriendl.kj/* Copyright (C) 2005 Tim Mayberry and Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // atomic operations #include #include "sigx/bad_caller.h" #include "sigx/bad_sync_call.h" #include "sigx/dispatcher.h" #include "sigx/tunnel_context_base.h" #include "__sigx_pchfence__.h" #include "sigx/lock_acquirer.h" using namespace std; namespace sigx { //statics bool dispatcher::deadlock_detection = false; dld::lockable_sync_messages_type dispatcher::thread_paired_sync_messages; dispatcher::dispatcher(): m_tunnel_contexts(), m_contexts_count(0), m_creator_thread(Glib::Thread::self()) {} dispatcher::~dispatcher() { // might throw bad_caller test_calling_thread(); } void dispatcher::test_calling_thread() { // must be executed in the context of the owner thread, i.e. the thread that // created this glib_dispatcher instance; // note that the Glib::dispatcher requires this, too; if (m_creator_thread != Glib::Thread::self()) throw bad_caller(); } void dispatcher::send(tunnel_context_base* context) { // deadlock detection if (context->is_sync() && dispatcher::deadlock_detection) { Glib::Thread* self = Glib::Thread::self(); if (self == m_creator_thread) // sending a sync message to ourselves will block throw bad_sync_call(); else increase_sync_messages(dld::make_thread_pair(self, m_creator_thread)); } g_atomic_int_inc(&m_contexts_count); writelock_acquirer locker(m_tunnel_contexts); access_acquiree(locker).push(context); } gint dispatcher::queued_contexts() const { return g_atomic_int_get(&m_contexts_count); } bool dispatcher::process_next() { bool more_work = false; tunnel_context_base* context = 0; // scope for locker { writelock_acquirer locker(m_tunnel_contexts); context_container_type& contexts = access_acquiree(locker); if (!contexts.empty()) { context = contexts.front(); contexts.pop(); } } if (context) { // XXX catch exceptions?? more_work = (g_atomic_int_dec_and_test(&m_contexts_count)); const threadhandle_type context_creator_thread = context->creator_thread(); const bool detect_deadlock = dispatcher::deadlock_detection && context->is_sync(); try { if (context->is_valid()) context->invoke(); } catch (...) { // must decrease the sync message counter if (detect_deadlock) decrease_sync_messages(dld::make_thread_pair(context_creator_thread, m_creator_thread)); throw; } // must decrease the sync message counter if (detect_deadlock) decrease_sync_messages(dld::make_thread_pair(context_creator_thread, m_creator_thread)); } return more_work; } //static void dispatcher::increase_sync_messages(const dld::thread_pair_type& threadpair) { // Glib::Thread::self() is the creator of the tunnel context const dld::thread_pair_type& key = threadpair; // a thread can't send a synchronous message to itself if (key.first == key.second) throw bad_sync_call(); writelock_acquirer locker(thread_paired_sync_messages); dld::sync_messages_type& sync_messages = access_acquiree(locker); const pair& pairIt = sync_messages.insert(make_pair(key, dld::syncmessages_counter(key.first))); dld::syncmessages_counter& counter = pairIt.first->second; // are there already synchronous messages pending from the thread we want to send // a message? if (counter) throw bad_sync_call(); ++counter; } //static void dispatcher::decrease_sync_messages(const dld::thread_pair_type& threadpair) { writelock_acquirer locker(thread_paired_sync_messages); dld::sync_messages_type& sync_messages = access_acquiree(locker); const dld::thread_pair_type& key = threadpair; const pair& pairIt = sync_messages.insert(make_pair(key, dld::syncmessages_counter(key.first))); dld::syncmessages_counter& counter = pairIt.first->second; --counter; } namespace dld { thread_pair_type make_thread_pair(threadhandle_type threadA, threadhandle_type threadB) { if (threadA < threadB) return std::make_pair(threadA, threadB); else return std::make_pair(threadB, threadA); } syncmessages_counter::syncmessages_counter(const threadhandle_type& threadA): m_threadA(threadA), m_countThreadA(), m_countThreadB() {} syncmessages_counter& syncmessages_counter::operator ++() { int& count = (Glib::Thread::self() == m_threadA) ? m_countThreadB : m_countThreadA; ++count; return *this; } syncmessages_counter& syncmessages_counter::operator --() { int& count = (Glib::Thread::self() == m_threadA) ? m_countThreadA : m_countThreadB; --count; return *this; } syncmessages_counter::operator bool() const { const int& count = (Glib::Thread::self() == m_threadA) ? m_countThreadA : m_countThreadB; return (count != 0); } } // namespace dld } // namespace sigx sigx/src/dispatchables.cpp0000644000175000017500000001426511130212042017015 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include // message macros, atomic operations #include #include #include "sigx/dispatchable.h" #include "sigx/tunnel_validity_tracker.h" #include "sigx/auto_dispatchable.h" #include "sigx/glib_auto_dispatchable.h" #include "sigx/manual_dispatchable.h" #include "sigx/shared_dispatchable.h" #include "sigx/glib_dispatcher.h" #include "__sigx_pchfence__.h" #include // std::auto_ptr #include "sigx/lock_acquirer.h" #include "sigx/glib_lockables.h" using namespace std; namespace sigx { dispatchable::dispatchable(): noncopyable(), m_shared_count(), m_dispatcher_change_callback_list(), m_disp_ptr() { std::auto_ptr p1(new int(1)); std::auto_ptr p2(new callback_list_ptr_type(0)); std::auto_ptr p3(new internal::rwlockable_dispatcher_ptr(0)); m_shared_count = p1.release(); m_dispatcher_change_callback_list = p2.release(); m_disp_ptr = p3.release(); } dispatchable::~dispatchable() throw() { release(); } dispatchable::dispatchable(const dispatchable& other) throw(): noncopyable(), m_shared_count(other.m_shared_count), m_dispatcher_change_callback_list(other.m_dispatcher_change_callback_list), m_disp_ptr(other.m_disp_ptr) { g_atomic_int_inc(m_shared_count); } dispatchable& dispatchable::operator =(const dispatchable& other) throw() { if (this == &other) return *this; release(); m_shared_count = other.m_shared_count; m_disp_ptr = other.m_disp_ptr; m_dispatcher_change_callback_list = other.m_dispatcher_change_callback_list; g_atomic_int_inc(m_shared_count); return *this; } void dispatchable::release() throw() { if (g_atomic_int_dec_and_test(m_shared_count)) { delete m_shared_count; delete m_disp_ptr; // only free the lockable, not the callback list itself; // this is the responsibility of derived dispatchables. g_assert(0 == *m_dispatcher_change_callback_list); delete m_dispatcher_change_callback_list; m_shared_count = 0; m_disp_ptr = 0; m_dispatcher_change_callback_list = 0; } } void dispatchable::add_dispatcher_change_notify_callback(void* data, func_dispatcher_change_notify func) const { callback_list_ptr_type& callbacklist = *m_dispatcher_change_callback_list; if (!callbacklist) callbacklist = new callback_list_type; callbacklist->push_back(make_pair(data, func)); } void dispatchable::remove_dispatcher_change_notify_callback(void* data) const { callback_list_ptr_type& callbacklist = *m_dispatcher_change_callback_list; const callback_list_type::iterator itEnd = callbacklist->end(); for (callback_list_type::iterator it = callbacklist->begin(); it != itEnd; /**/) { if (it->first == data) callbacklist->erase(it++); else ++it; } } void dispatchable::invalidate_tunnels() { callback_list_ptr_type& callbacklist = *m_dispatcher_change_callback_list; if (callbacklist) { const callback_list_type::iterator itEnd = callbacklist->end(); for (callback_list_type::iterator it = callbacklist->begin(); it != itEnd; ++it) it->second(it->first); delete callbacklist; callbacklist = 0; } } auto_dispatchable::auto_dispatchable(dispatcher_ptr disp): dispatchable() { // the auto_dispatchable sets up the dispatcher immediately in its ctor; // no need to lock the dispatcher pointer, invoke() is threadsafe m_disp_ptr->access_nonvolatile() = disp; } auto_dispatchable::~auto_dispatchable() { // scope for locker { // it's time to set the pointer to the dispatcher to 0 writelock_acquirer locker(*m_disp_ptr); dispatcher_ptr& disp = access_acquiree(locker); delete disp; disp = 0; } invalidate_tunnels(); // note that m_disp_ptr might still be referenced by others; // this probably means that some thread still has some // connections to a signal in this dispatchable's realm; // // We don't care here: tunnels connected to a signal will be disconnected // (invalidate_tunnels() notified the validity // trackable about the dispatcher change), messages to be sent will throw // a bad_dispatcher exception } glib_auto_dispatchable::glib_auto_dispatchable(): auto_dispatchable(new glib_dispatcher) {} glib_auto_dispatchable::glib_auto_dispatchable(const Glib::RefPtr& context): auto_dispatchable(new glib_dispatcher(context)) {} manual_dispatchable::manual_dispatchable(): dispatchable() {} manual_dispatchable::~manual_dispatchable() { invalidate_tunnels(); // Dispatcher should have been set to 0 already // when the thread ends, not when the dispatchable is destroyed //set_dispatcher(0); g_assert(dispatcher() == 0); // m_disp_ptr might still be referenced by others; // this probably means that some thread still has some // connections to a signal in this dispatchable's realm; } void manual_dispatchable::set_dispatcher(dispatcher_ptr pdisp) { // scope for locker { writelock_acquirer locker(*m_disp_ptr); dispatcher_ptr& disp = access_acquiree(locker); disp = pdisp; } // this will call back to all validity trackables invalidating their tunnel // functors operating on that dispatchable invalidate_tunnels(); } shared_dispatchable::shared_dispatchable(): dispatchable() {} shared_dispatchable::shared_dispatchable(const dispatchable& d) throw(): dispatchable(d) {} shared_dispatchable& shared_dispatchable::operator =(const dispatchable& d) throw() { dispatchable::operator =(d); return *this; } } // namespace sigx sigx/src/signal_f_base.cpp0000644000175000017500000000213111124202477016766 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/signal_f_base.h" #include "sigx/shared_dispatchable.h" #include "sigx/signal_source_base.h" #include "__sigx_pchfence__.h" namespace sigx { signal_f_base::signal_f_base(const shared_dispatchable& _A_disp, signal_source_ptr _A_psigsource): m_disp(_A_disp), m_sigsource(_A_psigsource) {} } // namespace sigx sigx/src/tunnel_base.cpp0000644000175000017500000000175211124202477016521 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/tunnel_functor.h" #include "__sigx_pchfence__.h" namespace sigx { tunnel_base::tunnel_base(const shared_dispatchable& _A_disp): m_disp(_A_disp), m_validity_tracker(_A_disp) {} } // namespace sigx sigx/src/glib_dispatcher.cpp0000644000175000017500000000346011124202477017343 0ustar triendl.kjtriendl.kj/* Copyright (C) 2005 Tim Mayberry * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include // g_return_if_fail() #include "sigx/glib_dispatcher.h" #include "__sigx_pchfence__.h" namespace sigx { glib_dispatcher::glib_dispatcher(const Glib::RefPtr& context): dispatcher(), m_disp(context) { m_disp.connect(sigc::mem_fun(this, &glib_dispatcher::do_work)); } glib_dispatcher::~glib_dispatcher() { // must be executed in the context of the owner thread, i.e. the thread that // created this glib_dispatcher instance; // note that the Glib::dispatcher requires this, too; test_calling_thread(); // flush queue. // note that this calls the message handlers! while (process_next()) /*++clouds*/; } void glib_dispatcher::send(tunnel_context_base* context) { dispatcher::send(context); m_disp.emit(); } void glib_dispatcher::do_work() { // 2006-08-12, kj // do not check anymore whether m_exiting==true because do_work() and the // dtor are executed in the context of the same thread anyway while (process_next()) /*++clouds*/; } } // namespace sigx sigx/src/tunnel_validity_tracker.cpp0000644000175000017500000002000311124202477021135 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include // message macros #include #include "sigx/tunnel_validity_tracker.h" #include "sigx/bad_dispatcher.h" #include "sigx/tunnel_functor.h" #include "__sigx_pchfence__.h" #include // std::for_each #include "sigx/validity_trackable.h" using namespace std; namespace sigx { namespace internal { validity_trackable::validity_trackable(const shared_dispatchable& _A_disp): m_refcount(), m_tunnel_refcount(), m_valid(true), m_connections(), m_disp(_A_disp), m_dispatcher_change_is_cleanup(false), m_creator_thread(Glib::Thread::self()) {} } // namespace internal tunnel_validity_tracker::tunnel_validity_tracker(const shared_dispatchable& _A_disp): m_info(new internal::validity_trackable(_A_disp)) { m_info->m_refcount = 1; m_info->m_tunnel_refcount = 1; } tunnel_validity_tracker::tunnel_validity_tracker(const tunnel_validity_tracker& other): m_info(other.m_info) { g_atomic_int_inc(&m_info->m_refcount); g_atomic_int_inc(&m_info->m_tunnel_refcount); } tunnel_validity_tracker& tunnel_validity_tracker::operator =(const tunnel_validity_tracker& other) { // destroy this first this->~tunnel_validity_tracker(); m_info = other.m_info; g_atomic_int_inc(&m_info->m_refcount); g_atomic_int_inc(&m_info->m_tunnel_refcount); return *this; } tunnel_validity_tracker::~tunnel_validity_tracker() { // test whether last tunnel functor died if (TRUE == g_atomic_int_dec_and_test(&m_info->m_tunnel_refcount)) { // test whether we are responsible to clean up the validity tracking stuff if (1 == g_atomic_int_get(&m_info->m_dispatcher_change_is_cleanup)) { if (m_info->m_creator_thread == Glib::Thread::self()) { // short cut - no need to tunnel a message because // validity trackable was created with the same // thread executing the dtor; // // this can happen e.g. if threadA has connected a tunnel functor to a signal // of threadB, threadB emits this very signal, threadA executes the emitted signal and ends threadB. // threadB might have emitted the signal again in the meanwhile and threadA has a message pending // in the dispatcher queue. threadB might finish its execution, destroying threadA's connection to // threadB's signal. Because threadA has still the message pending however, the validity trackable // is still alive with the message in the queue. // Then threadA executes the pending message and the last validity trackable will go out of scope // along with the processed message; because the validity trackable and the dispatcher belong to the // same thread as the executing one we can just call on_last_functor directly tunnel_validity_tracker::on_last_functor(*this); } else { // little hack to ensure that the dtor doesn't trigger this message again m_info->m_tunnel_refcount = 1; // send a maintenance message to the client thread; // note that the tunnel functor will make a copy of this (even we are // currently in the dtor) and thus // ensures that still everything will be valid; // // attention: never use any sigc::trackableS here, otherwise the maintenance message // would be triggered without end! (open_tunnel() creates again a validity trackable // which goes out of scope after the message is dispatched and comes here again...) sigc::exception_catch( open_tunnel_with(&tunnel_validity_tracker::on_last_functor, m_info->m_disp), bad_dispatcher_catcher() )(*this); } } } if (TRUE == g_atomic_int_dec_and_test(&m_info->m_refcount)) delete m_info; m_info = 0; } void tunnel_validity_tracker::on_last_functor(tunnel_validity_tracker& data) { // because the last tunnel functor died we can just clear the connections container because // there are obviously no connections open anymore data.m_info->m_connections.clear(); cleanup(data.m_info, true); } //static void tunnel_validity_tracker::cleanup(void* data, bool cleanup_dispatcher) { internal::validity_trackable* const vt = (internal::validity_trackable*) data; g_assert(vt->m_creator_thread == Glib::Thread::self()); if (vt->m_valid) { // deactivate validity tracking // (dtor doesn't need to send a cleanup message anymore) g_atomic_int_set(&vt->m_dispatcher_change_is_cleanup, 0); // invalidate callback vt->m_valid = false; // callback is invalid, disconnect slots containing // tunnel functors from a signal eventually; tunnel_validity_tracker::clear_connections(vt); if (cleanup_dispatcher) { // notify the associated dispatchable that the tunnel is not valid // anymore; // if cleanup_dispatcher = false then cleanup was called from notify_dispatcher_change() // which again was called by the dispatchable itself, just having removed us from its list vt->m_disp.remove_dispatcher_change_notify_callback(data); } // remove the validity trackable from all sigc::trackables for_each(vt->m_trackables.begin(), vt->m_trackables.end(), sigc::bind(sigc::mem_fun(&sigc::trackable::remove_destroy_notify_callback), vt) ); g_atomic_int_add(&vt->m_refcount, - (gint) vt->m_trackables.size()); vt->m_trackables.clear(); if (TRUE == g_atomic_int_dec_and_test(&vt->m_refcount)) delete vt; } } //static void* tunnel_validity_tracker::notify_from_trackable(void* data) { cleanup(data, true); return 0; } //static void tunnel_validity_tracker::notify_dispatcher_change(void* data) { cleanup(data, false); } void tunnel_validity_tracker::clear_connections(internal::validity_trackable* vt) { g_assert(vt->m_creator_thread == Glib::Thread::self()); // disconnect each sigx::connection_wrapper and ignore bad_dispatcher exceptions; // they would be thrown if the thread that owns the signal to which this connection // is related has ended and with it the signal was destroyed; // thus we can't disconnect anymore and there is no need to for_each(vt->m_connections.begin(), vt->m_connections.end(), sigc::exception_catch(sigc::mem_fun(&connection_wrapper::disconnect), bad_dispatcher_catcher()) ); vt->m_connections.clear(); } void tunnel_validity_tracker::do_bind_to_trackable(const sigc::trackable* t) const { g_assert(m_info->m_creator_thread == Glib::Thread::self()); t->add_destroy_notify_callback(m_info, &tunnel_validity_tracker::notify_from_trackable); m_info->m_trackables.push_back(t); // increase the reference count for the trackable ++m_info->m_refcount; } void tunnel_validity_tracker::add_connection(const connection_wrapper& c) { g_assert(m_info->m_creator_thread == Glib::Thread::self()); m_info->m_connections.push_back(c); } bool tunnel_validity_tracker::is_valid() const { //g_assert(m_info->dispatcher()->m_creator_thread == Glib::Thread::self()); return m_info->m_valid; } void tunnel_validity_tracker::activate() { g_assert(m_info->m_creator_thread == Glib::Thread::self()); g_assert(m_info->m_disp.dispatcher()); // add the validity_trackable to the dispatchable; // once for the destruction of the dispatcher m_info->m_disp.add_dispatcher_change_notify_callback(m_info, &tunnel_validity_tracker::notify_dispatcher_change); // validity_trackable added to dispatchable ++m_info->m_refcount; m_info->m_dispatcher_change_is_cleanup = 1; } } // namespace sigx sigx/src/operator_new.cpp0000644000175000017500000000252711131223155016721 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include "__sigx_pchfence__.h" namespace sigx { void* operator_new::operator new(std::size_t size) { // forward to global operator new() return ::operator new(size); } void operator_new::operator delete(void* p) { // forward to global operator delete() ::operator delete(p); } void* operator_new::operator new[](std::size_t size) { // forward to global operator new[]() return ::operator new[](size); } void operator_new::operator delete[](void* p) { // forward to global operator delete[]() ::operator delete[](p); } } // namespace sigx sigx/src/bad_dispatcher.cpp0000644000175000017500000000177611124207726017166 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/bad_dispatcher.h" #include "__sigx_pchfence__.h" namespace sigx { //virtual const char* bad_dispatcher::what() const throw() { return "dispatcher pointer is invalid, message can't be dispatched"; } } // namespace sigx sigx/src/connection_wrapper.cpp0000644000175000017500000001726111155006624020123 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #if 0 // rvalue references #include // std::move #endif #include #include #include #include #include "sigx/types.h" #include "sigx/connection_wrapper.h" #include "sigx/connection_handler.h" #include "sigx/signal_wrapper_base.h" #include "sigx/tunnel_functor.h" #include "__sigx_pchfence__.h" namespace sigx { connection_wrapper::connection_wrapper(): m_sigc_conn(), m_shared_disp(), m_sigcconn_refcount() {} connection_wrapper::connection_wrapper(const shared_dispatchable& _A_disp, const shared_sigc_conn_ptr& _A_conn): m_sigc_conn(_A_conn), m_shared_disp(_A_disp), m_sigcconn_refcount(new int(1)) {} connection_wrapper::connection_wrapper(const connection_wrapper& other) throw(): m_sigc_conn(other.m_sigc_conn), m_shared_disp(other.m_shared_disp), m_sigcconn_refcount(other.m_sigcconn_refcount) { if (m_sigcconn_refcount) g_atomic_int_inc(m_sigcconn_refcount); } #if 0 // rvalue references connection_wrapper::connection_wrapper(connection_wrapper&& other) throw(): m_sigc_conn(std::move(other.m_sigc_conn)), m_shared_disp(std::move(other.m_shared_disp)), m_sigcconn_refcount(other.m_sigcconn_refcount) { // destroy other other.m_sigcconn_refcount = 0; } #endif connection_wrapper::~connection_wrapper() throw() { try { destroy_self(); } catch (...) {} } void connection_wrapper::destroy_self() { if (m_sigcconn_refcount) { // test whether we are the last one pointing to the remote // sigc::connection and whether it's still valid; // destroy this connection if yes if (TRUE == g_atomic_int_dec_and_test(m_sigcconn_refcount)) { // make a local copy of the shared sigc connection pointer (nothrow) const shared_sigc_conn_ptr sigc_conn(m_sigc_conn); delete m_sigcconn_refcount; m_sigcconn_refcount = 0; m_sigc_conn.reset(); // destroying m_shared_disp is not part of self-destruction; // it will be destroyed by the dtor or assigned anew in operator = try { // note: we tunnel here a message to the static connection_handler::destroy() method to // destroy/delete the sigc connection object itself living at the server thread side; // // the sigc connection object itself is bound to the lifetime of the server thread. // the server thread keeps a sigc connection pointer (the address of the connection object // in a map where the address of the // connection pointer (not the object!) serves as a handle (key). // in order to ensure the lifetime of the connection pointer and thus its address (= handle) // we send the shared pointer to the connection pointer and turn it at the server thread's side // into the address of the connection pointer (a sigc::connection**) with a call // to shared_sigc_conn_ptr::get() - the destroy() function expects a sigc_connection_ptr* open_tunnel_with( sigc::compose( sigc::ptr_fun(&connection_handler::destroy), sigc::retype_return(sigc::mem_fun(&shared_sigc_conn_ptr::get)) ), m_shared_disp ) (sigc_conn); } catch (const bad_dispatcher&) { // silently ignore; // don't mind if the message can't get dispatched, the server // thread has probably already ended and deleted the // sigc::connection } // what about other exceptions? // well, in this case we find ourselves in a non-recoverable state because the // server thread didn't get the message to destroy the connection object. // The earliest point of destruction is the end of the server thread itself // (the lifetime of connection objects is bound to the server thread's lifetime); // the connection_wrapper object is cleaned up nevertheless... } } } connection_wrapper& connection_wrapper::operator =(const connection_wrapper& other) { if (this != &other) { destroy_self(); m_sigc_conn = other.m_sigc_conn; m_shared_disp = other.m_shared_disp; m_sigcconn_refcount = other.m_sigcconn_refcount; if (m_sigcconn_refcount) g_atomic_int_inc(m_sigcconn_refcount); } return *this; } #if 0 // rvalue references connection_wrapper& connection_wrapper::operator =(connection_wrapper&& other) { destroy_self(); m_sigc_conn = std::move(other.m_sigc_conn); m_shared_disp = std::move(other.m_shared_disp); m_sigcconn_refcount = other.m_sigcconn_refcount; // destroy other other.m_sigcconn_refcount = 0; return *this; } #endif bool connection_wrapper::empty() const { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return false; return open_sync_tunnel_with( sigc::mem_fun(&sigc::connection::empty), m_shared_disp // read volatile at the other side of the tunnel; )(sigc::ref(*m_sigc_conn)); } bool connection_wrapper::connected() const { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return false; return open_sync_tunnel_with( sigc::mem_fun(&sigc::connection::connected), m_shared_disp // read volatile at the other side of the tunnel; )(sigc::ref(*m_sigc_conn)); } bool connection_wrapper::blocked() const { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return false; return open_sync_tunnel_with( sigc::mem_fun(&sigc::connection::blocked), m_shared_disp // read volatile at the other side of the tunnel; )(sigc::ref(*m_sigc_conn)); } bool connection_wrapper::block(bool should_block /*= true*/) { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return false; return open_sync_tunnel_with( sigc::mem_fun(&sigc::connection::block), m_shared_disp // read volatile at the other side of the tunnel; // the ref() avoids copying the volatile pointer )(sigc::ref(*m_sigc_conn), should_block); } bool connection_wrapper::unblock() { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return false; return open_sync_tunnel_with( sigc::mem_fun(&sigc::connection::unblock), m_shared_disp // read volatile at the other side of the tunnel; // the ref() avoids copying the volatile pointer )(sigc::ref(*m_sigc_conn)); } void connection_wrapper::disconnect() { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return; return open_tunnel_with( sigc::compose( sigc::mem_fun(&sigc::connection::disconnect), sigc::mem_fun(&shared_sigc_conn_ptr::operator *) ), m_shared_disp // read volatile at the other side of the tunnel; // don't ref() because it's an async call )(m_sigc_conn); } connection_wrapper::operator bool() { if ((!m_sigcconn_refcount ) || (!g_atomic_pointer_get(&*m_sigc_conn) ) ) return false; return open_sync_tunnel_with( sigc::mem_fun(&sigc::connection::operator bool), m_shared_disp // read volatile at the other side of the tunnel; // the ref() avoids copying the volatile pointer )(sigc::ref(*m_sigc_conn)); } } // namespace sigx sigx/src/bad_sync_call.cpp0000644000175000017500000000214011124207732016766 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/bad_sync_call.h" #include "__sigx_pchfence__.h" namespace sigx { //virtual const char* bad_sync_call::what() const throw() { return "deadlock detected: caller thread wants to send a synchronous message to the server thread which in turn has just sent the caller thread an synchronous message"; } } // namespace sigx sigx/src/__sigx_pch__.cpp0000644000175000017500000000017411124202477016617 0ustar triendl.kjtriendl.kj#include #include #include #include "sigx/sigx.h" #include "__sigx_pchfence__.h" sigx/src/bad_caller.cpp0000644000175000017500000000174711124207724016276 0ustar triendl.kjtriendl.kj/* * Copyright 2008 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/bad_caller.h" #include "__sigx_pchfence__.h" namespace sigx { //virtual const char* bad_caller::what() const throw() { return "calling thread doesn't match creator thread"; } } // namespace sigx sigx/src/signal_wrapper_base.cpp0000644000175000017500000000367411124202477020236 0ustar triendl.kjtriendl.kj/* * Copyright 2006 Klaus Triendl * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "sigx/signal_wrapper_base.h" #include "sigx/signal_source_base.h" #include "sigx/tunnel_base.h" #include "__sigx_pchfence__.h" namespace sigx { signal_wrapper_base::signal_wrapper_base(): m_disp(), m_sigsource() {} signal_wrapper_base::signal_wrapper_base(const shared_dispatchable& _A_disp, const std::tr1::shared_ptr& _A_sigsource) throw(): m_disp(_A_disp), m_sigsource(_A_sigsource) {} signal_wrapper_base::~signal_wrapper_base() throw() {} std::pair > signal_wrapper_base::prepare_connection(const tunnel_base& _A_tunnel) const { // prepare a connection pointer; // note that the value '0x01' denotes a pending connection request std::tr1::shared_ptr refconnptr(new sigc_connection_ptr((sigc_connection_ptr) 0x01)); const connection_wrapper conn(m_disp, refconnptr); // add the connection_wrapper to the validity tracker of the tunnel functor. // This enables the validity tracker to disconnect the future slot connected // to this signal. _A_tunnel.validity_tracker().add_connection(conn); return std::make_pair(conn, refconnptr); } } // namespace sigx sigx/src/__sigx_pchfence__.h0000644000175000017500000000116411124213242017255 0ustar triendl.kjtriendl.kj// this file just exists as a fence for the precompiled headers; // with MSVC it doesn't even need to exist when pch is turned on, but as I // include it unconditionally it has to be present. // // I don't include any files here as 1) I don't want to impose any includes on // each cpp file and 2) the compilation will work without side effects // (performance etc...) if precompiled headers are turned off. // Rather __sigx_pchfence__.cpp includes everything that sigx needs and each // cpp file includes its own more accurate headers which also will be looked // up in the precomiled header file sigx-2.0.pch; sigx/docs/0000755000175000017500000000000011157535115013656 5ustar triendl.kjtriendl.kjsigx/docs/Doxyfile.in0000644000175000017500000002357411000401405015761 0ustar triendl.kjtriendl.kj# Doxyfile 1.4.5 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = sigx++ PROJECT_NUMBER = %MAJOR%.%MINOR%.%MICRO% OUTPUT_DIRECTORY = ./docs CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = NO STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 4 ALIASES = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO BUILTIN_STL_SUPPORT = NO DISTRIBUTE_GROUP_DOC = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = sigx \ src FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.py \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM \ *.PY RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = ./examples EXAMPLE_PATTERNS = *.h \ *.cpp EXAMPLE_RECURSIVE = YES IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = YES REFERENCES_RELATION = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO sigx/docs/manual/0000755000175000017500000000000011000222374015116 5ustar triendl.kjtriendl.kjsigx/docs/manual/glibmmx_manual.xml0000644000175000017500000002345610547567217020675 0ustar triendl.kjtriendl.kj glibmmx Klaus Triendl September 2006. glibmmx is a c++ template library that builds on glibmm and libsigc++ libraries to provide cross thread signalling. Introduction As soon as you enter the world of multithreaded programming you face the task of making threads doing a specific task or listening on events, the task of making your program threadsafe by synchronizing access to data shared by multiple threads and the need of interthread communication. glibmmx specializes in interthread communication and additionally offers types allowing you to do multithreaded programming at a high level. The name of the library originates in the intention to extend glibmm with a more sophisticated version of the Glib::Dispatcher. Its core comprehends of some key concepts that make it possible to implement the library within different environments; in its current version much of the higher level functionality is implemented on top of the sigc++ and glibmm libraries and therefore can be used natively as an extension to them, not to mention that it integrates perfectly into gtkmm and gnomemm based programs. glibmmx is not a cure to the problems that multithreading introduce but it is a powerful tool that helps you creating stable, multithreaded programs. Motivation glibmm already provides good facilities like Glib::Thread to handle threads, Glib::Mutex for data protection or the Glib::Dispatcher for interthread communication; sigc++ provides typesafe signals and callbacks; so, why another library? glibmmx simplifies common needs by creating conceptual types for even more threadsafety. E.g. it is a common need to protect an integer with a mutex; here, glibmmx comes into play with a type called "lockable" pairing an integer with a mutex, thus making the integer "lockable". More in the next chapters. glibmmx makes it very easy to create "thread objects", covering the common need to start and end the thread, get notified when the thread is idle and ready and setting up the dispatching mechanism. libsigc++ provides powerful, typesafe callbacks and signals but they are not threadsafe. They only work well in a single-threaded environment. Glib provides signals for various events like `SignalIdle", they too are not threadsafe. glibmmx provides threadsafe functors and representations of signals and connections. The Glib::Dispatcher provides a good way for interthread communication. But it is limited: although you can bind arguments to the invoked slot, you can only notify a thread that a "message" is waiting for it. glibmmx makes it possible to dispatch messages directly to a thread's handler function by introducing a "tunnel functor". glibmmx simplifies common needs by creating conceptual types for even more threadsafety. E.g. it is a common need to protect an integer with a mutex; here, glibmmx comes into play with a type called "lockable" pairing an integer with a mutex, thus making the integer "lockable". This integer still can't be accessed directly but only volatile. This is especially important for more complex types like classes: // somewhere class MyClass { public: void do_something() {} }; Glib::Mutex mtx; MyClass myclass; // somewhere else // not threadsafe, forgot to lock the mutex!! myclass.do_something(); This situation can't happen easily with glibmmx: // somewhere class MyClass { public: void do_something() {} }; GlibX::mutex_lockable<MyClass> lockable_myclass; // somewhere else // not threadsafe, forgot to lock the mutex!! // Luckily the compiler reports an error, because invoke() returns a reference // to a volatile MyClass and MyClass::do_something() is not qualified volatile. volatile MyClass& myclass = lockable_myclass.invoke(); myclass.do_something(); For example, you might have a two-tier application where server and client communicate over a network protocol. The server might send data every some seconds but you can't block the client as there might be a graphical user interface involved that would freeze everytime you listen to network events. Even if you would poll for new data you wouldn't want your GUI code be sprinkled and contaminated with network code. So, how do you tell your network thread to send a request to the server application and how do you receive messages from the network thread that in turn got them from the server application? LibSigC++ slots/signals alone are out of question because they are not threadsafe. The Glib Dispatcher is a great way to dispatch messages between two threads but it is limited in its use because it example A simple example So to get some experience, lets look at a simple example... I'd like to stick to my favourite example because it is based on a technique that I use in my own projects: an IP resolver. Of course we could elaborate on writing a typical "hello world" program but I think that you can follow better what's going on with a small, but real example. Let's assume that you have a firewall application that needs to resolve IP addresses to hostnames. The graphical user interface runs in the main thread whereas a dedicated thread resolves those IP addresses. We need two things: First, a window with an input field for the IP and a button to resolve it and second a resolver thread. Here's the window class: class TheGUI: public Gtk::Window, public GlibX::glib_auto_dispatchable { public: TheGUI(); private: // virtuals from Gtk::Widget virtual bool on_delete_event(GdkEventAny*); void on_gui_ready(); void on_resolve_clicked(); void on_resolved(const std::string& strHost, guint32 nIP); private: IPResolverThread m_resolver; GlibX::Connection m_connResolved; }; The first thing to note is that TheGUI is not only derived from Gtk::Window but also from GlibX::glib_auto_dispatchable. The glib_auto_dispatchable here does 2 things: 1) It creates automatically a Dispatcher running in the context of the main thread. (Note: A Dispatcher is responsible to dispatch messages from any thread to the receiver thread) 2) It enables TheGUI to participate automatically in interthread communication. (A dispatchable can be compared to a sigc::trackable that enables a derived class to notify slots of its destruction.) Further, we have 4 handlers: - on_delete_event: handler before closing the window; used to end the resolver thread - on_gui_ready: one-shot idle handler when the GUI is ready; used to connect to the resolver thread's signal `signal_resolved" - on_resolve_clicked: handler for the button; used to send the IP to the resolver thread. - on_resolved: handler that gets called for each resolved IP address. Next, we create a thread wrapper that allows us handle a thread very easily: class IPResolverThread: public GlibX::glib_threadable { protected: typedef sigc::signal<void, const std::string&, in_addr_t> signal_resolved_t; public: IPResolverThread(); protected: bool on_resolve(in_addr_t ip); public: GlibX::request_f<in_addr_t> resolve; GlibX::signal_f<signal_resolved_t> signal_resolved; private: struct ThreadData; Glib::Private<ThreadData> m_ThreadData; }; struct IPResolverThread::ThreadData { IPResolverThread::signal_resolved_t m_sigResolved; }; Wow! just a few lines for a whole thread! As you might already suppose, the core lies in the glib_threadable class; so what is it? 1) A thread wrapper object that provides the means to easily start and end a thread. 2) Creates a main loop and a context for that thread and sets up a dispatcher. 3) Implements a method that the thread can execute 4) Enables derived classes to participate automatically in interthread communication. The next important thing to mention is GlibX::request_f. request_f means "request functor". Let me explain what it is. Think one moment about how you would tell our resolver thread that it should resolve an IP address. The most natural thought is to write a request function "resolve" that sends a message over the message dispatcher to a method of our resolver thread. And this is exactly what request_f does! Instead of writing everytime a request function that tunnels a message to the other thread we just declare a request functor that has the dirty job done for us. Technically speaking, the request functor encapsulates the tunneling of a message to a method of the resolver thread. You may ask yourself how it works. It requires that you are familiar with functors. First, the request functor is initialized with a callback method and second it acts like a normal function to the caller. We will see below some lines of code. Reference See the reference documentation online sigx/docs/manual/manual_outline.txt0000644000175000017500000000075610547567217020732 0ustar triendl.kjtriendl.kj- introduction motivation; what glibmmx offers; - covering common needs - extending sigc++ - extending glibmm - locking facilities lockable; lock manager; locker; unlock; glibmm lockables; - dispatcher glib_dispatcher; other dispatchers; - dispatching dispatchable; glib_auto_dispatchable; threadmanaged_dispatchable; shared_dispatchable; - signals sigc signals; glibmm signals; connections; other signals; - threadable glib_threadable; other threadables; sigx/docs/internals.txt0000644000175000017500000000210310617333540016410 0ustar triendl.kjtriendl.kjsituations to cover: When connecting to a (server) thread's signal, a tunnel functor is sent from the client thread to the server thread. Thus, the server thread's signal holds a funtor with entities from the client thread like the dispatchable (and its dispatcher) and trackables eventually. The tunnel functor itself blocks tracking of trackables, but has a validity tracker to offer its own tracking mechanism. Note that if a tunnel functor is copied, the copy shares the same validity trackable. If something happens to these entities (when they go out of scope) or when either the client or the server thread ends or when the last tunnel functor holding the validity tracker goes out of scope (e.g. because the server thread ends or the functor is explicitly disconnected) then these situations must be managed to have a clean connection state. 1) A trackable goes out of scope 2) The dispatchable goes out of scope 3) The dispatcher goes out scope 4) The client thread finishes 5) The server thread finishes (and the functor is disconnected) 6) functor is explicitly disconnected sigx/examples/0000755000175000017500000000000011134706403014537 5ustar triendl.kjtriendl.kjsigx/examples/ipresolver/0000755000175000017500000000000011134707506016736 5ustar triendl.kjtriendl.kjsigx/examples/ipresolver/resolver.h0000644000175000017500000000564111000141330020731 0ustar triendl.kjtriendl.kj#ifndef RESOLVERTHREAD_H #define RESOLVERTHREAD_H #include #ifdef SIGC_MSC #include // in_addr_t is not defined on windows typedef ULONG in_addr_t; #else #include // in_addr #endif #include #include // Glib::Private #include #include #include /* Resolves IP addresses to host names. * * IP addresses are resolved by using gethostbyaddr(). * You can feed the resolver with addresses by calling resolve(). Results * are signaled after resolving with signal_resolved() to which you can * connect. * @attention Do not use two IPResolverThreads but only one instance because * gethostbyaddr() might not be threadsafe on some systems. */ class IPResolverThread: public sigx::glib_threadable { public: // convenience sigc::slot typedefs typedef sigc::slot slot_resolving_stopped_t; typedef sigc::slot slot_finished_t; typedef sigc::slot slot_resolved_t; protected: typedef sigc::signal signal_resolving_stopped_t; typedef sigc::signal signal_finished_t; typedef sigc::signal signal_resolved_t; public: IPResolverThread(); protected: // virtuals from sigx::glib_threadable virtual void on_startup(); virtual void on_cleanup(); /** @short marshalls the resolving requests and optimizes them * @note handler for resolve. */ void on_marshall_resolving(in_addr_t nIP); /** @short resolves an ip address to the hostname and emits a signal. @see signal_resolved */ bool resolve_next(); /** @short Resolves the specified ip address. * @return Resolving error. */ int resolve_this(in_addr addr); /** @short stops resolving and emits signal_resolving_stopped() when stopped. * @note handler for stop_resolving(). */ void on_stop_resolving(); public: /** @name request interface * All the requests you can send to this thread. */ //@{ /** @short resolves the provided ip. * * the result is broadcast with signal_resolved(). * * @note asynchronous */ sigx::request_f resolve; /** @short stops resolving. * * broadcasts signal_resolving_stopped() when stopped. * * @note asynchronous */ sigx::request_f<> stop_resolving; //@} /** @name signal interface * All the messages you can connect to. */ //@{ /** * @ingroup signal_api */ sigx::signal_f signal_resolving_stopped; /** * @ingroup signal_api */ sigx::signal_f signal_finished; /** emitted if resolving ended, no matter whether successful or not. * host constains an emtpy string if not successful. * for type of signal and slot @see signal_resolved_t */ sigx::signal_f signal_resolved; //@} private: struct ThreadData; Glib::Private m_ThreadData; }; #endif sigx/examples/ipresolver/resolver.cpp0000644000175000017500000001234711124211447021303 0ustar triendl.kjtriendl.kj#include #include #include #include #include #ifdef SIGX_MSC // windows and msvc++ # if (_WIN32_WINNT >= 0x0501) # include # else // must include for versions earlier than win xp # include # endif #else # include // AF_INET # include # include // hostent, gethostbyaddr, .. #endif #include #include "resolver.h" #include "resolver_p.h" using namespace std; #define DEBUG 1 IPResolverThread::ThreadData::ThreadData(): m_msgQueue(), m_connIdle(), m_nIPPrev(), m_strHost(), m_bStopResolving(), m_sigResolvingStopped(), m_sigFinished(), m_sigResolved() {} IPResolverThread::IPResolverThread(): sigx::glib_threadable(), m_ThreadData(), // request api resolve(sigc::mem_fun(this, &IPResolverThread::on_marshall_resolving)), stop_resolving(sigc::mem_fun(this, &IPResolverThread::on_stop_resolving)), // signal api, signals live in threadprivate data signal_resolving_stopped(*this, m_ThreadData, &ThreadData::m_sigResolvingStopped), signal_finished(*this, m_ThreadData, &ThreadData::m_sigFinished), signal_resolved(*this, m_ThreadData, &ThreadData::m_sigResolved) {} //virtual void IPResolverThread::on_startup() { // thread private pdata will be freed when the thread ends (according to the glib docs) m_ThreadData.set(new ThreadData); } //virtual void IPResolverThread::on_cleanup() { ThreadData* pthreaddata = m_ThreadData.get(); if (pthreaddata->m_connIdle.connected()) pthreaddata->m_connIdle.disconnect(); // tell others that I'm about to finish, even they might have joined me pthreaddata->m_sigFinished.emit(); } void IPResolverThread::on_stop_resolving() { ThreadData* pthreaddata = m_ThreadData.get(); pthreaddata->m_bStopResolving = true; pthreaddata->m_sigResolvingStopped.emit(); } void IPResolverThread::on_marshall_resolving(in_addr_t nIP) { ThreadData* pthreaddata = m_ThreadData.get(); if (pthreaddata->m_bStopResolving) return; const list::const_iterator it = find(pthreaddata->m_msgQueue.begin(), pthreaddata->m_msgQueue.end(), nIP); if (it == pthreaddata->m_msgQueue.end()) { // if ip is not yet in the message queue, append it pthreaddata->m_msgQueue.push_back(nIP); } // wait until we've got all messages; // if there are still messages in the dispatcher queue, // defer resolving. // the main purpose is to optimize this thread: // 1) resolving could take a longer time and there could be already // the "finish" message in the dispatcher queue. if we just blindly resolve // the next ip then we've got a problem. // 2) it could be that there are the same ips to resolve in the dispatcher // queue; we can skip them because everyone connected to the signal_resolved // gets the resolved ip and so we can speed up resolving // 3) if we would process messages all the time then this thread could end up in // a denial of service, so watch out for finish // // process other tunneled messages waiting in the dispatcher queue // (the IPResolverThread is a dispatchable and thus has a dispatcher) if (dispatcher()->queued_contexts() > 0) return; // upon receiving the next idle signal resolve the next IP if (!pthreaddata->m_connIdle.connected()) { pthreaddata->m_connIdle = maincontext()->signal_idle().connect( sigc::mem_fun(this, &IPResolverThread::resolve_next)); } } bool IPResolverThread::resolve_next() { ThreadData* pthreaddata = m_ThreadData.get(); const in_addr_t nIP = pthreaddata->m_msgQueue.front(); pthreaddata->m_msgQueue.pop_front(); in_addr addr = {}; addr.s_addr = nIP; int nErr(0); if ((pthreaddata->m_nIPPrev != nIP) || (pthreaddata->m_strHost.empty())) { // if the current ip differs from the previous one // or ip couldn't be resolved before pthreaddata->m_nIPPrev = nIP; if (DEBUG) { cout << "Resolving: " << inet_ntoa(addr) << endl; } nErr = resolve_this(addr); } else if (DEBUG) { cout << "Resolved: " << inet_ntoa(addr) << " to " << pthreaddata->m_strHost << endl; } pthreaddata->m_sigResolved.emit(pthreaddata->m_strHost, nIP, nErr); // the IPResolverThread is a dispatchable and thus has a dispatcher reference //if ((m_disp_ptr->invoke()->queued_contexts() > 0) || if ((dispatcher()->queued_contexts() > 0) || (pthreaddata->m_msgQueue.empty() ) ) { // disconnect from idle signal if there are messages waiting // in the dispatcher queue. there could be a "finish"-signal // waiting; // also disconnect if there are no addresses to resolve anymore; // this method will be triggered again by the next ip to resolve; return false; } // otherwise stay connected; return true; } int IPResolverThread::resolve_this(in_addr addr) { ThreadData* pthreaddata = m_ThreadData.get(); int nErr(0); #ifdef SIGC_MSC const hostent* phe = gethostbyaddr(inet_ntoa(addr), sizeof(in_addr), AF_INET); #else const hostent* phe = gethostbyaddr(&addr, sizeof(in_addr), AF_INET); #endif if (phe) { // resolved? if (DEBUG) { cout << "Resolved: " << inet_ntoa(addr) << " to " << phe->h_name << endl; } pthreaddata->m_strHost = phe->h_name; } else { nErr = h_errno; if (DEBUG) cerr << "not resolvable, error " << nErr << endl; pthreaddata->m_strHost.clear(); } return nErr; } sigx/examples/ipresolver/main.cpp0000644000175000017500000000145311124211434020356 0ustar triendl.kjtriendl.kj#include #include #include #include #include "thegui.h" #ifdef SIGC_MSC // windows and msvc++ # if (_WIN32_WINNT >= 0x0501) # include # else // must include for versions earlier than win xp # include # endif int main(int argc, char** argv) { // initialization Glib::thread_init(); WSADATA wsad = {}; // require socket library min version 1.1 WSAStartup(MAKEWORD(1, 1), &wsad); // scope for application { Gtk::Main theApp(argc, argv); TheGUI gui; theApp.run(gui); } WSACleanup(); return 0; } #else int main(int argc, char** argv) { // initialization Glib::thread_init(); // scope for application { Gtk::Main theApp(argc, argv); TheGUI gui; theApp.run(gui); } return 0; } #endif sigx/examples/ipresolver/thegui.cpp0000644000175000017500000001336711124211430020722 0ustar triendl.kjtriendl.kj#include #include #include #include #include #ifdef SIGC_MSC // windows and msvc++ # if (_WIN32_WINNT >= 0x0501) # include # else // must include for versions earlier than win xp # include # endif #else #include #include #endif #include #include "thegui.h" using namespace std; TheGUI::InfoDialog::InfoDialog(Gtk::Window& parent): Gtk::Dialog("", parent, true) { Gtk::HBox* hbox = Gtk::manage(new Gtk::HBox(false, 5)); Gtk::Image* ico = Gtk::manage(new Gtk::Image(Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG)); Gtk::Label* lbl = Gtk::manage(new Gtk::Label("The IP address resolver is still working.\nThis could take up to some minutes...")); hbox->pack_start(*ico, Gtk::PACK_SHRINK); hbox->pack_start(*lbl, Gtk::PACK_SHRINK); get_vbox()->add(*hbox); add_button(Gtk::Stock::STOP, Gtk::RESPONSE_OK); set_has_separator(); show_all_children(); } TheGUI::TheGUI(): Gtk::Window(), sigx::glib_auto_dispatchable(), m_resolver(), m_connResolved(), m_connResolvingStopped(), m_pentryIP(), m_pentryHostname(), m_ptvError() { Gtk::Label* pLabelIP = Gtk::manage(new Gtk::Label("IP Address:", Gtk::ALIGN_LEFT)); m_pentryIP = Gtk::manage(new Gtk::Entry); m_pentryIP->set_activates_default(); m_pentryIP->set_editable(false); Gtk::Label* plabelHostname = Gtk::manage(new Gtk::Label("Hostname:", Gtk::ALIGN_LEFT)); m_pentryHostname = Gtk::manage(new Gtk::Entry); m_pentryHostname->set_editable(false); Gtk::Label* plabelError = Gtk::manage(new Gtk::Label("Error:", Gtk::ALIGN_LEFT)); m_ptvError = Gtk::manage(new Gtk::TextView); m_ptvError->set_editable(false); Gtk::Button* pbtnResolve = Gtk::manage(new Gtk::Button(Gtk::Stock::CONVERT)); pbtnResolve->property_can_default() = true; Gtk::HBox* phboxIP = Gtk::manage(new Gtk::HBox(false, 5)); phboxIP->pack_start(*pLabelIP, Gtk::PACK_SHRINK); phboxIP->pack_start(*m_pentryIP); phboxIP->pack_start(*pbtnResolve, Gtk::PACK_SHRINK); Gtk::HBox* phboxHostname = Gtk::manage(new Gtk::HBox(false, 5)); phboxHostname->pack_start(*plabelHostname, Gtk::PACK_SHRINK); phboxHostname->pack_start(*m_pentryHostname); Gtk::HBox* phboxError = Gtk::manage(new Gtk::HBox(false, 5)); phboxError->pack_start(*plabelError, Gtk::PACK_SHRINK); phboxError->pack_start(*m_ptvError); Gtk::VBox* pvboxAll = Gtk::manage(new Gtk::VBox); pvboxAll->pack_start(*phboxIP, Gtk::PACK_SHRINK, 5); pvboxAll->pack_start(*phboxHostname, Gtk::PACK_SHRINK, 5); pvboxAll->pack_start(*phboxError, Gtk::PACK_SHRINK, 5); add(*pvboxAll); set_default(*pbtnResolve); show_all_children(); pbtnResolve->signal_clicked().connect(sigc::mem_fun(this, &TheGUI::on_resolve)); // one-shot idle handler Glib::signal_idle().connect(sigc::bind_return(sigc::mem_fun(this, &TheGUI::on_gui_ready), false)); // we connect to the resolver's signals in on_gui_ready() when the // resolver thread is started and ready } bool TheGUI::on_delete_event(GdkEventAny*) { m_pentryIP->property_editable() = false; // display an info dialog after 3 seconds if the program does not // end because the resolver is still resolving InfoDialog::threadsafe_type dlg(new InfoDialog(*this)); Glib::signal_timeout().connect( sigc::bind_return( sigc::bind( sigc::mem_fun(this, &TheGUI::on_display_infomessage), dlg ), false ), 3000 ); m_connResolved.disconnect(); cout << "waiting for resolver to stop resolving.." << endl; m_connResolvingStopped = m_resolver.signal_resolving_stopped().connect( sigc::bind( sigc::mem_fun(this, &TheGUI::on_resolving_stopped), dlg ) ); m_resolver.stop_resolving(); return true; // do not proceed } void TheGUI::on_gui_ready() { cout << "waiting for resolver to be ready" << endl; m_resolver.run(); m_connResolved = m_resolver.signal_resolved().connect( sigc::mem_fun(this, &TheGUI::on_resolved) ); cout << "connected to the resolver: " << boolalpha << m_connResolved.connected() << endl; m_pentryIP->set_editable(true); } void TheGUI::on_resolved(const std::string& strHost, guint32 nIP, int nErr) { m_pentryHostname->set_text(strHost); if (nErr) { const Glib::RefPtr pTextBuf = m_ptvError->get_buffer(); #ifdef SIGC_MSC char* pBuf(0); // FormatMessage returns the number of characters stored in the output buffer, excluding the terminating null character const DWORD nLen = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 0, nErr, 0, // must be a char** if FORMAT_MESSAGE_ALLOCATE_BUFFER is specified above reinterpret_cast(&pBuf), 0, 0 ); pTextBuf->set_text(Glib::locale_to_utf8(pBuf)); LocalFree(pBuf); #else pTextBuf->set_text(Glib::locale_to_utf8(hstrerror(nErr))); #endif } } void TheGUI::on_display_infomessage(InfoDialog::threadsafe_type pDlg) { if (pDlg->run() == Gtk::RESPONSE_OK) // user clicked "stop", don't wait for resolver thread hide(); } void TheGUI::on_resolving_stopped(InfoDialog::threadsafe_type pDlg) { cout << "resolver stopped resolving" << endl; // quit the info dialog eventually pDlg->response(Gtk::RESPONSE_DELETE_EVENT); m_connResolvingStopped.disconnect(); m_resolver.finish(); // now quit the main loop hide(); } void TheGUI::on_resolve() { m_pentryHostname->set_text(Glib::ustring()); m_ptvError->get_buffer()->set_text(Glib::ustring()); const Glib::ustring& strIP = m_pentryIP->get_text(); #ifdef SIGC_MSC const in_addr_t nIP = inet_addr(strIP.c_str()); if (nIP != INADDR_NONE) m_resolver.resolve(nIP); #else in_addr addr = {}; if (inet_aton(strIP.c_str(), &addr) != 0) m_resolver.resolve(addr.s_addr); #endif else { m_ptvError->get_buffer()->set_text("\"" + strIP + "\" is not a valid ip address"); cerr << ("\"" + strIP + "\" is not a valid ip address") << endl; } } sigx/examples/ipresolver/thegui.h0000644000175000017500000000176311000141345020364 0ustar triendl.kjtriendl.kj#include #include #include #include #include "resolver.h" class TheGUI: public Gtk::Window, public sigx::glib_auto_dispatchable { private: /* An info dialog that gets displayed if the resolver does not * stop in a timely fashion */ class InfoDialog: public Gtk::Dialog { public: typedef std::tr1::shared_ptr threadsafe_type; public: InfoDialog(Gtk::Window& parent); }; public: TheGUI(); private: // virtuals from Gtk::Widget virtual bool on_delete_event(GdkEventAny*); void on_gui_ready(); void on_resolve(); void on_resolved(const std::string& strHost, guint32 nIP, int nErr); void on_resolving_stopped(InfoDialog::threadsafe_type pDlg); void on_display_infomessage(InfoDialog::threadsafe_type pDlg); private: IPResolverThread m_resolver; sigx::connection_wrapper m_connResolved; sigx::connection_wrapper m_connResolvingStopped; Gtk::Entry* m_pentryIP; Gtk::Entry* m_pentryHostname; Gtk::TextView* m_ptvError; }; sigx/examples/ipresolver/resolver_p.h0000644000175000017500000000106311000141406021246 0ustar triendl.kjtriendl.kj#include #include #include #ifdef SIGC_MSC #include #else #include // in_addr_t #endif #include struct IPResolverThread::ThreadData { std::list m_msgQueue; sigc::connection m_connIdle; in_addr_t m_nIPPrev; ///< previous ip std::string m_strHost; bool m_bStopResolving; IPResolverThread::signal_resolving_stopped_t m_sigResolvingStopped; IPResolverThread::signal_finished_t m_sigFinished; IPResolverThread::signal_resolved_t m_sigResolved; ThreadData(); }; sigx/examples/SConscript0000644000175000017500000000111111126625144016546 0ustar triendl.kjtriendl.kj# -*- python -*- Import('env') localenv = env.Clone() localenv.Prepend(CPPPATH = "#") localenv.Prepend(LIBPATH = localenv['BUILDDIR']) localenv.Append(LIBS = localenv['VERSIONED_NAME']) #localenv.Append(PKG_CONFIG_TOP_BUILD_DIR = "#"); #env.Append(CXXFLAGS = ['-g']) gtkmm_env = localenv.Clone() gtkmm_env.ParseConfig('pkg-config --cflags --libs gtkmm-2.4 gthread-2.0') example_ipresolver = gtkmm_env.Program('example_ipresolver', [ 'ipresolver/main.cpp', 'ipresolver/resolver.cpp', 'ipresolver/thegui.cpp' ]) example_programs = [ example_ipresolver ] Return('example_programs') sigx/ChangeLog0000644000175000017500000004611711155007715014507 0ustar triendl.kjtriendl.kj2005-11-08 Tim Mayberry * glibmmx: initial version. 2006-01-29 Klaus Triendl * completed the reengineering of the tunnel handling and implementation. tunnels are now sigc++2.0 functor adaptors which eases their usage and integrates well in the sigc++'s way of doing things; * Additionally, the api is easier to use, open_tunnel accepts every kind of functor, the type of arguments is deduced when the functor is called, i.e. tunnel functors are real sigc++ adaptors * tunnels can be synchronous or asynchronous. * renamed TunnelFunctor to TunnelContext * renamed TunnelFunctor(0..7) to tunnel_context (which is a template specialization for different kind of tunnels * added tunnel_functor (note: this is not the former TunnelFunctor(0..7) but is a sigc++ adaptor * changes to open_tunnel: - returns a tunnel_functor instead of a sigc::slot - parameter reordering - accepts every kind of functor - an asynchronous/synhronous tunnel can be created by specifying the template argument GlibX::SYNC or GlibX::ASYNC; asynchronous tunnels are created by default * removed call_it * removed template function tunnel(), tunnels can only be opened by open_tunnel() * moved the Glib::Cond member from GlibX::Dispatcher to GlibX::StandardDispatcher because it was only used there 2006-05-28 Klaus Triendl * added threadsafe signaling on top of sigc++ 1) Signal: a wrapper to a sigc::signal 2) SignalReference: a threadsafe reference to a Signal 3) ConnectionReference: a threadsafe reference to a sigc::connection * has now an interesting example: ipresolver * added option 'SHAREDLIB' to SConstruct to allow switching between shared and static library builds * needs a boost::shared_ptr, added dependency to boost/shared_ptr.hpp 2006-06-04 Klaus Triendl * improved the documentation by grouping the classes and adding documentation; still some work needs to be done, though 2006-06-05 Klaus Triendl * bugfix: synchronous TunnelContexts did not lock in the correct order (tunnel() locked the mutex for the condition after and invoke()) * bugfix: Dispatcher ctor did not initialize m_queued_contexts; initializes now all members explicitly 2006-06-06 Klaus Triendl * improved example "ipresolver", now tells the user if the resolver thread is blocking and can't be finished because it still tries to resolve something 2006-06-11 Klaus Triendl * removed parameter bSync from threadable::finish() * threadable::finish() is now threadsafe, the first thread aquiring the mutex joins the thread * made lockable non-copyable 2006-07-02 Klaus Triendl * added template struct `auto_tunneler" and template struct `is_functor_tunneled" to facilitate auto tunneling of functors at compile time * redesigned threadable; follow Tim's suggestion and provide virtual methods on_startup() and on_cleanup() instead of letting derived classes override on_run() and on_finish() * complete rework of the documentation for threadable * cleaned up the ipresolver example and added it to the reference documentation * follow Tim's advice to use glib atomic operations for counting the tunnel contexts (messages) in the dispatcher queue in favor of using sig_atomic_t that is not garanteed to be threadsafe on all platforms; thus removing dependency to 2006-07-16 Klaus Triendl * added template functor `request" to facilitate message dispatching when "requesting" a threadable to do something. 2006-07-22 Klaus Triendl * added class noncopyable (namespace internal) to facilitate the non-copyable idiom * remove threadable::on_finish() as handler for the `finish" message; finish() now uses a composite functor calling quit() on the mainloop 2006-07-23 Klaus Triendl * improved macros: - using defines _R_, _P_ and _T_ (sigc::type_trait<>::take, sigc::type_trait<>::pass, sigc::type_trait<>::type) - simplified and generalized creation of tunnel contexts * improved documentation for tunnel contexts * bugfix (compile time): synchronous tunnel contexts did not define correct std::auto_ptr template for self-deletion thus resulting in a compiler error when constructing the std::auto_ptr with `this" * asynchronous tunnel contexts now also use a std::auto_ptr for self-deletion; this ensures proper deletion of the tunnel context even when exceptions are thrown. 2006-08-18 Klaus Triendl * renamed referenced_dispatchable to shared_dispatchable * renamed open_tunnel_sync() to open_sync_tunnel() * removed dependency to boost::shared_ptr; I've implemented my own sharing mechanism for the dispatchable's dispatcher pointer 2006-08-26 Klaus Triendl * added request_f (request functor) to facilitate sending messages to a thread * reengineered completely the signal handling and implementation: + removed SignalBase, Signal, SignalBaseReference, SignalReference + added signal_f_base, signal_f, signal_base, signal, signal_source_base, signal_source_threadprivate, signal_source_obj_mem, signal_source_slot, ConnectionHandler, TypedConnectionHandler + 1) signal_f acts as a mediator between two threads such that the client thread gets a threadsafe copy of a server thread's signal 2) a signal_source_base abstracts completely the origin of a server thread's signal, thus enabling the programmer to specify different sources for a signal. + GlibX::Signal specialization for Glib::SignalIdle; SignalTimeout, SignalIO and SignalProxy will follow soon; allow a programmer to connect a client thread with these signals of a server thread * improved locking facilities: + renamed lockable to lockable_base, lockable_type to lockable + made a lockable's encapsulated type volatile + a lockable is now template specialized for a "lock", e.g. a mutex or a read/write lock; this approach generalizes programming with locks and locked types; there are predefined lockables specialized for a specific lock: static_mutex_lockable, mutex_lockable, static_rw_lockable, rw_lockable, static_recmutex_lockable, recmutex_lockable + added classes Locker and ConstLocker to lock a lockable, nonvolatile access to the locked type with unlock() * tunnel_context now throws exception `bad_dispatcher" in case that the pointer to the dispatcher is invalid (message cannot get dispatched to the server thread) * added concept classes: noncopyable, nonheapcreatable, noninstantiatible, operator_new 2006-08-26 Klaus Triendl * renamed managed_dispatchable to threadmanaged_dispatchable, much clearer * splitted auto_dispatchable: auto_dispatchable is now a baseclass with protected access, added glib_auto_dispatchable that does the right job: creating a GlibDispatcher * Dispatcher must be created and destroyed by the thread in who's context the dispatcher is acting * Dispatcher now inherits from operator_new to ensure heap allocation happens in the glibmmx module (needed for windows) 2006-09-02 Klaus Triendl * added deadlock detection: throw an exception if a thread sends a synchronous message to itself or to a thread that in turn has a synchronous message pending to the sending thread 2006-09-03 Klaus Triendl * added GlibX::Signal specialization for SignalTimeout, SignalIO and SignalChildWatch 2006-09-03 Klaus Triendl * little bit of documentation 2006-09-12 Klaus Triendl * GlibX::Signal now can be template specialized for a group of signal types: Glib::SignalNormalProxy and sigc::signal_base derived signals and irrelevant grouping; This allows you to connect to Glib::SignalProxyN signals, e.g. to a Gtk::Button::signal_clicked() if that signal is exposed by a signal functor (signal_f) 2006-09-14 Klaus Triendl * small bugfixes for some signal_f ctors * object instances for signal sources can now be late bound; This is achieved by pointer references to objects ( T_obj*& ) 2006-09-21 Klaus Triendl * added internal::shared_ptr (unwillingly but necessarily) * Signal::connect* methods are now asynchronous; this is achieved by sharing a pointer to a connection (internal::shared_ptr) that is transferred to the server thread. The actual sigc::connection to which the shared connection pointer points to is then created later by the server thread. I call this "late binding" of an instance to a shared pointer This means effectively that connecting to a signal is now asynchronous. 2006-09-25 Klaus Triendl * signal_f::operator () is now asynchronous; this is achieved by sharing a pointer to a signal source (internal::shared_ptr) that is transferred to the server thread. The actual signal source to which the shared signal source pointer points to is also transferred to the server thread where it is then bound to the server thread's lifetime I call this "late binding" of an instance to a shared pointer. This means effectively that getting a threadsafe representation of a signal is now asynchronous. 2006-10-18 Klaus Triendl * remove constraint_toplevel_functor() (replaced by SIGX_STATIC_ASSERT) * add is_or_adapts_slot to find out at compile time whether a functor is a slot itself or contains a functor adapting a slot * add SIGX_STATIC_ASSERT to issue clearer compile time error messages at function scope * Signal::connect and Signal::connect_notify now ensure with SIGX_STATIC_ASSERT that no slots are connected 2006-10-21 Klaus Triendl * Thanks to Tim's idea (PDB::Dispatcher::run()), glib_threadable::run() now blocks until the thread is in a running state 2006-10-21 Klaus Triendl * If a thread sends a synchronous message to itself then this case is detected as a deadlock detection, too * request functors now don't accept slots, adapted slots and tunnel functors that are not toplevel 2007-01-06 Klaus Triendl * renamed namespace GlibX to sigx * added export/import declaration to classes exported from the DLL on windows * created a solution for MSVC++ 2005: - the library builds now successfully on windows - ipresolver example runs on windows - tests compile and run on windows - macro files compile to hpp files * added sigxconfig.hpp * scons doesn't doesn't substitute anymore macros in *.hpp.in files, rather m4 creates the hpp-files directly (added a macro definition for the copyright) * put tunnel_functor's members into tunnel_base * added sigxconfig.hpp (has still to be done for linux) to get machine and sigc++ configuration * added validity tracking for tunnel functors (message is not dispatched anymore if dispatchable of callback goes out of scope; also, all connected tunnel functors are d * renamed sigx::signal to sigx::signal_wrapper * now, sigx::connectionS share a pointer to a sigc::connection (the sigc::connection lives in the context of the server thread) * now, sigx::signal_wrapperS share the signal source (that accesses a signal living in the context of the server thread) 2007-01-06 Klaus Triendl * added visual c++ project test_static_assert * tunnel callbacks are now invalidated when dispatcher goes out of scope, not when the dispatchable dies * signal_f takes a sigc::(const_)reference_wrapper for late binding objects to pointer variables 2007-01-08 Klaus Triendl * SConstruct tests for available std::tr1::shared_ptr or boost::shared_ptr; they take precedence over the sigx::internal::shared_ptr because they are perfectly configured for many environments 2007-07-22 Klaus Triendl * renamed directories and scons variables from "glibmmx" to "sigx" * added threadable 2008-03/2008-04 Klaus Triendl * changed validity tracking in tunnel functors: - must not activated anymore by default: tunnel_functorS are not subject to validity tracking otherwise explicitly requested (yielded problems with request_f and "on-the-fly" tunnels) - sigx::signal_wrapper::connect() activates it explicitly on tunnel_functorS * added solution for MSVC++ 2008 (note however that heap debug assertions happen at the end of the program when executing example and test programs) * renamed *.hpp to *.h * added sigx::ref, like sigc::ref but overloaded for reference wrappers * added make_new_tunnel_context, enables us to let the compiler deduce the correct functor for a full tunnel_context specialization * refactored tunnel_context: - specialize template on functor type instead of argument types, eases the creation of tunnel_contextS, less specializations - no need for tunnel_context.h.m4 * refactored tunnel_functor: - use sigc::bind together with sigx::ref for easy creation of tunnel_contextS * removed shared_ptr.h, shared_ptr functionality is too complex and tr1 is almost at hand or easily available in boost * require availability of (shared_ptr) * require availability of boost (needed for mpl) * made scons target "tests" * made scons target "examples" 2008-03/2008-04-12 Klaus Triendl * renamed sigx::connection to sigx::connection_wrapper to be in sync with signal_wrapper * added test program test_sync_async_argument_passing * derive sigx::request_f protected from sigc::slot and make sigc::slot::operator() explicitly public with a using directive 2008-03/2008-04-13 Klaus Triendl * renamed sigx::threadmanaged_dispatchable to sigx::manual_dispatchable 2008-05-05 Klaus Triendl * sigx::connection_wrapper doesn't cache the connection status anymore * ... which means one variable less, leading to a bugfix: connection_wrapper could have leaked (under very low memory conditions, though) * for the glib debug message facilities include instead of ; that's not the nicest way but the official one and fixes a compilation error because gassert() was moved from gmessages.h to gtestutils.h in glib-2.16 2008-05-07 Klaus Triendl * bugfix for sigx::connection_wrapper::operator =: prevent self-assignment * renamed cpp macro DISPATCH_WITH_FUNCTOR to SIGX_DISPATCH_WITH_FUNCTOR * removed unused sigx::conditional_functor, a functor adaptor executing the adapted functor only if a condition evaluates to true * consolidated open_tunnel() functions * connection_handler now stores plain pointer to a sigc::connection instead of a shared_ptr in the threadspecific connections * modifications to the construction script: - pull in the whole environment as construction variables - ... and replace them with any explicitly provided commandline options - write the c++ compiler in use 2008-05-11 Klaus Triendl * signal_wrapper<>::connect() now calls new protected template method signal_wrapper_base::connect() that contains the common code for all signal types * bugfix for tunnel_validity_tracker::on_last_functor(): reference count for the validity_trackable was not decreased and prevented the validity_trackable to be destroyed (memory leaks!) * added validity tracking to connection_wrapper such that it can be used even after restarting a threadable * when checking in the initial repository msvc test projects were missing in the source tree (though the projects were in the solution) * new test program test_connection_handling to test connections after restarting a thread * bugfix: dispatchable's ctor could have leaked allocated resources 2008-05-11 Klaus Triendl * moved msvc project for sigx++2 into its own subdirectory * all intermediate build output goes into a projects $(ConfigurationName) subdirectory * all final build output (exe, dll, pdb) goes into $(SolutionDir)$(ConfigurationName) subdirectory * added nothrow hint to connection_wrapper's, signal_wrapper_base's, signal_wrapper's, dispatchable's and shared_dispatchable's ctors 2008-12-21 Klaus Triendl * tested sigx with libraries and modules from the newest gtkmm (2.14) installer for windows; they added modules linked against the vc9 runtime and the heap problem with gtkmm applications is gone * use new MSVC property sheets from the newest gtkmm installer * added copyright to .h and .cpp files where it was missing (thx to Chow Loong Jin ) * updated address of the Free Software Foundation in the copyright (thx to Chow Loong Jin ) * added DESTDIR to SConstruct, useful for making binary packages (thx to Chow Loong Jin ) * env.CXXFLAGS got quoted when appending flags (SConstruct), now convert to an array first (thx to Chow Loong Jin ) 2008-12-23 Klaus Triendl * added precompiled header facilities (__sigx_pchfence__.h, __sigx_pch__.cpp) - pch has a huge impact on compilation time * MSVC projects use precompiled headers for sigx to speed up the compilation process * changed MSVC projects to match the output file naming convention of the gtkmm installer -> sigx-vc{80|90}[-d]-2_0.{dll|lib} 2008-12-24 Klaus Triendl * modified and added debian/SConscript (thx to Jacek Wolszczak [shutdownrunner@o2.pl]) * removed old MSVC property sheets 2008-12-29 Klaus Triendl * prevent removal of header files generated by the m4 builder and sigx-2.0.pc, sigxconfig.h and docs/Doxyfile generated by the SubstInFile builder by using the scons' NoClean function 2008-12-31 Klaus Triendl * added a VersionedSharedLibrary method from Richard Levitte appending the version to the shared library and setting the correct SONAME on various systems * Depend on scons >=0.98 (NoClean is available in 0.97, AddMethod in 0.98) 2008-01-04 Klaus Triendl * add (this == &other) check to dispatchable::operator =() 2008-01-07 Klaus Triendl * increased release version: 2.0.1 * class operator_new got operator new[]() and operator delete[]() 2008-01-08 Klaus Triendl * create and install versioned shared library on posix systems with the soname correctly set (replaced Levitte's VersionedSharedLibrary builder with a combination of the tools 'versionedlibrary' and 'symlink' from the eugene project and my own) 2008-01-18 Klaus Triendl * updated sigx.pc.in, contained old library name 'glibmmx' and the old project link * add distclean target, removes sigx-2.0.pc, sigxconfig.h, docs/Doxyfile 2009-02-14 Klaus Triendl * fixed compiler errors when calling g_atomic_pointer_set() on target architectures (e.g. powerpc) not supporting atomic read/write of integer variables: g_atomic_pointer_set is a macro expanding on those architectures to a function where arguments get checked then by the compiler, on other target machines it just expands to a simple assignment sigx/AUTHORS0000644000175000017500000000017511000134137013763 0ustar triendl.kjtriendl.kjKlaus Triendl Tim Mayberry on whose initial version of glibmmx I developed sigx++. sigx/INSTALL0000755000175000017500000000003410547571534013766 0ustar triendl.kjtriendl.kjBasic Install scons installsigx/NEWS0000644000175000017500000000000011000133646013401 0ustar triendl.kjtriendl.kjsigx/sigx.pc.in0000644000175000017500000000063211134670244014630 0ustar triendl.kjtriendl.kjprefix=%PREFIX% exec_prefix=${prefix} libdir=${exec_prefix}/lib includedir=${prefix}/include Name: sigx++ Description: An interthread communication library for c++ on top of libsigc++ and glibmm Version: %MAJOR%.%MINOR%.%MICRO% URL: http://www.assembla.com/spaces/sigx Requires: glibmm-2.4 gthread-2.0 Libs: -L${libdir} -l%VERSIONED_NAME% Cflags: -I${libdir}/%VERSIONED_NAME% -I${includedir}/%VERSIONED_NAME% sigx/COPYING0000755000175000017500000006364410547571534014010 0ustar triendl.kjtriendl.kj GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. ^L Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. ^L GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. ^L Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. ^L 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. ^L 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. ^L 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. ^L 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS ^L How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! sigx/SConstruct0000644000175000017500000003262711157535055014775 0ustar triendl.kjtriendl.kj# -*- python -*- # SConstruct # libsigx build script # # Process this file with 'scons' to build the project. # For more information, please visit: http://www.scons.org/ . # # Usage: # # . scons build the library # . scons -h see available configuration options # . scons opt=value set a configuration option # . scons install install library and include files (as root) # . scons tests build test programs # . scons examples build example programs # . scons dist build a source package (.tar.bz2) ## . scons docs build documentation for the project (Doxygen) # . scons debian help building a debian package, read and change the SConscript file in the debian/ directory! # . scons -c clean intermediate files # . scons -c distclean clean all target files # # scons version >0.98 is required, we need the NoClean function (0.97) and the AddMethod function (0.98) EnsureSConsVersion(0, 98) #import commands import os, sys, re, string, glob, SCons.Node.FS SConsignFile() def Check_cxx_shared_ptr(context): context.Message('Checking for std::tr1::shared_ptr ...') ret = context.TryCompile(""" #include int main() { std::tr1::shared_ptr p(new int(42)); return 0; } """, '.cpp') context.Result(ret) return ret subst_dict = { } config_subst_dict = { } ############# # Options # ############# # explicit Command line options opts = Options('options.cache') opts.AddOptions( ('DESTDIR', 'Destination root directory (useful for package maintainers)', ''), PathOption('PREFIX', 'Installation prefix directory', '/usr/local'), BoolOption('DEBUG', 'Debug version (useful for developers only)', 0), BoolOption('SHAREDLIB', 'build a shared library, otherwise a static library', 1), ("TR1_INCLUDE_PATH", "Include path for c++ tr1\n(if your compiler has no tr1 or tr1 isn't in the standard include path)"), ("BOOST_INCLUDE_PATH", "Include path for c++ boost\nif boost isn't in the standard include path)") ) ############################### # Configuration Environment # ############################### # pull the whole environment in as construction variables; # this allows us to get various environment variables like CXX, CXXFLAGS construction_vars = os.environ.copy() # ... and update the construction variables with explicitly specified arguments construction_vars.update(**ARGUMENTS) env = Environment(options = opts, tools = ['default', 'versionedlibrary', 'symlink'], ENV = os.environ, **dict(construction_vars)) if env.has_key('TR1_INCLUDE_PATH'): env.Append(CPPPATH = env['TR1_INCLUDE_PATH']) if env.has_key('BOOST_INCLUDE_PATH'): env.Append(CPPPATH = env['BOOST_INCLUDE_PATH']) # don't configure when cleaning if not env.GetOption('clean'): conf = Configure(env, custom_tests = { 'Check_cxx_shared_ptr' : Check_cxx_shared_ptr }) env.Append(SIGX_HAVE_CXX_SHARED_PTR = conf.Check_cxx_shared_ptr()) env.Append(SIGX_HAVE_BOOST = conf.CheckCXXHeader('boost/mpl/eval_if.hpp')) if not env['SIGX_HAVE_CXX_SHARED_PTR']: print ' header not found' Exit(1) if not env['SIGX_HAVE_BOOST']: print 'boost not found' Exit(1) env = conf.Finish() # remember whether user called: scons -c distclean if 'distclean' in COMMAND_LINE_TARGETS: do_distclean = True else: do_distclean = False env.Append(MAJOR='2', MINOR='0', MICRO='1') env.Append(PACKAGE_NAME = 'sigx') env.Append(VERSIONED_NAME = "%s-%s.%s" % (env['PACKAGE_NAME'], env['MAJOR'], env['MINOR'])) env.Append(CPPPATH = [ '#' ]) #env.Append(TARFLAGS = ['-c']) #env.Append(TARFLAGS = ['--bzip2']) # convert CXXFLAGS to an array because we append flags to it using lists if env.has_key('CXXFLAGS') and type(env['CXXFLAGS']) == str: env['CXXFLAGS'] = env['CXXFLAGS'].split(' '); if env['DEBUG'] == 1: env.Append(CXXFLAGS = ['-g']) env.Append(CXXFLAGS = ['-O0']) env.Append(CXXFLAGS = ['-W']) env.Append(CXXFLAGS = ['-Wall']) env.Append(CXXFLAGS = ['-ansi']) env.Append(CXXFLAGS = ['-pedantic']) env.Append(CXXFLAGS = ['-Wpointer-arith']) env.Append(CXXFLAGS = ['-Woverloaded-virtual']) env.Append(CXXFLAGS = ['-Wconversion']) env.Append(CXXFLAGS = ['-Wcast-align']) env.Append(CXXFLAGS = ['-Wshadow']) else: env.Append(CXXFLAGS = ['-O2']) env.Append(CXXFLAGS = ['-DG_DISABLE_ASSERT=1']) #-fomit-frame-pointer -fmove-all-movables -fstrict-aliasing # lib dependencies. # we do depend on sigc-2.0 and glibmm; # note that sigc is included in glibmm env.ParseConfig ('pkg-config --cflags --libs glibmm-2.4') # Generate help text for command line options Help(opts.GenerateHelpText(env)) # Cache current options opts.Save('options.cache', env) ############## # Builders # ############## def do_subst_in_file(targetfile, sourcefile, dict): """Replace all instances of the keys of dict with their values. For example, if dict is {'%VERSION%': '1.2345', '%BASE%': 'MyProg'}, then all instances of %VERSION% in the file will be replaced with 1.2345 etc. """ try: f = open(sourcefile, 'rb') contents = f.read() f.close() except: raise SCons.Errors.UserError, "Can't read source file %s"%sourcefile for (k,v) in dict.items(): contents = re.sub(k, v, contents) try: f = open(targetfile, 'wb') f.write(contents) f.close() except: raise SCons.Errors.UserError, "Can't write target file %s"%targetfile return 0 # success def subst_in_file(target, source, env): if not env.has_key('SUBST_DICT'): raise SCons.Errors.UserError, "SubstInFile requires SUBST_DICT to be set." d = dict(env['SUBST_DICT']) # copy it for (k,v) in d.items(): if callable(v): d[k] = env.subst(v()) elif SCons.Util.is_String(v): d[k]=env.subst(v) else: raise SCons.Errors.UserError, "SubstInFile: key %s: %s must be a string or callable"%(k, repr(v)) for (t,s) in zip(target, source): return do_subst_in_file(str(t), str(s), d) def subst_in_file_string(target, source, env): """This is what gets printed on the console.""" return '\n'.join(['Substituting vars from %s into %s'%(str(s), str(t)) for (t,s) in zip(target, source)]) def subst_emitter(target, source, env): """Add dependency from substituted SUBST_DICT to target. Returns original target, source tuple unchanged. """ d = env['SUBST_DICT'].copy() # copy it for (k,v) in d.items(): if callable(v): d[k] = env.subst(v()) elif SCons.Util.is_String(v): d[k]=env.subst(v) Depends(target, SCons.Node.Python.Value(d)) # Depends(target, source) # this doesn't help the install-sapphire-linux.sh problem return target, source subst_action = Action (subst_in_file, subst_in_file_string) subst_builder = Builder(action=subst_action, emitter=subst_emitter) env.Append (BUILDERS = {'SubstInFile' : subst_builder}) # # source tar file builder # def distcopy (target, source, env): treedir = str (target[0]) try: os.mkdir (treedir) except OSError, (errnum, strerror): if errnum != errno.EEXIST: print 'mkdir ', treedir, ':', strerror cmd = 'tar cf - ' # # we don't know what characters might be in the file names # so quote them all before passing them to the shell # all_files = ([ str(s) for s in source ]) cmd += " ".join ([ "'%s'" % quoted for quoted in all_files]) cmd += ' | (cd ' + treedir + ' && tar xf -)' p = os.popen (cmd) return p.close (); def tarballer (target, source, env): cmd = 'tar cjf ' + str (target[0]) + ' ' + str(source[0]) + " --exclude-from='sigx_tar_exclude_these_files.txt'" print 'running ', cmd, ' ... ' p = os.popen (cmd) return p.close () dist_bld = Builder (action = distcopy, target_factory = SCons.Node.FS.default_fs.Entry, source_factory = SCons.Node.FS.default_fs.Entry, multi = 1) tarball_bld = Builder (action = tarballer, target_factory = SCons.Node.FS.default_fs.Entry, source_factory = SCons.Node.FS.default_fs.Entry) env.Append (BUILDERS = {'Distribute' : dist_bld}) env.Append (BUILDERS = {'Tarball' : tarball_bld}) # Documentation generation system doxygen_builder = Builder(action = 'doxygen $SOURCE') env.Append(BUILDERS = { 'DoxygenDoc' : doxygen_builder }) # M4 builder # note that scons has a built-in m4 builder but I define here my own because # the built-in one feeds sigx's m4 files through stdin which produces the wrong # header file guard m4_builder = Builder(action = 'm4 -Imacros $SOURCE > $TARGET') env.Append(BUILDERS = { 'M4' : m4_builder }) ######################## # Installation rules # ######################## env.Append(INSTALL_PREFIX = env['DESTDIR'] + env['PREFIX']) env.Append(LIBDIR = "%s/lib" % env['INSTALL_PREFIX']) env.Append(LIBINCLUDEDIR = "%s/lib/%s/" % (env['INSTALL_PREFIX'], env['VERSIONED_NAME'])) env.Append(INCLUDEDIR = "%s/include/%s/sigx" % (env['INSTALL_PREFIX'], env['VERSIONED_NAME'])) installpaths = [ env['LIBDIR'], env['LIBINCLUDEDIR'], env['INCLUDEDIR'] ] ########################### # Configuration summary # ########################### debugging = "" if env['DEBUG']: debugging = "ON" else: debugging = "OFF" libtype = "" if env['SHAREDLIB']: libtype = "shared" else: libtype = "static" print "" print "+=================+" print "| CONFIGURATION |" print "+=================+" print "" print "Installation prefix : " + env['PREFIX'] print "libdir : " + env['LIBDIR'] print "libincludedir : " + env['LIBINCLUDEDIR'] print "includedir : " + env['INCLUDEDIR'] print "Debugging mode : " + debugging if env.has_key('TR1_INCLUDE_PATH'): print "tr1 include path : " + env['TR1_INCLUDE_PATH'] if env.has_key('BOOST_INCLUDE_PATH'): print "boost include path : " + env['BOOST_INCLUDE_PATH'] print "Library : " + libtype print "c++ compiler : " + env['CXX'] print "" ################# # Build rules # ################# # generate templates # Build directory if env['DEBUG']: BuildDir("#build/debug", 'src', duplicate = 0) buildDirectory = 'build/debug/' else: BuildDir("#build/release", 'src', duplicate = 0) buildDirectory = 'build/release/' # remember build directory for SConscript files env['BUILDDIR'] = buildDirectory Export('env') ######################### # Generate sigx.pc # ######################### subst_dict['%MAJOR%'] = env['MAJOR'] subst_dict['%MINOR%'] = env['MINOR'] subst_dict['%MICRO%'] = env['MICRO'] subst_dict['%PREFIX%'] = env['PREFIX'] subst_dict['%VERSIONED_NAME%'] = env['VERSIONED_NAME'] pcfilename = "%s.pc" % env['VERSIONED_NAME'] pcbuild = env.SubstInFile ( pcfilename,'sigx.pc.in', SUBST_DICT = subst_dict) ############################### # Generate sigxconfig.h # ############################### # substitute certain defines sin sigxconfig.h.in #config_subst_dict['#undef SIGX_HAVE_XYZ'] = '#define SIGX_HAVE_XYZ 1'; configbuild = env.SubstInFile('sigxconfig.h', 'sigxconfig.h.in', SUBST_DICT = config_subst_dict) ################### # Documentation # ################## #subst_dict['%TOP_SRCDIR%'] = env['ENV']['PWD'] doxybuild = env.SubstInFile ( 'docs/Doxyfile', 'docs/Doxyfile.in', SUBST_DICT = subst_dict) doxygen_path = '(doxygen-generated-files)' env.DoxygenDoc(doxygen_path, 'docs/Doxyfile') ####################### # build and targets # ####################### m4build = SConscript(os.path.join('macros', 'SConscript')) sigxbuild = SConscript(os.path.join(buildDirectory, 'SConscript')) test_programs = SConscript(os.path.join('tests', 'SConscript')) example_programs = SConscript(os.path.join('examples', 'SConscript')) debianpkg = SConscript(os.path.join('debian', 'SConscript')) # prevent removal of some target files when cleaning (scons -c); # they don't need to be regenerated every time # note: pcbuild + configbuild + doxybuild env.NoClean(m4build) if not do_distclean: env.NoClean(pcbuild + configbuild + doxybuild) Default(doxybuild) Default(pcbuild) Default(configbuild) Default(m4build) #Default(sigxbuild) Default(buildDirectory) # just a test function def InstallSymlink(env, dir, target, source): linksource = os.path.basename(str(source)) targets = [] for tgt in target: targets += env.SymbolicLink(os.path.join(dir, os.path.basename(str(tgt))), source) return targets #y = env.Install(env['LIBDIR'], sigxbuild[0]) #InstallSymlink(env, env['LIBDIR'], [sigxbuild[1], sigxbuild[2]], y) # note: assumes that sigxbuild is a list with 3 elements containing the output and two symlinks env.InstallVersionedLibrary(env['LIBDIR'], sigxbuild) env.Install(env['INCLUDEDIR'], glob.glob('sigx/*.h')) env.Install(env['LIBINCLUDEDIR'], glob.glob('sigxconfig.h')) env.Install(env['LIBDIR'] + '/pkgconfig', pcfilename) #tarball_path = 'sigx.tar.bz' #env.Tarball(tarball_path, ['.']) # Provide targets "install", "docs", "tests", "examples", "debian" (experimental) # ie. 'scons install', ... env.Alias('install', installpaths) env.Alias('docs', doxygen_path) env.Alias('tests', test_programs) env.Alias('examples', example_programs) env.Alias('debian', debianpkg) #env.Alias('tarball', tarball_path) # provide a distclean target: scons -c distclean, removing all target files if env.GetOption('clean'): env.Alias('distclean', ['.']) sigx/README0000644000175000017500000000660711000177365013613 0ustar triendl.kjtriendl.kjWelcome to sigx++, a interthread communication library on top of sigc++ and glibmm. It evolved out of glibmmx, an initial approach of Tim Mayberry to create such a library. Dependencies: ------------- * tr1 Most notably sigx++ needs c++ tr1 facitilites, more precisely to for std::tr1::shared_ptr, both when compiling sigx++ itself and when using it. shared_ptr is the only most standard compliant and general way for sharing objects between multiple threads and facilities. Note that boost has a tr1 include directory starting from version 1.34.0. If tr1 isn't in your compiler's or IDE's default include path you have to provide them to the build tools (see below). * boost mpl Also, for the build process, sigx++ needs access to the boost meta programming stuff in by now. If boost isn't in your compiler's or IDE's default include path you have to provide them to the build tools (see below). * sigc++ and glibmm Important dependencies to mention are of course sigc++ and glibmm as sigx++ provides facilities on top of them; * gtkmm gtkmm is needed for example and test programs. * m4 The gnu m4 macro tool Linux: ------ sigx++ uses scons as the build utility which is similar to the automake suite. The reason for this is simply because Tim used scons and I myself prefer it in the meantime over make because it seems much easier to use. That said, sigcx++ requires pyhton and scons to be installed on your system. Once you have set it up, you can run > scons -h from within the sigcx++ top directory for spitting out options you can provide to the build environment. You may have to set the tr1 and boost include paths depending on your environment. Then simply build the library with > scons [TR1_INCLUDE=] [BOOST_INCLUDE=] [DEBUG={1|0}] [PREFIX=] [SHAREDLIB={0|1}] sigc++ and glibmm stuff is determined by using the pkg-config tool. Installing it is as easy as typing > scons install Build test and example programs: > scons tests > scons examples Windows: -------- First, you have to get the gtk and gtkmm headers/libraries; one convenient way to install them is to use the installers from found at http://www.gtk.org/download-windows.html for the gtk+ stack bundle and http://www.gtkmm.org/download.shtml#Binary for a link to a gtkmm windows installer package (which includes glibmm and sigc++). You are free to use scons on windows, too; if yes then you can read section "Linux" for details. I didn't test scons on windows but it should be as easy to use as on linux. Additionaly there are projects for msvc2005 and msvc2008. There are project property sheets where you can easily adjust your include and library paths for gtk, sigc++/glibmm, gtkmm, tr1, boost and the gnu m4 tool in case you need to compile m4 macro files. Note that msvc2008 doesn't work well yet with glibmm - there are heap problems when a program ends. It's not sigx++'s problem, the error happens also without sigx++. Examples: --------- I think that there is a useful example included, namely an "ipresolver"; it's taken from the currently inactive firewall project "fireflier" and resolves IPs to hostnames, showing nicely how sigx++ can be used. Also, have a look at the test programs; test_button_click e.g. shows how a thread can connect to the GUI thread's "button_clicked" signal. sigx/build/0000755000175000017500000000000011157535147014032 5ustar triendl.kjtriendl.kjsigx/sigx_tar_exclude_these_files.txt0000644000175000017500000000101211135150233021352 0ustar triendl.kjtriendl.kjCVS* options.cache config.log *.o \.scon* build/debug* build/release* docs/html* docs/manual/html* examples/example_* Doxyfile debian* sigxconfig.h sigx-2.0.pc core* src/signals.cpp svn* \.svn* \.git* *.dll *.exe *.obj *.idb *.pdb *.ilk MSVC_Net2005/Debug* MSVC_Net2005/debug* MSVC_Net2005/Release* MSVC_Net2005/release* MSVC_Net2005/*/Debug* MSVC_Net2005/*/Release* MSVC_Net2008/Debug* MSVC_Net2008/debug* MSVC_Net2008/Release* MSVC_Net2008/release* MSVC_Net2008/*/Debug* MSVC_Net2008/*/Release* *.user *.ncb *.suo *.pyc sigx/sigxconfig.h.in0000644000175000017500000000200411155006552015634 0ustar triendl.kjtriendl.kj// take over from sigc++ #include // Detect common platforms #if defined(_WIN32) // Win32 compilers have a lot of variation #if defined(_MSC_VER) #define SIGX_MSC #define SIGX_WIN32 #define SIGX_DLL #elif defined(__CYGWIN__) #elif defined(__MINGW32__) #define SIGX_WIN32 #else //The Tru64 compiler complains about this "unrecognized preprocessing directive", but it should never get this far anyway. //#warning "libsigc++ config: Unknown win32 architecture (send me gcc --dumpspecs or equiv)" #endif #else #endif /* _WIN32 */ #ifdef SIGX_MSC // C++ exception specification ignored except to indicate a function is not __declspec(nothrow) #pragma warning(disable: 4290) #endif #ifdef SIGX_DLL #if defined(SIGX_BUILD) && defined(_WINDLL) #define SIGX_API __declspec(dllexport) #elif !defined(SIGX_BUILD) #define SIGX_API __declspec(dllimport) #else #define SIGX_API #endif /* SIGX_BUILD - _WINDLL */ #else #define SIGX_API #endif /* SIGX_DLL */ sigx/NOTES0000644000175000017500000000772211000137156013537 0ustar triendl.kjtriendl.kjImportant notices to understand sigx: When talking about threadsafe signaling we separate into a client thread and a server thread. When the client thread connects to a signal of the server thread, the server thread owns and manages the signals (which is up to the programmer at the moment, but it wouldn't be wise not to put the signal into a thread private data structure because sigx's thread objects are just convenience wrappers for threads) and the connections made to that signal. The client thread gets back a threadsafe representation of the connection and is able to manage the connection through the same API calls as with the sigc::connection. Because the server thread manages the connections, it must ensure proper cleanup of the connections but also must ensure that the connected tunnel functor (from the client thread) is disconnected if the server thread finishes if the client thread didn't disconnect beforehand. On connecting a tunnel functor to a server thread's signal, the tunnel functor's trackables and the dispatchable get bound to a validity trackable that the tunnel functor holds. The validity trackable is shared by the client thread's dispatchable and trackables and copies of the same tunnel functor. Each copy additionally increases a separate reference counter in the validity trackable and decreases it on destruction. The following situations must be managed: 1) client thread disconnects the functor explicitly through connection::disconnect() (client thread's functor will go out of scope) 2) client thread finishes (client thread's dispatcher will die) 3) client thread's dispatcher dies 4) client thread's dispatchable dies 5) client thread's trackable dies 6) server thread finishes (client thread's functors will go out of scope) 2), 3) - validity trackable gets notified and disconnects all connections stored in the validity trackable with sigx::connection_wrapper::disconnect(), which sends a message to the server thread. If the server thread sends a message to the client thread in the meantime the sending will fail with a bad_dispatcher exception which is caught by the wrapping sigc::exception_functor. - tunnel callback is NOT invalidated, stays valid - note: must still think about this point (whether connections should get disconnected) 4), 5) - validity trackable gets notified and disconnects all connections stored in the validity trackable with sigx::connection_wrapper::disconnect(), which sends a message to the server thread. If the server thread sends a message to the client thread in the meantime the sending will fail with a bad_dispatcher exception which is caught by the wrapping sigc::exception_functor. - tunnel callback is invalidated (validity trackable) - all registered trackables and the dispatchable get their connection to the validity trackable removed (this is done assuming that all trackables and the dispatchable live in the same client thread) 6) If the server thread dies then the signals will be destroyed if they live in a thread private data (which should be the case). If they live in the thread wrapper object (sigx::threadable) all the connections to the signal will be disconnected when the thread private data for the sigx::connectionS is destroyed. BTW: one thread wrapper object represents one thread! - on destruction of the signal connection the tunnel functor will be destroyed, too. If the functor gets destroyed it decreases a separate reference counter in the validity trackable (and the regular one of course, too). If that separate reference counter reaches 0 then a management message is sent to the client thread (through the client thread's dispatcher [shared by the client's shared_dispatchable]) that the last functor was destroyed and thus the client thread's dispatchable and the trackables can get disconnected from the validity trackable. This message is worked out in the context of the client thread. Should the client's dispatcher die before the message can be sent then the sender must catch the bad_dispatcher exception. sigx/MSVC_Net2008/0000755000175000017500000000000011155006534014612 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/m4.rules0000644000175000017500000000104711011773576016220 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/sigx++2.sln0000644000175000017500000001260211011776054016515 0ustar triendl.kjtriendl.kjMicrosoft Visual Studio Solution File, Format Version 10.00 # Visual C++ Express 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_ipresolver", "examples\ipresolver\ipresolver.vcproj", "{F3350287-57BB-4023-A531-D3CF6A877366}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_button_click", "tests\test_button_click\test_button_click.vcproj", "{483658C9-9EE0-41FB-BA20-A1184B5F2D5F}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_signal_idle", "tests\test_signal_idle\test_signal_idle.vcproj", "{BD31F5B6-D62D-4065-A9AB-A5ED13376C71}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_validity_tracking", "tests\test_validity_tracking\test_validity_tracking.vcproj", "{C4150050-5C55-4BCB-8E9C-F116A31F318A}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_static_assert", "tests\test_static_assert\test_static_assert.vcproj", "{9425AB1E-CECD-44F2-A75E-521B9E948543}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_sync_async_argument_passing", "tests\test_sync_async_argument_passing\test_sync_async_argument_passing.vcproj", "{53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_connection_handling", "tests\test_connection_handling\test_connection_handling.vcproj", "{383A6A36-58DE-4E74-A559-53D04DA818D4}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sigx-2.0", "sigx\sigx++2.vcproj", "{99826A14-2B47-4AB6-9A85-3D8A68E24FCD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {F3350287-57BB-4023-A531-D3CF6A877366}.Debug|Win32.ActiveCfg = Debug|Win32 {F3350287-57BB-4023-A531-D3CF6A877366}.Debug|Win32.Build.0 = Debug|Win32 {F3350287-57BB-4023-A531-D3CF6A877366}.Release|Win32.ActiveCfg = Release|Win32 {F3350287-57BB-4023-A531-D3CF6A877366}.Release|Win32.Build.0 = Release|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Debug|Win32.ActiveCfg = Debug|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Debug|Win32.Build.0 = Debug|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Release|Win32.ActiveCfg = Release|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Release|Win32.Build.0 = Release|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Debug|Win32.ActiveCfg = Debug|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Debug|Win32.Build.0 = Debug|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Release|Win32.ActiveCfg = Release|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Release|Win32.Build.0 = Release|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Debug|Win32.ActiveCfg = Debug|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Debug|Win32.Build.0 = Debug|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Release|Win32.ActiveCfg = Release|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Release|Win32.Build.0 = Release|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Debug|Win32.ActiveCfg = Debug|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Debug|Win32.Build.0 = Debug|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Release|Win32.ActiveCfg = Release|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Release|Win32.Build.0 = Release|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Debug|Win32.ActiveCfg = Debug|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Debug|Win32.Build.0 = Debug|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Release|Win32.ActiveCfg = Release|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Release|Win32.Build.0 = Release|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Debug|Win32.ActiveCfg = Debug|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Debug|Win32.Build.0 = Debug|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Release|Win32.ActiveCfg = Release|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Release|Win32.Build.0 = Release|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Debug|Win32.ActiveCfg = Debug|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Debug|Win32.Build.0 = Debug|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Release|Win32.ActiveCfg = Release|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal sigx/MSVC_Net2008/m4.vsprops0000644000175000017500000000035710630621156016575 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/boost_tr1.vsprops0000644000175000017500000000056211123525117020165 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/sigx/0000755000175000017500000000000011124233731015561 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/sigx/sigx-2.0.rc0000644000175000017500000000444211000150032017343 0ustar triendl.kjtriendl.kj// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 2,0,0,0 PRODUCTVERSION 2,0,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "The sigx++ development team (see AUTHORS)" VALUE "FileDescription", "A c++ interthread communication library" VALUE "FileVersion", "2.0.0" VALUE "LegalCopyright", "Distribution is under the LGPL (see COPYING)" VALUE "OriginalFilename", "sigx-2.0" VALUE "ProductName", "sigx++" VALUE "ProductVersion", "2.0.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED sigx/MSVC_Net2008/sigx/sigx++2.vcproj0000644000175000017500000003115211124234563020176 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/examples/0000755000175000017500000000000011011776025016430 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/examples/ipresolver/0000755000175000017500000000000011123520720020613 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/examples/ipresolver/ipresolver.vcproj0000644000175000017500000001227511123521437024247 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/tests/0000755000175000017500000000000011011776027015756 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_connection_handling/0000755000175000017500000000000011123517463023021 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_connection_handling/test_connection_handling.vcproj0000644000175000017500000001122311123517473031310 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/tests/test_signal_idle/0000755000175000017500000000000011123517463021270 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_signal_idle/test_signal_idle.vcproj0000644000175000017500000001112311123517473026025 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/tests/test_button_click/0000755000175000017500000000000011124263271021472 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_button_click/test_button_click.vcproj0000644000175000017500000001123611124263564026446 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/tests/test_validity_tracking/0000755000175000017500000000000011123517556022530 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_validity_tracking/test_validity_tracking.vcproj0000644000175000017500000001100711123517473030520 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/tests/test_sync_async_argument_passing/0000755000175000017500000000000011123517463024615 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_sync_async_argument_passing/test_sync_async_argument_passing.vcproj0000644000175000017500000001125311123517473034703 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/tests/test_static_assert/0000755000175000017500000000000011123517463021666 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2008/tests/test_static_assert/test_static_assert.vcproj0000644000175000017500000001105111123517473027021 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/gtkmm-vc90-d-2_4.vsprops0000644000175000017500000000434111123202022020734 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2008/gtkmm-vc90-2_4.vsprops0000644000175000017500000000431711123206444020532 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/0000755000175000017500000000000011155006546014612 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/m4.rules0000644000175000017500000000104711011773576016215 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/sigx++2.sln0000755000175000017500000001260111011775411016510 0ustar triendl.kjtriendl.kjMicrosoft Visual Studio Solution File, Format Version 9.00 # Visual C++ Express 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_ipresolver", "examples\ipresolver\ipresolver.vcproj", "{F3350287-57BB-4023-A531-D3CF6A877366}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_button_click", "tests\test_button_click\test_button_click.vcproj", "{483658C9-9EE0-41FB-BA20-A1184B5F2D5F}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_signal_idle", "tests\test_signal_idle\test_signal_idle.vcproj", "{BD31F5B6-D62D-4065-A9AB-A5ED13376C71}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_validity_tracking", "tests\test_validity_tracking\test_validity_tracking.vcproj", "{C4150050-5C55-4BCB-8E9C-F116A31F318A}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_static_assert", "tests\test_static_assert\test_static_assert.vcproj", "{9425AB1E-CECD-44F2-A75E-521B9E948543}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_sync_async_argument_passing", "tests\test_sync_async_argument_passing\test_sync_async_argument_passing.vcproj", "{53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_connection_handling", "tests\test_connection_handling\test_connection_handling.vcproj", "{383A6A36-58DE-4E74-A559-53D04DA818D4}" ProjectSection(ProjectDependencies) = postProject {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} = {99826A14-2B47-4AB6-9A85-3D8A68E24FCD} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sigx-2.0", "sigx\sigx++2.vcproj", "{99826A14-2B47-4AB6-9A85-3D8A68E24FCD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {F3350287-57BB-4023-A531-D3CF6A877366}.Debug|Win32.ActiveCfg = Debug|Win32 {F3350287-57BB-4023-A531-D3CF6A877366}.Debug|Win32.Build.0 = Debug|Win32 {F3350287-57BB-4023-A531-D3CF6A877366}.Release|Win32.ActiveCfg = Release|Win32 {F3350287-57BB-4023-A531-D3CF6A877366}.Release|Win32.Build.0 = Release|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Debug|Win32.ActiveCfg = Debug|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Debug|Win32.Build.0 = Debug|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Release|Win32.ActiveCfg = Release|Win32 {483658C9-9EE0-41FB-BA20-A1184B5F2D5F}.Release|Win32.Build.0 = Release|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Debug|Win32.ActiveCfg = Debug|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Debug|Win32.Build.0 = Debug|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Release|Win32.ActiveCfg = Release|Win32 {BD31F5B6-D62D-4065-A9AB-A5ED13376C71}.Release|Win32.Build.0 = Release|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Debug|Win32.ActiveCfg = Debug|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Debug|Win32.Build.0 = Debug|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Release|Win32.ActiveCfg = Release|Win32 {C4150050-5C55-4BCB-8E9C-F116A31F318A}.Release|Win32.Build.0 = Release|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Debug|Win32.ActiveCfg = Debug|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Debug|Win32.Build.0 = Debug|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Release|Win32.ActiveCfg = Release|Win32 {9425AB1E-CECD-44F2-A75E-521B9E948543}.Release|Win32.Build.0 = Release|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Debug|Win32.ActiveCfg = Debug|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Debug|Win32.Build.0 = Debug|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Release|Win32.ActiveCfg = Release|Win32 {53E8CE4B-3EA8-40AB-813B-A89C95F27DFC}.Release|Win32.Build.0 = Release|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Debug|Win32.ActiveCfg = Debug|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Debug|Win32.Build.0 = Debug|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Release|Win32.ActiveCfg = Release|Win32 {383A6A36-58DE-4E74-A559-53D04DA818D4}.Release|Win32.Build.0 = Release|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Debug|Win32.ActiveCfg = Debug|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Debug|Win32.Build.0 = Debug|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Release|Win32.ActiveCfg = Release|Win32 {99826A14-2B47-4AB6-9A85-3D8A68E24FCD}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal sigx/MSVC_Net2005/tests/0000755000175000017500000000000011011252564015746 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_static_assert/0000755000175000017500000000000011011660466021661 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_static_assert/test_static_assert.vcproj0000400000175000017500000001075111123523620027001 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/tests/test_sync_async_argument_passing/0000755000175000017500000000000011011775773024620 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_sync_async_argument_passing/test_sync_async_argument_passing.vcproj0000644000175000017500000001115311123523620034666 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/tests/test_validity_tracking/0000755000175000017500000000000011011775773022530 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_validity_tracking/test_validity_tracking.vcproj0000644000175000017500000001070711123523620030512 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/tests/test_button_click/0000755000175000017500000000000011123524763021474 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_button_click/test_button_click.vcproj0000644000175000017500000001113611124227631026435 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/tests/test_signal_idle/0000755000175000017500000000000011011775773021273 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_signal_idle/test_signal_idle.vcproj0000644000175000017500000001102311123523620026010 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/tests/test_connection_handling/0000755000175000017500000000000011012002151022772 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/tests/test_connection_handling/test_connection_handling.vcproj0000644000175000017500000001112311123523620031273 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/examples/0000755000175000017500000000000011000222373016413 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/examples/ipresolver/0000755000175000017500000000000011011775773020630 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/examples/ipresolver/ipresolver.vcproj0000755000175000017500000001232311124227631024241 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/m4.vsprops0000644000175000017500000000035710630621156016572 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/boost_tr1.vsprops0000644000175000017500000000056211123525104020156 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/gtkmm-vc80-d-2_4.vsprops0000644000175000017500000000420711120721430020737 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/sigx/0000755000175000017500000000000011123524657015567 5ustar triendl.kjtriendl.kjsigx/MSVC_Net2005/sigx/sigx-2.0.rc0000644000175000017500000000444211000150032017340 0ustar triendl.kjtriendl.kj// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 2,0,0,0 PRODUCTVERSION 2,0,0,0 FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x2L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "The sigx++ development team (see AUTHORS)" VALUE "FileDescription", "A c++ interthread communication library" VALUE "FileVersion", "2.0.0" VALUE "LegalCopyright", "Distribution is under the LGPL (see COPYING)" VALUE "OriginalFilename", "sigx-2.0" VALUE "ProductName", "sigx++" VALUE "ProductVersion", "2.0.0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED sigx/MSVC_Net2005/sigx/sigx++2.vcproj0000755000175000017500000003107711124234113020173 0ustar triendl.kjtriendl.kj sigx/MSVC_Net2005/gtkmm-vc80-2_4.vsprops0000644000175000017500000000416511120721430020521 0ustar triendl.kjtriendl.kj sigx/site_scons/0000755000175000017500000000000011157534672015106 5ustar triendl.kjtriendl.kjsigx/site_scons/site_tools/0000755000175000017500000000000011157535063017265 5ustar triendl.kjtriendl.kjsigx/site_scons/site_tools/versionedlibrary.py0000644000175000017500000000262611157534632023231 0ustar triendl.kjtriendl.kjimport SCons.Defaults def VersionedLibrary(env, target, major, minor, micro, source): major = int(major) minor = int(minor) micro = int(micro) targets = [] platform = env.subst('$PLATFORM') libname = env.subst('$SHLIBPREFIX') + target + env.subst('$SHLIBSUFFIX') soname = libname + ".%d" % major # copy SHLINKFLAGS - [:] splices the whole list/string shlinkflags = env['SHLINKFLAGS'][:] shlibsuffix = '${SHLIBSUFFIX}' + ".%d.%d.%d" % (major, minor, micro) # write soname into shared library; # TODO: other platforms? (for examples see Richard Levitte's VersionedSharedLibrary function) if platform == 'posix': shlinkflags.append('-Wl,-soname=%s' % (soname)) # make the shared library targets += env.SharedLibrary(target = target, source = source, SHLIBSUFFIX = shlibsuffix, SHLINKFLAGS = shlinkflags) # build symlinks # TODO: other platforms? (for examples see Richard Levitte's VersionedSharedLibrary function if platform == 'posix': targets += env.SymbolicLink(libname, targets[0]) targets += env.SymbolicLink(soname, targets[0]) return targets def InstallVersionedLibrary(env, dir, source): targets = [] targets += env.Install(dir, source[0]) targets += env.InstallSymlinks(dir, source[1:], source[0]) return targets def generate(env, **kw): env.AddMethod(VersionedLibrary, 'VersionedLibrary') env.AddMethod(InstallVersionedLibrary, 'InstallVersionedLibrary') def exists(env): return 1 sigx/site_scons/site_tools/symlink.py0000644000175000017500000000253311157534632021331 0ustar triendl.kjtriendl.kjimport os, errno class SymLink: def __init__(self, target, source): self.target = target self.source = source def symlink_action(target, source, env): if os.path.lexists(str(target[0])): os.remove(str(target[0])) old_wd = os.path.curdir abs_target = os.path.abspath(str(target[0])) abs_source = os.path.abspath(str(source[0])) prefix = os.path.dirname(os.path.commonprefix([abs_target, abs_source])) link_source = abs_source[len(prefix)+1:] os.symlink(link_source, str(target[0])) def symlink_string(target, source, env): return "Creating symbolic link %s to %s" % (str(target[0]), str(source[0])) def InstallSymlinks1(env, targetdir, target): targets = [] for tgt in target: linksource = os.path.join(dir, os.path.basename(str(tgt.source))) targets += env.SymbolicLink(os.path.join(dir, os.path.basename(str(tgt.target))), linksource) return targets def InstallSymlinks(env, dir, target, source): linksource = os.path.join(dir, os.path.basename(str(source))) targets = [] for tgt in target: targets += env.SymbolicLink(os.path.join(dir, os.path.basename(str(tgt))), linksource) return targets def generate(env, **kw): action = env.Action(symlink_action, symlink_string) env['BUILDERS']['SymbolicLink'] = env.Builder(action=action, single_source=True) env.AddMethod(InstallSymlinks, 'InstallSymlinks') def exists(env): return 1