No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | mail-mt.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | mail-mt.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU Lesser General Public
4 * License as published by the Free Software Foundation; either
5 * version 2 of the License, or (at your option) version 3.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 * Lesser General Public License for more details.
11 *
12 * You should have received a copy of the GNU Lesser General Public
13 * License along with the program; if not, see <http://www.gnu.org/licenses/>
14 *
15 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
16 */
17
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include <gtk/gtk.h>
28
29 #include <libedataserver/libedataserver.h>
30
31 #include "mail-mt.h"
32
33 /*#define MALLOC_CHECK*/
34 #define d(x)
35
36 /* XXX This is a dirty hack on a dirty hack. We really need
37 * to rework or get rid of the functions that use this. */
38 const gchar *shell_builtin_backend = "mail";
39
40 static guint mail_msg_seq; /* sequence number of each message */
41
42 /* Table of active messages. Must hold mail_msg_lock to access. */
43 static GHashTable *mail_msg_active_table;
44 static GMutex *mail_msg_lock;
45 static GCond *mail_msg_cond;
46
47 static MailMsgCreateActivityFunc create_activity = NULL;
48 static MailMsgSubmitActivityFunc submit_activity = NULL;
49 static MailMsgFreeActivityFunc free_activity = NULL;
50 static MailMsgCompleteActivityFunc complete_activity = NULL;
51 static MailMsgAlertErrorFunc alert_error = NULL;
52 static MailMsgCancelActivityFunc cancel_activity = NULL;
53 static MailMsgGetAlertSinkFunc get_alert_sink = NULL;
54
55 void
56 mail_msg_register_activities (MailMsgCreateActivityFunc acreate,
57 MailMsgSubmitActivityFunc asubmit,
58 MailMsgFreeActivityFunc freeact,
59 MailMsgCompleteActivityFunc comp_act,
60 MailMsgCancelActivityFunc cancel_act,
61 MailMsgAlertErrorFunc ealert,
62 MailMsgGetAlertSinkFunc ealertsink)
63 {
64 /* XXX This is an utter hack to keep EActivity out
65 * of EDS and still let Evolution do EActivity. */
66 create_activity = acreate;
67 submit_activity = asubmit;
68 free_activity = freeact;
69 complete_activity = comp_act;
70 cancel_activity = cancel_act;
71 alert_error = ealert;
72 get_alert_sink = ealertsink;
73 }
74
75 EAlertSink *
76 mail_msg_get_alert_sink ()
77 {
78 if (get_alert_sink)
79 return get_alert_sink ();
80
81 return NULL;
82 }
83
84 static void
85 mail_msg_cancelled (CamelOperation *operation,
86 gpointer user_data)
87 {
88 mail_msg_cancel (GPOINTER_TO_UINT (user_data));
89 }
90
91 static gboolean
92 mail_msg_submit (CamelOperation *cancellable)
93 {
94
95 if (submit_activity)
96 submit_activity ((GCancellable *) cancellable);
97 return FALSE;
98 }
99
100 gpointer
101 mail_msg_new (MailMsgInfo *info)
102 {
103 MailMsg *msg;
104
105 g_mutex_lock (mail_msg_lock);
106
107 msg = g_slice_alloc0 (info->size);
108 msg->info = info;
109 msg->ref_count = 1;
110 msg->seq = mail_msg_seq++;
111
112 msg->cancellable = camel_operation_new ();
113
114 if (create_activity)
115 create_activity (msg->cancellable);
116
117 g_signal_connect (
118 msg->cancellable, "cancelled",
119 G_CALLBACK (mail_msg_cancelled),
120 GINT_TO_POINTER (msg->seq));
121
122 g_hash_table_insert (
123 mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg);
124
125 d (printf ("New message %p\n", msg));
126
127 g_mutex_unlock (mail_msg_lock);
128
129 return msg;
130 }
131
132 #ifdef MALLOC_CHECK
133 #include <mcheck.h>
134
135 static void
136 checkmem (gpointer p)
137 {
138 if (p) {
139 gint status = mprobe (p);
140
141 switch (status) {
142 case MCHECK_HEAD:
143 printf ("Memory underrun at %p\n", p);
144 abort ();
145 case MCHECK_TAIL:
146 printf ("Memory overrun at %p\n", p);
147 abort ();
148 case MCHECK_FREE:
149 printf ("Double free %p\n", p);
150 abort ();
151 }
152 }
153 }
154 #endif
155
156 static gboolean
157 mail_msg_free (MailMsg *mail_msg)
158 {
159 /* This is an idle callback. */
160
161 if (free_activity)
162 free_activity (mail_msg->cancellable);
163
164 if (mail_msg->cancellable != NULL)
165 g_object_unref (mail_msg->cancellable);
166
167 if (mail_msg->error != NULL)
168 g_error_free (mail_msg->error);
169
170 g_slice_free1 (mail_msg->info->size, mail_msg);
171
172 return FALSE;
173 }
174
175 gpointer
176 mail_msg_ref (gpointer msg)
177 {
178 MailMsg *mail_msg = msg;
179
180 g_return_val_if_fail (mail_msg != NULL, msg);
181 g_return_val_if_fail (mail_msg->ref_count > 0, msg);
182
183 g_atomic_int_inc (&mail_msg->ref_count);
184
185 return msg;
186 }
187
188 void
189 mail_msg_unref (gpointer msg)
190 {
191 MailMsg *mail_msg = msg;
192
193 g_return_if_fail (mail_msg != NULL);
194 g_return_if_fail (mail_msg->ref_count > 0);
195
196 if (g_atomic_int_dec_and_test (&mail_msg->ref_count)) {
197
198 #ifdef MALLOC_CHECK
199 checkmem (mail_msg);
200 checkmem (mail_msg->cancel);
201 checkmem (mail_msg->priv);
202 #endif
203 d (printf ("Free message %p\n", msg));
204
205 if (mail_msg->info->free)
206 mail_msg->info->free (mail_msg);
207
208 g_mutex_lock (mail_msg_lock);
209
210 g_hash_table_remove (
211 mail_msg_active_table,
212 GINT_TO_POINTER (mail_msg->seq));
213 g_cond_broadcast (mail_msg_cond);
214
215 g_mutex_unlock (mail_msg_lock);
216
217 /* Destroy the message from an idle callback
218 * so we know we're in the main loop thread.
219 * Prioritize ahead of GTK+ redraws. */
220 g_idle_add_full (
221 G_PRIORITY_HIGH_IDLE,
222 (GSourceFunc) mail_msg_free, mail_msg, NULL);
223 }
224 }
225
226 void
227 mail_msg_check_error (gpointer msg)
228 {
229 MailMsg *m = msg;
230
231 #ifdef MALLOC_CHECK
232 checkmem (m);
233 checkmem (m->cancel);
234 checkmem (m->priv);
235 #endif
236
237 if (m->error == NULL)
238 return;
239
240 if (complete_activity)
241 complete_activity (m->cancellable);
242
243 if (g_error_matches (m->error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
244 if (cancel_activity)
245 cancel_activity (m->cancellable);
246 return;
247 }
248
249 /* XXX Hmm, no explanation of why this is needed. It looks like
250 * a lame hack and will be removed at some point, if only to
251 * reintroduce whatever issue made this necessary so we can
252 * document it in the source code this time. */
253 if (g_error_matches (
254 m->error, CAMEL_FOLDER_ERROR,
255 CAMEL_FOLDER_ERROR_INVALID_UID))
256 return;
257
258 /* FIXME: Submit an error on the dbus */
259 if (alert_error) {
260 gchar *what;
261
262 if (m->info->desc && (what = m->info->desc (m))) {
263 alert_error (m->cancellable, what, m->error->message);
264 g_free (what);
265 } else
266 alert_error (m->cancellable, NULL, m->error->message);
267 }
268 }
269
270 void
271 mail_msg_cancel (guint msgid)
272 {
273 MailMsg *msg;
274 GCancellable *cancellable = NULL;
275
276 g_mutex_lock (mail_msg_lock);
277
278 msg = g_hash_table_lookup (
279 mail_msg_active_table, GINT_TO_POINTER (msgid));
280
281 /* Hold a reference to the GCancellable so it doesn't finalize
282 * itself on us between unlocking the mutex and cancelling. */
283 if (msg != NULL) {
284 cancellable = msg->cancellable;
285 if (g_cancellable_is_cancelled (cancellable))
286 cancellable = NULL;
287 else
288 g_object_ref (cancellable);
289 }
290
291 g_mutex_unlock (mail_msg_lock);
292
293 if (cancellable != NULL) {
294 g_cancellable_cancel (cancellable);
295 g_object_unref (cancellable);
296 }
297 }
298
299 gboolean
300 mail_msg_active (void)
301 {
302 gboolean active;
303
304 g_mutex_lock (mail_msg_lock);
305 active = g_hash_table_size (mail_msg_active_table) > 0;
306 g_mutex_unlock (mail_msg_lock);
307
308 return active;
309 }
310
311 /* **************************************** */
312
313 static GHookList cancel_hook_list;
314
315 GHook *
316 mail_cancel_hook_add (GHookFunc func,
317 gpointer data)
318 {
319 GHook *hook;
320
321 g_mutex_lock (mail_msg_lock);
322
323 if (!cancel_hook_list.is_setup)
324 g_hook_list_init (&cancel_hook_list, sizeof (GHook));
325
326 hook = g_hook_alloc (&cancel_hook_list);
327 hook->func = func;
328 hook->data = data;
329
330 g_hook_append (&cancel_hook_list, hook);
331
332 g_mutex_unlock (mail_msg_lock);
333
334 return hook;
335 }
336
337 void
338 mail_cancel_hook_remove (GHook *hook)
339 {
340 g_mutex_lock (mail_msg_lock);
341
342 g_return_if_fail (cancel_hook_list.is_setup);
343 g_hook_destroy_link (&cancel_hook_list, hook);
344
345 g_mutex_unlock (mail_msg_lock);
346 }
347
348 void
349 mail_cancel_all (void)
350 {
351 camel_operation_cancel_all ();
352
353 g_mutex_lock (mail_msg_lock);
354
355 if (cancel_hook_list.is_setup)
356 g_hook_list_invoke (&cancel_hook_list, FALSE);
357
358 g_mutex_unlock (mail_msg_lock);
359 }
360
361 static guint idle_source_id = 0;
362 G_LOCK_DEFINE_STATIC (idle_source_id);
363 static GAsyncQueue *main_loop_queue = NULL;
364 static GAsyncQueue *msg_reply_queue = NULL;
365 static GThread *main_thread = NULL;
366
367 static gboolean
368 mail_msg_idle_cb (void)
369 {
370 MailMsg *msg;
371
372 g_return_val_if_fail (main_loop_queue != NULL, FALSE);
373 g_return_val_if_fail (msg_reply_queue != NULL, FALSE);
374
375 G_LOCK (idle_source_id);
376 idle_source_id = 0;
377 G_UNLOCK (idle_source_id);
378 /* check the main loop queue */
379 while ((msg = g_async_queue_try_pop (main_loop_queue)) != NULL) {
380 GCancellable *cancellable;
381
382 cancellable = msg->cancellable;
383
384 g_idle_add_full (
385 G_PRIORITY_DEFAULT,
386 (GSourceFunc) mail_msg_submit,
387 g_object_ref (msg->cancellable),
388 (GDestroyNotify) g_object_unref);
389 if (msg->info->exec != NULL)
390 msg->info->exec (msg, cancellable, &msg->error);
391 if (msg->info->done != NULL)
392 msg->info->done (msg);
393 mail_msg_unref (msg);
394 }
395
396 /* check the reply queue */
397 while ((msg = g_async_queue_try_pop (msg_reply_queue)) != NULL) {
398 if (msg->info->done != NULL)
399 msg->info->done (msg);
400 mail_msg_check_error (msg);
401 mail_msg_unref (msg);
402 }
403 return FALSE;
404 }
405
406 static void
407 mail_msg_proxy (MailMsg *msg)
408 {
409 GCancellable *cancellable;
410
411 cancellable = msg->cancellable;
412
413 if (msg->info->desc != NULL) {
414 gchar *text = msg->info->desc (msg);
415 camel_operation_push_message (cancellable, "%s", text);
416 g_free (text);
417 }
418
419 g_idle_add_full (
420 G_PRIORITY_DEFAULT,
421 (GSourceFunc) mail_msg_submit,
422 g_object_ref (msg->cancellable),
423 (GDestroyNotify) g_object_unref);
424
425 if (msg->info->exec != NULL)
426 msg->info->exec (msg, cancellable, &msg->error);
427
428 if (msg->info->desc != NULL)
429 camel_operation_pop_message (cancellable);
430
431 g_async_queue_push (msg_reply_queue, msg);
432
433 G_LOCK (idle_source_id);
434 if (idle_source_id == 0)
435 /* Prioritize ahead of GTK+ redraws. */
436 idle_source_id = g_idle_add_full (
437 G_PRIORITY_HIGH_IDLE,
438 (GSourceFunc) mail_msg_idle_cb, NULL, NULL);
439 G_UNLOCK (idle_source_id);
440 }
441
442 void
443 mail_msg_init (void)
444 {
445 mail_msg_lock = g_mutex_new ();
446 mail_msg_cond = g_cond_new ();
447
448 main_loop_queue = g_async_queue_new ();
449 msg_reply_queue = g_async_queue_new ();
450
451 mail_msg_active_table = g_hash_table_new (NULL, NULL);
452 main_thread = g_thread_self ();
453 }
454
455 static gint
456 mail_msg_compare (const MailMsg *msg1,
457 const MailMsg *msg2)
458 {
459 gint priority1 = msg1->priority;
460 gint priority2 = msg2->priority;
461
462 if (priority1 == priority2)
463 return 0;
464
465 return (priority1 < priority2) ? 1 : -1;
466 }
467
468 static gpointer
469 create_thread_pool (gpointer data)
470 {
471 GThreadPool *thread_pool;
472 gint max_threads = GPOINTER_TO_INT (data);
473
474 /* once created, run forever */
475 thread_pool = g_thread_pool_new (
476 (GFunc) mail_msg_proxy, NULL, max_threads, FALSE, NULL);
477 g_thread_pool_set_sort_function (
478 thread_pool, (GCompareDataFunc) mail_msg_compare, NULL);
479
480 return thread_pool;
481 }
482
483 void
484 mail_msg_main_loop_push (gpointer msg)
485 {
486 g_async_queue_push_sorted (
487 main_loop_queue, msg,
488 (GCompareDataFunc) mail_msg_compare, NULL);
489
490 G_LOCK (idle_source_id);
491 if (idle_source_id == 0)
492 /* Prioritize ahead of GTK+ redraws. */
493 idle_source_id = g_idle_add_full (
494 G_PRIORITY_HIGH_IDLE,
495 (GSourceFunc) mail_msg_idle_cb, NULL, NULL);
496 G_UNLOCK (idle_source_id);
497 }
498
499 void
500 mail_msg_unordered_push (gpointer msg)
501 {
502 static GOnce once = G_ONCE_INIT;
503
504 g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (10));
505
506 g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL);
507 }
508
509 void
510 mail_msg_fast_ordered_push (gpointer msg)
511 {
512 static GOnce once = G_ONCE_INIT;
513
514 g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1));
515
516 g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL);
517 }
518
519 void
520 mail_msg_slow_ordered_push (gpointer msg)
521 {
522 static GOnce once = G_ONCE_INIT;
523
524 g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1));
525
526 g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL);
527 }
528
529 gboolean
530 mail_in_main_thread (void)
531 {
532 return (g_thread_self () == main_thread);
533 }
534
535 /* ********************************************************************** */
536
537 struct _call_msg {
538 MailMsg base;
539
540 mail_call_t type;
541 MailMainFunc func;
542 gpointer ret;
543 va_list ap;
544 EFlag *done;
545 };
546
547 static void
548 do_call (struct _call_msg *m,
549 GCancellable *cancellable,
550 GError **error)
551 {
552 gpointer p1, *p2, *p3, *p4, *p5;
553 gint i1;
554 va_list ap;
555
556 G_VA_COPY (ap, m->ap);
557
558 switch (m->type) {
559 case MAIL_CALL_p_p:
560 p1 = va_arg (ap, gpointer);
561 m->ret = m->func (p1);
562 break;
563 case MAIL_CALL_p_pp:
564 p1 = va_arg (ap, gpointer);
565 p2 = va_arg (ap, gpointer);
566 m->ret = m->func (p1, p2);
567 break;
568 case MAIL_CALL_p_ppp:
569 p1 = va_arg (ap, gpointer);
570 p2 = va_arg (ap, gpointer);
571 p3 = va_arg (ap, gpointer);
572 m->ret = m->func (p1, p2, p3);
573 break;
574 case MAIL_CALL_p_pppp:
575 p1 = va_arg (ap, gpointer);
576 p2 = va_arg (ap, gpointer);
577 p3 = va_arg (ap, gpointer);
578 p4 = va_arg (ap, gpointer);
579 m->ret = m->func (p1, p2, p3, p4);
580 break;
581 case MAIL_CALL_p_ppppp:
582 p1 = va_arg (ap, gpointer);
583 p2 = va_arg (ap, gpointer);
584 p3 = va_arg (ap, gpointer);
585 p4 = va_arg (ap, gpointer);
586 p5 = va_arg (ap, gpointer);
587 m->ret = m->func (p1, p2, p3, p4, p5);
588 break;
589 case MAIL_CALL_p_ppippp:
590 p1 = va_arg (ap, gpointer);
591 p2 = va_arg (ap, gpointer);
592 i1 = va_arg (ap, gint);
593 p3 = va_arg (ap, gpointer);
594 p4 = va_arg (ap, gpointer);
595 p5 = va_arg (ap, gpointer);
596 m->ret = m->func (p1, p2, i1, p3, p4, p5);
597 break;
598 }
599
600 if (g_cancellable_is_cancelled (cancellable)) {
601 if (cancel_activity)
602 cancel_activity (cancellable);
603 } else {
604 if (complete_activity)
605 complete_activity (cancellable);
606 }
607
608 if (m->done != NULL)
609 e_flag_set (m->done);
610 }
611
612 static MailMsgInfo mail_call_info = {
613 sizeof (struct _call_msg),
614 (MailMsgDescFunc) NULL,
615 (MailMsgExecFunc) do_call,
616 (MailMsgDoneFunc) NULL,
617 (MailMsgFreeFunc) NULL
618 };
619
620 gpointer
621 mail_call_main (mail_call_t type,
622 MailMainFunc func,
623 ...)
624 {
625 GCancellable *cancellable;
626 struct _call_msg *m;
627 gpointer ret;
628 va_list ap;
629
630 va_start (ap, func);
631
632 m = mail_msg_new (&mail_call_info);
633 m->type = type;
634 m->func = func;
635 G_VA_COPY (m->ap, ap);
636
637 cancellable = m->base.cancellable;
638
639 if (mail_in_main_thread ())
640 do_call (m, cancellable, &m->base.error);
641 else {
642 mail_msg_ref (m);
643 m->done = e_flag_new ();
644 mail_msg_main_loop_push (m);
645 e_flag_wait (m->done);
646 e_flag_free (m->done);
647 }
648
649 va_end (ap);
650
651 ret = m->ret;
652 mail_msg_unref (m);
653
654 return ret;
655 }
656
657 void
658 mail_mt_set_backend (gchar *backend)
659 {
660 shell_builtin_backend = backend;
661 }