evolution-3.6.4/libemail-utils/mail-mt.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }