1 /* 2 * Copyright (C) 2006-2015 Paul Davis <paul@linuxaudiosystems.com> 3 * Copyright (C) 2015 Robin Gareus <robin@gareus.org> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 20 #ifndef __pbd__crossthread_h__ 21 #define __pbd__crossthread_h__ 22 23 #ifdef check 24 #undef check 25 #endif 26 27 #include <glibmm/main.h> 28 29 #include "pbd/libpbd_visibility.h" 30 31 #ifdef PLATFORM_WINDOWS 32 #include <windows.h> 33 #endif // PLATFORM_WINDOWS 34 35 36 /** A simple abstraction of a mechanism of signalling one thread from another. 37 * The signaller calls \ref wakeup() to tell the signalled thread to check for 38 * work to be done. 39 * 40 * This implementation provides both selectable() for use in direct 41 * poll/select-based event loops, and a Glib::IOSource via ios() for use 42 * in Glib main loop based situations. 43 */ 44 45 class LIBPBD_API CrossThreadChannel { 46 public: 47 /** if @a non_blocking is true, the channel will not cause blocking 48 * when used in an event loop based on poll/select or the glib main 49 * loop. 50 */ 51 CrossThreadChannel(bool non_blocking); 52 ~CrossThreadChannel(); 53 54 /** Tell the listening thread that is has work to do. 55 */ 56 void wakeup(); 57 58 /* if the listening thread cares about the precise message 59 * it is being sent, then \ref deliver() can be used to send 60 * a single byte message rather than a simple wakeup. These 61 * two mechanisms should not be used on the same CrossThreadChannel 62 * because there is no way to know which byte value will be used 63 * for ::wakeup() 64 */ 65 int deliver (char msg); 66 67 /** if using \ref deliver() to wakeup the listening thread, then 68 * the listener should call \ref receive() to fetch the message 69 * type from the channel. 70 * 71 * wait = true only make sense for non_blocking channels, 72 * it polls for data to become available. 73 */ 74 int receive (char& msg, bool wait = false); 75 76 /** empty the channel of all requests. 77 * Typically this is done as soon as input 78 * is noticed on the channel, because the 79 * handler will look at a separately managed work 80 * queue. The actual number of queued "wakeups" 81 * in the channel will not be important. 82 */ 83 void drain (); 84 85 void set_receive_handler (sigc::slot<bool,Glib::IOCondition> s); 86 void attach (Glib::RefPtr<Glib::MainContext>); 87 88 private: 89 friend gboolean cross_thread_channel_call_receive_slot (GIOChannel*, GIOCondition condition, void *data); 90 91 GIOChannel* receive_channel; 92 GSource* receive_source; 93 sigc::slot<bool,Glib::IOCondition> receive_slot; 94 95 bool poll_for_request(); 96 97 #ifndef PLATFORM_WINDOWS 98 int fds[2]; // current implementation uses a pipe/fifo 99 #else 100 101 SOCKET send_socket; 102 SOCKET receive_socket; 103 struct sockaddr_in recv_address; 104 #endif 105 106 }; 107 108 #endif /* __pbd__crossthread_h__ */ 109