File: dispatcher.h

package info (click to toggle)
sigx 2.0.2-3
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 1,144 kB
  • ctags: 1,311
  • sloc: cpp: 3,103; ansic: 653; xml: 206; python: 65; makefile: 26
file content (233 lines) | stat: -rw-r--r-- 7,078 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#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 <queue>
#include <map>
#include <glib.h> // gint
#include <sigxconfig.h>
#include <sigx/fwddecl.h>
#include <sigx/bad_caller.h>
#include <sigx/bad_sync_call.h>
#include <sigx/operator_new.h>
#include <sigx/glib_lockables.h>


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<const threadhandle_type /*threadA*/, const threadhandle_type /*threadB*/> 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<thread_pair_type, thread_pair_type, bool>
{
	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<thread_pair_type, syncmessages_counter, thread_compare> sync_messages_type;
typedef static_mutex_lockable<sync_messages_type> 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<tunnel_context_base*> context_container_type;
	typedef mutex_lockable<context_container_type> 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