X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fcrossthread.h;h=d172c9c60f65933df348e3130ab8ea74210b5d75;hb=95ccbc452f513a9d6f70de45bc413067e568364c;hp=b815cfd31953fffa3317869dfc058e1caed46c02;hpb=87726495c30f90554b5204b5385d17274a8fe93e;p=ardour.git diff --git a/libs/pbd/pbd/crossthread.h b/libs/pbd/pbd/crossthread.h index b815cfd319..d172c9c60f 100644 --- a/libs/pbd/pbd/crossthread.h +++ b/libs/pbd/pbd/crossthread.h @@ -20,38 +20,86 @@ #ifndef __pbd__crossthread_h__ #define __pbd__crossthread_h__ -#include -#include -#include - -template -void -call_slot_from_thread_or_dispatch_it (pthread_t thread_id, AbstractUI& ui, sigc::slot theSlot) -{ - /* when called, this function will determine whether the calling thread - is the same as thread specified by the first argument. if it is, - the we execute the slot. if not, we ask the interface given by the second - argument to call the slot. - */ +#ifdef check +#undef check +#endif + +#include + +#include "pbd/libpbd_visibility.h" + +/** A simple abstraction of a mechanism of signalling one thread from another. + * The signaller calls ::wakeup() to tell the signalled thread to check for + * work to be done. + * + * This implementation provides both ::selectable() for use in direct + * poll/select-based event loops, and a Glib::IOSource via ::ios() for use + * in Glib main loop based situations. + */ + +class LIBPBD_API CrossThreadChannel { + public: + /** if @a non_blocking is true, the channel will not cause blocking + * when used in an event loop based on poll/select or the glib main + * loop. + */ + CrossThreadChannel(bool non_blocking); + ~CrossThreadChannel(); + + /** Tell the listening thread that is has work to do. + */ + void wakeup(); + + /* if the listening thread cares about the precise message + * it is being sent, then ::deliver() can be used to send + * a single byte message rather than a simple wakeup. These + * two mechanisms should not be used on the same CrossThreadChannel + * because there is no way to know which byte value will be used + * for ::wakeup() + */ + int deliver (char msg); - if (pthread_self() == thread_id) { - theSlot (); - } else { - ui.call_slot (theSlot); - } -} - -template -sigc::slot -crossthread_safe (pthread_t thread_id, AbstractUI& ui, sigc::slot theSlot) -{ - /* this function returns a slot that will ensure that theSlot is either - called by the specified thread or passed to the interface via - AbstractUI::call_slot(). + /** if using ::deliver() to wakeup the listening thread, then + * the listener should call ::receive() to fetch the message + * type from the channel. + */ + int receive (char& msg); + + /** empty the channel of all requests. + * Typically this is done as soon as input + * is noticed on the channel, because the + * handler will look at a separately managed work + * queue. The actual number of queued "wakeups" + * in the channel will not be important. + */ + void drain (); + static void drain (int fd); + + /** File descriptor that can be used with poll/select to + * detect when wakeup() has been called on this channel. + * It be marked as readable/input-ready when this condition + * is true. It has already been marked non-blocking. + */ + int selectable() const { return fds[0]; } + + /* glibmm 2.22 and earlier has a terrifying bug that will + cause crashes whenever a Source is removed from + a MainContext (including the destruction of the MainContext), + because the Source is destroyed "out from under the nose of" + the RefPtr. I (Paul) have fixed this (https://bugzilla.gnome.org/show_bug.cgi?id=561885) + but in the meantime, we need a hack to get around the issue. */ - - return sigc::bind (sigc::ptr_fun (call_slot_from_thread_or_dispatch_it), - thread_id, ui, theSlot); -} + Glib::RefPtr ios(); + void drop_ios (); + + /** returns true if the CrossThreadChannel was + * correctly constructed. + */ + bool ok() const { return fds[0] >= 0 && fds[1] >= 0; } + + private: + Glib::RefPtr* _ios; // lazily constructed + int fds[2]; // current implementation uses a pipe/fifo +}; #endif /* __pbd__crossthread_h__ */