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