1 /*
2  * Copyright (C) 2009 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (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
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18  */
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <libgda/libgda.h>
23 #include <thread-wrapper/gda-thread-wrapper.h>
24 #include "dummy-object.h"
25 #include <stdarg.h>
26 
27 #define NTHREADS 10
28 #define NCALLS 10
29 #define PRINT_CALLS
30 #undef PRINT_CALLS
31 
32 static gint test1 (void);
33 static gint test2 (void);
34 
35 GdaThreadWrapper *wrapper; /* global object */
36 
37 int
main(int argc,char ** argv)38 main (int argc, char** argv)
39 {
40 	gint failures = 0;
41 
42 	gda_init ();
43 
44 	failures += test1 ();
45 	failures += test2 ();
46 
47 	g_print ("Threads COUNT: %d, CALLS per thread:%d\n", NTHREADS, NCALLS*2 + 1);
48 	g_print ("FAILURES: %d\n", failures);
49 
50 	return failures != 0 ? 1 : 0;
51 }
52 
53 
54 
55 /*
56  * This test creates a single GdaThreadWrapper and runs NTHREADS threads which use the
57  * same GdaThreadWrapper object (each thread executes 2*NCALLS function calls plus a random
58  * number of function calls which return void).
59  *
60  * No signal is handled in this test
61  */
62 static gpointer main_thread_func (gpointer int_id);
63 static gpointer exec_in_wrapped_thread (gpointer int_in, GError **error);
64 static gchar *exec_in_wrapped_thread2 (gchar *str, GError **error);
65 static void exec_in_wrapped_thread_v (gchar *str, GError **error);
66 static gint
test1(void)67 test1 (void)
68 {
69 	gint failures = 0;
70 	gint i;
71 	GSList *threads = NULL;
72 
73 	wrapper = gda_thread_wrapper_new ();
74 
75 	/* use GdaThreadWrapper from several threads */
76 	for (i = 0; i < NTHREADS; i++) {
77 		GThread *th;
78 		th = g_thread_new ("th", main_thread_func, GINT_TO_POINTER (i));
79 		if (!th) {
80 			g_print ("Can't create thread %d (not part of the test)\n", i);
81 			exit (1);
82 		}
83 		threads = g_slist_prepend (threads, th);
84 	}
85 
86 	/* join the threads */
87 	GSList *list;
88 	for (list = threads; list; list = list->next)
89 		failures += GPOINTER_TO_INT (g_thread_join ((GThread*) list->data));
90 	g_slist_free (threads);
91 
92 	g_object_unref (wrapper);
93 	return failures;
94 }
95 
96 static gpointer
exec_in_wrapped_thread(gpointer int_in,GError ** error)97 exec_in_wrapped_thread (gpointer int_in, GError **error)
98 {
99 	g_print ("function_1 (%d)\n", GPOINTER_TO_INT (int_in));
100 	return int_in;
101 }
102 
103 static gchar *
exec_in_wrapped_thread2(gchar * str,GError ** error)104 exec_in_wrapped_thread2 (gchar *str, GError **error)
105 {
106 	g_print ("function_2 (%s)\n", str);
107 	return g_strdup (str);
108 }
109 
110 static void
exec_in_wrapped_thread_v(gchar * str,GError ** error)111 exec_in_wrapped_thread_v (gchar *str, GError **error)
112 {
113 	g_print ("function_VOID (%s)\n", str);
114 }
115 
116 static void
free_arg(gchar * str)117 free_arg (gchar *str)
118 {
119 	g_print ("\tFreeing: %s\n", str);
120 	g_free (str);
121 }
122 
123 static gpointer
main_thread_func(gpointer int_id)124 main_thread_func (gpointer int_id)
125 {
126 	gint i;
127 	guint *ids;
128 	gchar *estr;
129 
130 	gint total_jobs = 0;
131 	gint nfailed = 0;
132 
133 	g_print ("NEW thread %p <=> %d\n", g_thread_self(), GPOINTER_TO_INT (int_id));
134 
135 	ids = g_new0 (guint, 2*NCALLS);
136 	for (i = 0; i < NCALLS; i++) {
137 		guint id;
138 		GError *error = NULL;
139 
140 		/* func1 */
141 		id = gda_thread_wrapper_execute (wrapper, (GdaThreadWrapperFunc) exec_in_wrapped_thread,
142 						 GINT_TO_POINTER (i + GPOINTER_TO_INT (int_id) * 1000), NULL, &error);
143 		if (id == 0) {
144 			g_print ("Error in %s() for thread %d: %s\n", __FUNCTION__, GPOINTER_TO_INT (int_id),
145 				 error && error->message ? error->message : "No detail");
146 			if (error)
147 				g_error_free (error);
148 			return GINT_TO_POINTER (1);
149 		}
150 		ids[2*i] = id;
151 #ifdef PRINT_CALLS
152 		g_print ("--> Thread %d jobID %u arg %d\n", GPOINTER_TO_INT (int_id), id, i + GPOINTER_TO_INT (int_id) * 1000);
153 #endif
154 		if (rand () >= RAND_MAX / 2.)
155 			g_thread_yield ();
156 
157 
158 		if (rand () >= RAND_MAX / 2.) {
159 			id = gda_thread_wrapper_execute_void (wrapper, (GdaThreadWrapperVoidFunc) exec_in_wrapped_thread_v,
160 							      g_strdup_printf ("perturbator %d.%d", GPOINTER_TO_INT (int_id), i),
161 							      (GDestroyNotify) free_arg, &error);
162 			if (id == 0) {
163 				g_print ("Error in %s() for thread %d: %s\n", __FUNCTION__, GPOINTER_TO_INT (int_id),
164 					 error && error->message ? error->message : "No detail");
165 				if (error)
166 					g_error_free (error);
167 				return GINT_TO_POINTER (1);
168 			}
169 			total_jobs ++;
170 		}
171 		if (rand () >= RAND_MAX / 2.)
172 			g_thread_yield ();
173 
174 		/* func2 */
175 		id = gda_thread_wrapper_execute (wrapper, (GdaThreadWrapperFunc) exec_in_wrapped_thread2,
176 						 g_strdup_printf ("Hello %d.%d", GPOINTER_TO_INT (int_id), i),
177 						 (GDestroyNotify) free_arg, &error);
178 		if (id == 0) {
179 			g_print ("Error in %s() for thread %d: %s\n", __FUNCTION__, GPOINTER_TO_INT (int_id),
180 				 error && error->message ? error->message : "No detail");
181 			if (error)
182 				g_error_free (error);
183 			return GINT_TO_POINTER (1);
184 		}
185 		ids[2*i+1] = id;
186 		estr = g_strdup_printf ("Hello %d.%d", GPOINTER_TO_INT (int_id), i);
187 #ifdef PRINT_CALLS
188 		g_print ("--> Thread %d jobID %u arg %s\n", GPOINTER_TO_INT (int_id), id, estr);
189 #endif
190 		g_free (estr);
191 		if (rand () >= RAND_MAX / 2.)
192 			g_thread_yield ();
193 	}
194 	total_jobs += 2*NCALLS;
195 	g_thread_yield ();
196 
197 	/* pick up results */
198 	for (i = 0; i < NCALLS; i++) {
199 		gpointer res;
200 		res = gda_thread_wrapper_fetch_result (wrapper, TRUE, ids[2*i], NULL);
201 		if (GPOINTER_TO_INT (res) != i + GPOINTER_TO_INT (int_id) * 1000) {
202 			g_print ("Error in %s() for thread %d: sub thread's exec result is wrong\n",
203 				 __FUNCTION__, GPOINTER_TO_INT (int_id));
204 			nfailed ++;
205 		}
206 #ifdef PRINT_CALLS
207 		g_print ("<-- Thread %d jobID %u arg %d\n", GPOINTER_TO_INT (int_id), id, i + GPOINTER_TO_INT (int_id) * 1000);
208 #endif
209 		if (rand () >= RAND_MAX / 2.)
210 			g_thread_yield ();
211 
212 		gchar *str;
213 		estr = g_strdup_printf ("Hello %d.%d", GPOINTER_TO_INT (int_id), i);
214 		str = gda_thread_wrapper_fetch_result (wrapper, TRUE, ids[2*i+1], NULL);
215 		if (!str || strcmp (str, estr)) {
216 			g_print ("Error in %s() for thread %d: sub thread's exec result is wrong: got %s, exp: %s\n",
217 				 __FUNCTION__, GPOINTER_TO_INT (int_id), str, estr);
218 			nfailed ++;
219 		}
220 		g_free (estr);
221 #ifdef PRINT_CALLS
222 		g_print ("<-- Thread %d jobID %u arg %s\n", GPOINTER_TO_INT (int_id), id, str);
223 #endif
224 		g_free (str);
225 		if (rand () >= RAND_MAX / 2.)
226 			g_thread_yield ();
227 	}
228 	g_free (ids);
229 
230 	return GINT_TO_POINTER (nfailed);
231 }
232 
233 
234 /*
235  * This test creates a single #GdaThreadWrapper object and a single dummy object (DummyObject) which is
236  * used to emit signals by functions executed in sub threads.
237  */
238 typedef struct {
239 	DummyObject *dummy;
240 	GSList      *signals_sent; /* list of TestSignal structures */
241 	GMutex       mutex;
242 } t2ExecData;
243 static void add_to_signals_sent (t2ExecData *data, gpointer what_to_add);
244 static gpointer t2_main_thread_func (DummyObject *dummy);
245 static gpointer t2_exec_in_wrapped_thread (t2ExecData *data, GError **error);
246 static void t2_exec_in_wrapped_thread_v (t2ExecData *data, GError **error);
247 #define INT_TOKEN 1034
248 
249 static void
add_to_signals_sent(t2ExecData * data,gpointer what_to_add)250 add_to_signals_sent (t2ExecData *data, gpointer what_to_add)
251 {
252 	g_mutex_lock (&data->mutex);
253 	data->signals_sent = g_slist_append (data->signals_sent, what_to_add);
254 	g_mutex_unlock (&data->mutex);
255 }
256 
257 static gint
test2(void)258 test2 (void)
259 {
260 	gint failures = 0;
261 	gint i;
262 	GSList *threads = NULL;
263 	DummyObject *dummy;
264 
265 	wrapper = gda_thread_wrapper_new ();
266 	dummy = dummy_object_new ();
267 
268 	/* use GdaThreadWrapper from several threads */
269 	for (i = 0; i < NTHREADS; i++) {
270 		GThread *th;
271 		th = g_thread_new ("th", (GThreadFunc) t2_main_thread_func, dummy);
272 		if (!th) {
273 			g_print ("Can't create thread %d (not part of the test)\n", i);
274 			exit (1);
275 		}
276 		threads = g_slist_prepend (threads, th);
277 	}
278 
279 	/* join the threads */
280 	GSList *list;
281 	for (list = threads; list; list = list->next) {
282 		g_signal_emit_by_name (dummy, "sig0", NULL); /* this signal should be ignored */
283 		failures += GPOINTER_TO_INT (g_thread_join ((GThread*) list->data));
284 	}
285 	g_slist_free (threads);
286 
287 	g_object_unref (wrapper);
288 	g_object_unref (dummy);
289 
290 	return failures;
291 }
292 
293 /*
294  * structure to hold information about either a signal sent or received
295  */
296 typedef struct {
297 	gchar  *name;
298 	guint   n_param_values;
299         GValue *param_values; /* array of GValue structures */
300 } TestSignal;
301 
302 /*
303  * ... is a list of GType and value as native type (there must be exactly @n_param_values pairs)
304  */
305 static TestSignal *
test_signal_new(const gchar * signame,guint n_param_values,...)306 test_signal_new (const gchar *signame, guint n_param_values, ...)
307 {
308 	TestSignal *ts;
309 	va_list ap;
310 	guint i;
311 
312 	ts = g_new0 (TestSignal, 1);
313 	ts->name = g_strdup (signame);
314 	ts->n_param_values = n_param_values;
315 	ts->param_values = g_new0 (GValue, n_param_values);
316 
317 	va_start (ap, n_param_values);
318 	for (i = 0; i < n_param_values; i++) {
319 		GValue *value;
320 		GType type;
321 		type = va_arg (ap, GType);
322 
323 		value = ts->param_values + i;
324 		g_value_init (value, type);
325 		if (type == G_TYPE_INT) {
326 			gint v;
327 			v = va_arg (ap, gint);
328 			g_value_set_int (value, v);
329 		}
330 		else if (type == G_TYPE_STRING) {
331 			gchar *v;
332 			v = va_arg (ap, gchar *);
333 			g_value_set_string (value, v);
334 		}
335 		else
336 			g_assert_not_reached ();
337 	}
338 	va_end (ap);
339 
340 	return ts;
341 }
342 
343 /*
344  * Returns: TRUE if lists are equal
345  */
346 static gboolean
compare_signals_lists(GSList * explist,GSList * gotlist)347 compare_signals_lists (GSList *explist, GSList *gotlist)
348 {
349 	GSList *elist, *glist;
350 	for (elist = explist, glist = gotlist;
351 	     elist && glist;
352 	     elist = elist->next, glist = glist->next) {
353 		TestSignal *es = (TestSignal*) elist->data;
354 		TestSignal *gs = (TestSignal*) glist->data;
355 
356 		if (strcmp (es->name, gs->name)) {
357 			g_print ("Error: expected signal '%s', got signal '%s'\n", es->name, gs->name);
358 			return FALSE;
359 		}
360 		if (es->n_param_values != gs->n_param_values) {
361 			g_print ("Error: expected %d arguments in '%s', got %d\n", es->n_param_values,
362 				 es->name, gs->n_param_values);
363 			return FALSE;
364 		}
365 		guint i;
366 		for (i = 0; i < es->n_param_values; i++) {
367 			GValue *ev, *gv;
368 			ev = es->param_values + i;
369 			gv = gs->param_values + i;
370 			if (gda_value_differ (ev, gv)) {
371 				g_print ("Error: expected value %s in '%s', got %s\n",
372 					 gda_value_stringify (ev), es->name, gda_value_stringify (gv));
373 				return FALSE;
374 			}
375 		}
376 		/*g_print ("Checked signal %s\n", es->name);*/
377 	}
378 
379 	if (elist) {
380 		g_print ("Error: Some signals have not been received:\n");
381 		for (; elist; elist = elist->next) {
382 			TestSignal *es = (TestSignal*) elist->data;
383 			guint i;
384 			g_print ("\tSignal: %s", es->name);
385 			for (i = 0; i < es->n_param_values; i++)
386 				g_print (" %s", gda_value_stringify (es->param_values + i));
387 			g_print ("\n");
388 		}
389 		return FALSE;
390 	}
391 
392 	if (glist) {
393 		g_print ("Error: Received too many signals:\n");
394 		for (; glist; glist = glist->next) {
395 			TestSignal *gs = (TestSignal*) glist->data;
396 			guint i;
397 			g_print ("\tSignal: %s", gs->name);
398 			for (i = 0; i < gs->n_param_values; i++)
399 				g_print (" %s", gda_value_stringify (gs->param_values + i));
400 			g_print ("\n");
401 		}
402 		return FALSE;
403 	}
404 
405 	return TRUE;
406 }
407 
408 static gpointer
t2_exec_in_wrapped_thread(t2ExecData * data,GError ** error)409 t2_exec_in_wrapped_thread (t2ExecData *data, GError **error)
410 {
411 #ifdef PRINT_CALLS
412 	g_print ("TH %p ** emit sig0 (dummy=>%p)\n", g_thread_self (), data->dummy);
413 #endif
414         g_signal_emit_by_name (data->dummy, "sig0", NULL);
415 	add_to_signals_sent (data, test_signal_new ("sig0", 0));
416 
417 #ifdef PRINT_CALLS
418         g_print ("TH %p ** emit sig1 (dummy=>%p, i=>123)\n", g_thread_self (), data->dummy);
419 #endif
420         g_signal_emit_by_name (data->dummy, "sig1", 123, NULL);
421 	add_to_signals_sent (data, test_signal_new ("sig1", 1, G_TYPE_INT, 123));
422 
423 #ifdef PRINT_CALLS
424         g_print ("TH %p ** emit sig0 (dummy=>%p)\n", g_thread_self (), data->dummy);
425 #endif
426         g_signal_emit_by_name (data->dummy, "sig0", NULL);
427 	add_to_signals_sent (data, test_signal_new ("sig0", 0));
428 
429 #ifdef PRINT_CALLS
430         g_print ("TH %p ** emit sig2 (dummy=>%p, i=>456 str=>Hello)\n", g_thread_self (), data->dummy);
431 #endif
432         g_signal_emit_by_name (data->dummy, "sig2", 456, "Hello", NULL);
433 	add_to_signals_sent (data, test_signal_new ("sig2", 2, G_TYPE_INT, 456, G_TYPE_STRING, "Hello"));
434 
435 #ifdef PRINT_CALLS
436         g_print ("TH %p ** emit sig0 (dummy=>%p)\n", g_thread_self (), data->dummy);
437 #endif
438         g_signal_emit_by_name (data->dummy, "sig0", NULL);
439 	add_to_signals_sent (data, test_signal_new ("sig0", 0));
440 
441 #ifdef PRINT_CALLS
442         g_print ("TH %p ** emit sig1 (dummy=>%p, i=>789)\n", g_thread_self (), data->dummy);
443 #endif
444         g_signal_emit_by_name (data->dummy, "sig1", 789, NULL);
445 	add_to_signals_sent (data, test_signal_new ("sig1", 1, G_TYPE_INT, 789));
446 
447 #ifdef PRINT_CALLS
448         g_print ("TH %p ** emit sig2 (dummy=>%p, i=>32 str=>World)\n", g_thread_self (), data->dummy);
449 #endif
450         g_signal_emit_by_name (data->dummy, "sig2", 32, "World", NULL);
451 	add_to_signals_sent (data, test_signal_new ("sig2", 2, G_TYPE_INT, 32, G_TYPE_STRING, "World"));
452 
453 	return GINT_TO_POINTER (INT_TOKEN);
454 }
455 
456 static void
t2_exec_in_wrapped_thread_v(t2ExecData * data,GError ** error)457 t2_exec_in_wrapped_thread_v (t2ExecData *data, GError **error)
458 {
459 #ifdef PRINT_CALLS
460 	g_print ("TH %p ** emit sig0 (dummy=>%p)\n", g_thread_self (), data->dummy);
461 #endif
462         g_signal_emit_by_name (data->dummy, "sig0", NULL);
463 	add_to_signals_sent (data, test_signal_new ("sig0", 0));
464 
465 #ifdef PRINT_CALLS
466         g_print ("TH %p ** emit sig1 (dummy=>%p, i=>321)\n", g_thread_self (), data->dummy);
467 #endif
468         g_signal_emit_by_name (data->dummy, "sig1", 321, NULL);
469 	add_to_signals_sent (data, test_signal_new ("sig1", 1, G_TYPE_INT, 321));
470 
471 #ifdef PRINT_CALLS
472         g_print ("TH %p ** emit sig0 (dummy=>%p)\n", g_thread_self (), data->dummy);
473 #endif
474         g_signal_emit_by_name (data->dummy, "sig0", NULL);
475 	add_to_signals_sent (data, test_signal_new ("sig0", 0));
476 
477 #ifdef PRINT_CALLS
478         g_print ("TH %p ** emit sig2 (dummy=>%p, i=>654 str=>Thread)\n", g_thread_self (), data->dummy);
479 #endif
480         g_signal_emit_by_name (data->dummy, "sig2", 654, "Thread", NULL);
481 	add_to_signals_sent (data, test_signal_new ("sig2", 2, G_TYPE_INT, 654, G_TYPE_STRING, "Thread"));
482 
483 #ifdef PRINT_CALLS
484         g_print ("TH %p ** emit sig0 (dummy=>%p)\n", g_thread_self (), data->dummy);
485 #endif
486         g_signal_emit_by_name (data->dummy, "sig0", NULL);
487 	add_to_signals_sent (data, test_signal_new ("sig0", 0));
488 
489 #ifdef PRINT_CALLS
490         g_print ("TH %p ** emit sig1 (dummy=>%p, i=>987)\n", g_thread_self (), data->dummy);
491 #endif
492         g_signal_emit_by_name (data->dummy, "sig1", 987, NULL);
493 	add_to_signals_sent (data, test_signal_new ("sig1", 1, G_TYPE_INT, 987));
494 
495 #ifdef PRINT_CALLS
496         g_print ("TH %p ** emit sig2 (dummy=>%p, i=>23 str=>Thread)\n", g_thread_self (), data->dummy);
497 #endif
498         g_signal_emit_by_name (data->dummy, "sig2", 23, "Thread", NULL);
499 	add_to_signals_sent (data, test_signal_new ("sig2", 2, G_TYPE_INT, 23, G_TYPE_STRING, "Thread"));
500 }
501 
502 static void
wrapper_callback(GdaThreadWrapper * wrapper,gpointer instance,const gchar * signame,gint n_param_values,const GValue * param_values,gpointer gda_reserved,GSList ** sig_list)503 wrapper_callback (GdaThreadWrapper *wrapper, gpointer instance, const gchar *signame,
504 		  gint n_param_values, const GValue *param_values, gpointer gda_reserved, GSList **sig_list)
505 {
506 	gint i;
507 	/*
508 	g_print ("RECEIVED signal '%s' on thread %p\n", signame, g_thread_self ());
509 	for (i = 0; i < n_param_values; i++) {
510 		gchar *str = gda_value_stringify (param_values  + i);
511 		g_print ("\tParam %d: %s\n", i, str);
512 		g_free (str);
513 	}
514 	*/
515 
516 	TestSignal *ts;
517 
518 	ts = g_new0 (TestSignal, 1);
519 	ts->name = g_strdup (signame);
520 	ts->n_param_values = n_param_values;
521 	ts->param_values = g_new0 (GValue, n_param_values);
522 	for (i = 0; i < n_param_values; i++) {
523 		GValue *dest = ts->param_values + i;
524 		const GValue *src = param_values + i;
525 		g_value_init (dest, G_VALUE_TYPE (src));
526 		g_value_copy (src, dest);
527 	}
528 	*sig_list = g_slist_append (*sig_list, ts);
529 }
530 
531 static gpointer
t2_main_thread_func(DummyObject * dummy)532 t2_main_thread_func (DummyObject *dummy)
533 {
534 	gint i;
535 	guint *ids;
536 
537 	gint total_jobs = 0;
538 	gint nfailed = 0;
539 
540 	gulong sigid[3];
541 	t2ExecData edata;
542 	GSList *received_list = NULL;
543 
544 	/*g_print ("NEW test thread: %p\n", g_thread_self());*/
545 	sigid[0] = gda_thread_wrapper_connect_raw (wrapper, dummy, "sig0", TRUE, TRUE,
546 						   (GdaThreadWrapperCallback) wrapper_callback,
547 						   &received_list);
548 	sigid[1] = gda_thread_wrapper_connect_raw (wrapper, dummy, "sig1", TRUE, TRUE,
549 						   (GdaThreadWrapperCallback) wrapper_callback,
550 						   &received_list);
551 	sigid[2] = gda_thread_wrapper_connect_raw (wrapper, dummy, "sig2", TRUE, TRUE,
552 						   (GdaThreadWrapperCallback) wrapper_callback,
553 						   &received_list);
554 
555 	edata.dummy = dummy;
556 	edata.signals_sent = NULL;
557 	g_mutex_init (&edata.mutex);
558 
559 	ids = g_new0 (guint, NCALLS);
560 	for (i = 0; i < NCALLS; i++) {
561 		guint id;
562 		GError *error = NULL;
563 
564 		/* func1 */
565 		id = gda_thread_wrapper_execute (wrapper,
566 						 (GdaThreadWrapperFunc) t2_exec_in_wrapped_thread,
567 						 &edata, NULL, &error);
568 		if (id == 0) {
569 			g_print ("Error in %s() for thread %p: %s\n", __FUNCTION__, g_thread_self (),
570 				 error && error->message ? error->message : "No detail");
571 			if (error)
572 				g_error_free (error);
573 			return GINT_TO_POINTER (1);
574 		}
575 		ids[i] = id;
576 #ifdef PRINT_CALLS
577 		g_print ("--> Thread %p jobID %u\n", g_thread_self (), id);
578 #endif
579 		if (rand () >= RAND_MAX / 2.)
580 			g_thread_yield ();
581 
582 
583 		if (rand () >= RAND_MAX / 2.) {
584 			id = gda_thread_wrapper_execute_void (wrapper,
585 							      (GdaThreadWrapperVoidFunc) t2_exec_in_wrapped_thread_v,
586 							      &edata,
587 							      NULL, &error);
588 			if (id == 0) {
589 				g_print ("Error in %s() for thread %p: %s\n", __FUNCTION__, g_thread_self (),
590 					 error && error->message ? error->message : "No detail");
591 				if (error)
592 					g_error_free (error);
593 				return GINT_TO_POINTER (1);
594 			}
595 			total_jobs ++;
596 		}
597 		if (rand () >= RAND_MAX / 2.)
598 			g_thread_yield ();
599 	}
600 	total_jobs += NCALLS;
601 	g_thread_yield ();
602 
603 	/* pick up results */
604 	for (i = 0; i < NCALLS; i++) {
605 		gpointer res;
606 
607 		g_signal_emit_by_name (dummy, "sig0", NULL); /* this signal should be ignored */
608 
609 		res = gda_thread_wrapper_fetch_result (wrapper, TRUE, ids[i], NULL);
610 		if (GPOINTER_TO_INT (res) != INT_TOKEN) {
611 			g_print ("Error in %s() for thread %p: sub thread's exec result is wrong\n",
612 				 __FUNCTION__, g_thread_self ());
613 			nfailed ++;
614 		}
615 #ifdef PRINT_CALLS
616 		g_print ("<-- Thread %p jobID %u arg %d\n", g_thread_self (), ids[i], INT_TOKEN);
617 #endif
618 		if (rand () >= RAND_MAX / 2.)
619 			g_thread_yield ();
620 		g_signal_emit_by_name (dummy, "sig1", 666, NULL); /* this signal should be ignored */
621 	}
622 
623 	while (gda_thread_wrapper_get_waiting_size (wrapper) > 0) {
624 		gda_thread_wrapper_iterate (wrapper, FALSE);
625 		g_usleep (10000);
626 	}
627 
628 	g_mutex_lock (&edata.mutex);
629 	if (! compare_signals_lists (edata.signals_sent, received_list))
630 		nfailed++;
631 	g_mutex_unlock (&edata.mutex);
632 
633 
634 #ifdef PRINT_CALLS
635 	g_print ("Disconnecting signals\n");
636 #endif
637 	gda_thread_wrapper_disconnect (wrapper, sigid[0]);
638 	gda_thread_wrapper_disconnect (wrapper, sigid[1]);
639 	gda_thread_wrapper_disconnect (wrapper, sigid[2]);
640 
641 	g_free (ids);
642 
643 	/* we don't care about mem leaks here... */
644 	received_list = NULL;
645 	guint id;
646 	GError *error = NULL;
647 	id = gda_thread_wrapper_execute_void (wrapper,
648 					      (GdaThreadWrapperVoidFunc) t2_exec_in_wrapped_thread_v,
649 					      &edata,
650 					      NULL, &error);
651 	if (id == 0) {
652 		g_print ("Error in %s() for thread %p: %s\n", __FUNCTION__, g_thread_self (),
653 			 error && error->message ? error->message : "No detail");
654 		if (error)
655 			g_error_free (error);
656 		return GINT_TO_POINTER (1);
657 	}
658 	total_jobs ++;
659 
660 	while (gda_thread_wrapper_get_waiting_size (wrapper) > 0) {
661 		gda_thread_wrapper_iterate (wrapper, FALSE);
662 		g_usleep (10000);
663 	}
664 	g_mutex_clear (&edata.mutex);
665 
666 	if (received_list) {
667 		g_print ("Error: signals should not be received anymore...\n");
668 		nfailed ++;
669 	}
670 
671 	return GINT_TO_POINTER (nfailed);
672 }
673