X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fpbd%2Fcrossthread.h;h=e87879e4a31bb9a36698b1f71cc9548919be8c43;hb=569167a603ef812a234d3c02f6a94976571a70ea;hp=413dea024e4c1c54c95795cd01523fab1798dfdd;hpb=7bbf76132164d3bd293c3bfdf2038dd47f1cc63b;p=ardour.git diff --git a/libs/pbd/pbd/crossthread.h b/libs/pbd/pbd/crossthread.h index 413dea024e..e87879e4a3 100644 --- a/libs/pbd/pbd/crossthread.h +++ b/libs/pbd/pbd/crossthread.h @@ -1,38 +1,108 @@ +/* + Copyright (C) 2000-2007 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + #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. - */ - - 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(). - */ - - return sigc::bind (sigc::ptr_fun (call_slot_from_thread_or_dispatch_it), - thread_id, ui, theSlot); -} +#ifdef check +#undef check +#endif + +#include + +#include "pbd/libpbd_visibility.h" + +#ifdef PLATFORM_WINDOWS +#include +#endif // PLATFORM_WINDOWS + + +/** 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 using ::deliver() to wakeup the listening thread, then + * the listener should call ::receive() to fetch the message + * type from the channel. + * + * wait = true only make sense for non_blocking channels, + * it polls for data to become available. + */ + int receive (char& msg, bool wait = false); + + /** 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 (); + + void set_receive_handler (sigc::slot s); + void attach (Glib::RefPtr); + +private: + friend gboolean cross_thread_channel_call_receive_slot (GIOChannel*, GIOCondition condition, void *data); + + GIOChannel* receive_channel; + GSource* receive_source; + sigc::slot receive_slot; + + bool poll_for_request(); + +#ifndef PLATFORM_WINDOWS + int fds[2]; // current implementation uses a pipe/fifo +#else + + SOCKET send_socket; + SOCKET receive_socket; + struct sockaddr_in recv_address; +#endif + +}; #endif /* __pbd__crossthread_h__ */