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