diff options
Diffstat (limited to 'mail/mail-mt.c')
-rw-r--r-- | mail/mail-mt.c | 646 |
1 files changed, 0 insertions, 646 deletions
diff --git a/mail/mail-mt.c b/mail/mail-mt.c deleted file mode 100644 index 526571f61f..0000000000 --- a/mail/mail-mt.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * This program 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#include <gtk/gtk.h> - -#include <libedataserver/e-flag.h> - -#include <e-util/e-alert-sink.h> -#include <shell/e-shell-view.h> - -#include "mail-mt.h" - -/*#define MALLOC_CHECK*/ -#define d(x) - -/* XXX This is a dirty hack on a dirty hack. We really need - * to rework or get rid of the functions that use this. */ -const gchar *shell_builtin_backend = "mail"; - -static guint mail_msg_seq; /* sequence number of each message */ - -/* Table of active messages. Must hold mail_msg_lock to access. */ -static GHashTable *mail_msg_active_table; -static GMutex *mail_msg_lock; -static GCond *mail_msg_cond; - -static void -mail_msg_cancelled (CamelOperation *operation, - gpointer user_data) -{ - mail_msg_cancel (GPOINTER_TO_UINT (user_data)); -} - -static gboolean -mail_msg_submit (EActivity *activity) -{ - EShell *shell; - EShellBackend *shell_backend; - - shell = e_shell_get_default (); - shell_backend = e_shell_get_backend_by_name ( - shell, shell_builtin_backend); - - e_shell_backend_add_activity (shell_backend, activity); - - return FALSE; -} - -gpointer -mail_msg_new (MailMsgInfo *info) -{ - MailMsg *msg; - GCancellable *cancellable; - - g_mutex_lock (mail_msg_lock); - - msg = g_slice_alloc0 (info->size); - msg->info = info; - msg->ref_count = 1; - msg->seq = mail_msg_seq++; - msg->activity = e_activity_new (); - - cancellable = camel_operation_new (); - - e_activity_set_percent (msg->activity, 0.0); - e_activity_set_cancellable (msg->activity, cancellable); - - g_signal_connect ( - cancellable, "cancelled", - G_CALLBACK (mail_msg_cancelled), - GINT_TO_POINTER (msg->seq)); - - g_object_unref (cancellable); - - g_hash_table_insert ( - mail_msg_active_table, GINT_TO_POINTER (msg->seq), msg); - - d(printf("New message %p\n", msg)); - - g_mutex_unlock (mail_msg_lock); - - return msg; -} - -#ifdef MALLOC_CHECK -#include <mcheck.h> - -static void -checkmem (gpointer p) -{ - if (p) { - gint status = mprobe (p); - - switch (status) { - case MCHECK_HEAD: - printf("Memory underrun at %p\n", p); - abort (); - case MCHECK_TAIL: - printf("Memory overrun at %p\n", p); - abort (); - case MCHECK_FREE: - printf("Double free %p\n", p); - abort (); - } - } -} -#endif - -static gboolean -mail_msg_free (MailMsg *mail_msg) -{ - /* This is an idle callback. */ - - if (mail_msg->activity != NULL) - g_object_unref (mail_msg->activity); - - if (mail_msg->error != NULL) - g_error_free (mail_msg->error); - - g_slice_free1 (mail_msg->info->size, mail_msg); - - return FALSE; -} - -gpointer -mail_msg_ref (gpointer msg) -{ - MailMsg *mail_msg = msg; - - g_return_val_if_fail (mail_msg != NULL, msg); - g_return_val_if_fail (mail_msg->ref_count > 0, msg); - - g_atomic_int_inc (&mail_msg->ref_count); - - return msg; -} - -void -mail_msg_unref (gpointer msg) -{ - MailMsg *mail_msg = msg; - - g_return_if_fail (mail_msg != NULL); - g_return_if_fail (mail_msg->ref_count > 0); - - if (g_atomic_int_dec_and_test (&mail_msg->ref_count)) { - -#ifdef MALLOC_CHECK - checkmem (mail_msg); - checkmem (mail_msg->cancel); - checkmem (mail_msg->priv); -#endif - d(printf("Free message %p\n", msg)); - - if (mail_msg->info->free) - mail_msg->info->free (mail_msg); - - g_mutex_lock (mail_msg_lock); - - g_hash_table_remove ( - mail_msg_active_table, - GINT_TO_POINTER (mail_msg->seq)); - g_cond_broadcast (mail_msg_cond); - - g_mutex_unlock (mail_msg_lock); - - /* Destroy the message from an idle callback - * so we know we're in the main loop thread. */ - g_idle_add ((GSourceFunc) mail_msg_free, mail_msg); - } -} - -void -mail_msg_check_error (gpointer msg) -{ - EShell *shell; - EShellView *shell_view; - EShellWindow *shell_window = NULL; - EShellContent *shell_content; - GtkApplication *application; - MailMsg *m = msg; - gchar *what; - GList *list, *iter; - -#ifdef MALLOC_CHECK - checkmem (m); - checkmem (m->cancel); - checkmem (m->priv); -#endif - - if (e_activity_handle_cancellation (m->activity, m->error)) - return; - - e_activity_set_state (m->activity, E_ACTIVITY_COMPLETED); - - if (m->error == NULL) - return; - - /* XXX Hmm, no explanation of why this is needed. It looks like - * a lame hack and will be removed at some point, if only to - * reintroduce whatever issue made this necessary so we can - * document it the source code this time. */ - if (g_error_matches (m->error, CAMEL_FOLDER_ERROR, CAMEL_FOLDER_ERROR_INVALID_UID)) - return; - - shell = e_shell_get_default (); - application = GTK_APPLICATION (shell); - list = gtk_application_get_windows (application); - - /* Find the most recently used EShellWindow. */ - for (iter = list; iter != NULL; iter = g_list_next (iter)) { - if (E_IS_SHELL_WINDOW (iter->data)) { - shell_window = E_SHELL_WINDOW (iter->data); - break; - } - } - - /* If we can't find an EShellWindow then... well, screw it. */ - if (shell_window == NULL) - return; - - shell_view = e_shell_window_get_shell_view ( - shell_window, shell_builtin_backend); - shell_content = e_shell_view_get_shell_content (shell_view); - - if (m->info->desc && (what = m->info->desc (m))) { - e_alert_submit ( - E_ALERT_SINK (shell_content), - "mail:async-error", what, - m->error->message, NULL); - g_free (what); - } else - e_alert_submit ( - E_ALERT_SINK (shell_content), - "mail:async-error-nodescribe", - m->error->message, NULL); -} - -void -mail_msg_cancel (guint msgid) -{ - MailMsg *msg; - GCancellable *cancellable = NULL; - - g_mutex_lock (mail_msg_lock); - - msg = g_hash_table_lookup ( - mail_msg_active_table, GINT_TO_POINTER (msgid)); - - /* Hold a reference to the GCancellable so it doesn't finalize - * itself on us between unlocking the mutex and cancelling. */ - if (msg != NULL) { - cancellable = e_activity_get_cancellable (msg->activity); - if (g_cancellable_is_cancelled (cancellable)) - cancellable = NULL; - else - g_object_ref (cancellable); - } - - g_mutex_unlock (mail_msg_lock); - - if (cancellable != NULL) { - g_cancellable_cancel (cancellable); - g_object_unref (cancellable); - } -} - -gboolean -mail_msg_active (void) -{ - gboolean active; - - g_mutex_lock (mail_msg_lock); - active = g_hash_table_size (mail_msg_active_table) > 0; - g_mutex_unlock (mail_msg_lock); - - return active; -} - -/* **************************************** */ - -static GHookList cancel_hook_list; - -GHook * -mail_cancel_hook_add (GHookFunc func, - gpointer data) -{ - GHook *hook; - - g_mutex_lock (mail_msg_lock); - - if (!cancel_hook_list.is_setup) - g_hook_list_init (&cancel_hook_list, sizeof (GHook)); - - hook = g_hook_alloc (&cancel_hook_list); - hook->func = func; - hook->data = data; - - g_hook_append (&cancel_hook_list, hook); - - g_mutex_unlock (mail_msg_lock); - - return hook; -} - -void -mail_cancel_hook_remove (GHook *hook) -{ - g_mutex_lock (mail_msg_lock); - - g_return_if_fail (cancel_hook_list.is_setup); - g_hook_destroy_link (&cancel_hook_list, hook); - - g_mutex_unlock (mail_msg_lock); -} - -void -mail_cancel_all (void) -{ - camel_operation_cancel_all (); - - g_mutex_lock (mail_msg_lock); - - if (cancel_hook_list.is_setup) - g_hook_list_invoke (&cancel_hook_list, FALSE); - - g_mutex_unlock (mail_msg_lock); -} - -static guint idle_source_id = 0; -G_LOCK_DEFINE_STATIC (idle_source_id); -static GAsyncQueue *main_loop_queue = NULL; -static GAsyncQueue *msg_reply_queue = NULL; -static GThread *main_thread = NULL; - -static gboolean -mail_msg_idle_cb (void) -{ - MailMsg *msg; - - g_return_val_if_fail (main_loop_queue != NULL, FALSE); - g_return_val_if_fail (msg_reply_queue != NULL, FALSE); - - G_LOCK (idle_source_id); - idle_source_id = 0; - G_UNLOCK (idle_source_id); - /* check the main loop queue */ - while ((msg = g_async_queue_try_pop (main_loop_queue)) != NULL) { - GCancellable *cancellable; - - cancellable = e_activity_get_cancellable (msg->activity); - - g_idle_add_full ( - G_PRIORITY_DEFAULT, - (GSourceFunc) mail_msg_submit, - g_object_ref (msg->activity), - (GDestroyNotify) g_object_unref); - if (msg->info->exec != NULL) - msg->info->exec (msg, cancellable, &msg->error); - if (msg->info->done != NULL) - msg->info->done (msg); - mail_msg_unref (msg); - } - - /* check the reply queue */ - while ((msg = g_async_queue_try_pop (msg_reply_queue)) != NULL) { - if (msg->info->done != NULL) - msg->info->done (msg); - mail_msg_check_error (msg); - mail_msg_unref (msg); - } - return FALSE; -} - -static void -mail_msg_proxy (MailMsg *msg) -{ - GCancellable *cancellable; - - cancellable = e_activity_get_cancellable (msg->activity); - - if (msg->info->desc != NULL) { - gchar *text = msg->info->desc (msg); - camel_operation_push_message (cancellable, "%s", text); - g_free (text); - } - - g_idle_add_full ( - G_PRIORITY_DEFAULT, - (GSourceFunc) mail_msg_submit, - g_object_ref (msg->activity), - (GDestroyNotify) g_object_unref); - - if (msg->info->exec != NULL) - msg->info->exec (msg, cancellable, &msg->error); - - if (msg->info->desc != NULL) - camel_operation_pop_message (cancellable); - - g_async_queue_push (msg_reply_queue, msg); - - G_LOCK (idle_source_id); - if (idle_source_id == 0) - idle_source_id = g_idle_add ( - (GSourceFunc) mail_msg_idle_cb, NULL); - G_UNLOCK (idle_source_id); -} - -void -mail_msg_init (void) -{ - mail_msg_lock = g_mutex_new (); - mail_msg_cond = g_cond_new (); - - main_loop_queue = g_async_queue_new (); - msg_reply_queue = g_async_queue_new (); - - mail_msg_active_table = g_hash_table_new (NULL, NULL); - main_thread = g_thread_self (); -} - -static gint -mail_msg_compare (const MailMsg *msg1, - const MailMsg *msg2) -{ - gint priority1 = msg1->priority; - gint priority2 = msg2->priority; - - if (priority1 == priority2) - return 0; - - return (priority1 < priority2) ? 1 : -1; -} - -static gpointer -create_thread_pool (gpointer data) -{ - GThreadPool *thread_pool; - gint max_threads = GPOINTER_TO_INT (data); - - /* once created, run forever */ - thread_pool = g_thread_pool_new ( - (GFunc) mail_msg_proxy, NULL, max_threads, FALSE, NULL); - g_thread_pool_set_sort_function ( - thread_pool, (GCompareDataFunc) mail_msg_compare, NULL); - - return thread_pool; -} - -void -mail_msg_main_loop_push (gpointer msg) -{ - g_async_queue_push_sorted (main_loop_queue, msg, - (GCompareDataFunc) mail_msg_compare, NULL); - - G_LOCK (idle_source_id); - if (idle_source_id == 0) - idle_source_id = g_idle_add ( - (GSourceFunc) mail_msg_idle_cb, NULL); - G_UNLOCK (idle_source_id); -} - -void -mail_msg_unordered_push (gpointer msg) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (10)); - - g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); -} - -void -mail_msg_fast_ordered_push (gpointer msg) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); - - g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); -} - -void -mail_msg_slow_ordered_push (gpointer msg) -{ - static GOnce once = G_ONCE_INIT; - - g_once (&once, (GThreadFunc) create_thread_pool, GINT_TO_POINTER (1)); - - g_thread_pool_push ((GThreadPool *) once.retval, msg, NULL); -} - -gboolean -mail_in_main_thread (void) -{ - return (g_thread_self () == main_thread); -} - -/* ********************************************************************** */ - -struct _call_msg { - MailMsg base; - - mail_call_t type; - MailMainFunc func; - gpointer ret; - va_list ap; - EFlag *done; -}; - -static void -do_call (struct _call_msg *m, - GCancellable *cancellable, - GError **error) -{ - gpointer p1, *p2, *p3, *p4, *p5; - gint i1; - va_list ap; - - G_VA_COPY (ap, m->ap); - - switch (m->type) { - case MAIL_CALL_p_p: - p1 = va_arg (ap, gpointer ); - m->ret = m->func (p1); - break; - case MAIL_CALL_p_pp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2); - break; - case MAIL_CALL_p_ppp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - p3 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, p3); - break; - case MAIL_CALL_p_pppp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - p3 = va_arg (ap, gpointer ); - p4 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, p3, p4); - break; - case MAIL_CALL_p_ppppp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - p3 = va_arg (ap, gpointer ); - p4 = va_arg (ap, gpointer ); - p5 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, p3, p4, p5); - break; - case MAIL_CALL_p_ppippp: - p1 = va_arg (ap, gpointer ); - p2 = va_arg (ap, gpointer ); - i1 = va_arg (ap, gint); - p3 = va_arg (ap, gpointer ); - p4 = va_arg (ap, gpointer ); - p5 = va_arg (ap, gpointer ); - m->ret = m->func (p1, p2, i1, p3, p4, p5); - break; - } - - e_activity_set_state ( - m->base.activity, - g_cancellable_is_cancelled (cancellable) ? - E_ACTIVITY_CANCELLED : E_ACTIVITY_COMPLETED); - - if (m->done != NULL) - e_flag_set (m->done); -} - -static MailMsgInfo mail_call_info = { - sizeof (struct _call_msg), - (MailMsgDescFunc) NULL, - (MailMsgExecFunc) do_call, - (MailMsgDoneFunc) NULL, - (MailMsgFreeFunc) NULL -}; - -gpointer -mail_call_main (mail_call_t type, - MailMainFunc func, - ...) -{ - GCancellable *cancellable; - struct _call_msg *m; - gpointer ret; - va_list ap; - - va_start (ap, func); - - m = mail_msg_new (&mail_call_info); - m->type = type; - m->func = func; - G_VA_COPY (m->ap, ap); - - cancellable = e_activity_get_cancellable (m->base.activity); - - if (mail_in_main_thread ()) - do_call (m, cancellable, &m->base.error); - else { - mail_msg_ref (m); - m->done = e_flag_new (); - mail_msg_main_loop_push (m); - e_flag_wait (m->done); - e_flag_free (m->done); - } - - va_end (ap); - - ret = m->ret; - mail_msg_unref (m); - - return ret; -} - -void -mail_mt_set_backend (gchar *backend) -{ - shell_builtin_backend = backend; -} - |