From 71f191b2a609e291a3afcf726ab8aacab572637b Mon Sep 17 00:00:00 2001 From: hiro Date: Thu, 17 Sep 2009 07:26:17 +0000 Subject: introduced multi-threading. git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@2255 ee746299-78ed-0310-b773-934348b2243d --- ChangeLog | 19 +++++++++++++ libsylph/filter.c | 2 +- libsylph/session.c | 12 ++++++--- libsylph/socket.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ libsylph/socket.h | 3 +++ libsylph/utils.c | 56 +++++++++++++++++++++++++++++++++++++++ libsylph/utils.h | 3 +++ src/compose.c | 4 +++ src/folderview.c | 15 +++++++++-- src/inc.c | 5 ++++ src/main.c | 21 ++++++++++----- src/rpop3.c | 4 +++ src/send_message.c | 11 ++++++++ src/sigstatus.c | 4 +++ src/trayicon.c | 3 +++ 15 files changed, 227 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index e9751409..10f83faa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2009-09-18 + + * introduced multi-threading. + * libsylph/session.c + libsylph/socket.[ch]: win32: connect() on another thread to avoid + UI blocking. + * libsylph/filter.c + libsylph/utils.[ch]: execute command on another thread to avoid + UI blocking. + * src/rpop3.c + src/compose.c + src/inc.c + src/trayicon.c + src/main.c + src/send_message.c + src/folderview.c + src/sigstatus.c: surround timeout/IO-watch callback functions with + gdk_threads_enter() and gdk_threads_leave(). + 2009-09-17 * folderview_new_folder_cb(): win32: fixed prohibited character check. diff --git a/libsylph/filter.c b/libsylph/filter.c index 9ea834ff..e61b5095 100644 --- a/libsylph/filter.c +++ b/libsylph/filter.c @@ -400,7 +400,7 @@ static gboolean filter_match_cond(FilterCond *cond, MsgInfo *msginfo, if (!file) return FALSE; cmdline = g_strconcat(cond->str_value, " \"", file, "\"", NULL); - ret = execute_command_line(cmdline, FALSE); + ret = execute_command_line_async_wait(cmdline); matched = (ret == 0); if (ret == -1) fltinfo->error = FLT_ERROR_EXEC_FAILED; diff --git a/libsylph/session.c b/libsylph/session.c index d64fc72d..0617e402 100644 --- a/libsylph/session.c +++ b/libsylph/session.c @@ -120,7 +120,8 @@ void session_init(Session *session) gint session_connect(Session *session, const gchar *server, gushort port) { #ifndef G_OS_UNIX - SockInfo *sock; + SockInfo *sock = NULL; + gint flag = 0; #endif g_return_val_if_fail(session != NULL, -1); g_return_val_if_fail(server != NULL, -1); @@ -143,8 +144,13 @@ gint session_connect(Session *session, const gchar *server, gushort port) return 0; #else - sock = sock_connect(server, port); - if (sock == NULL) { + session->conn_id = sock_connect_async(server, port); + if (session->conn_id < 0) { + g_warning("can't connect to server."); + session->state = SESSION_ERROR; + return -1; + } + if (sock_connect_async_wait(session->conn_id, &sock) < 0) { g_warning("can't connect to server."); session->state = SESSION_ERROR; return -1; diff --git a/libsylph/socket.c b/libsylph/socket.c index 97d273d7..431d95f1 100644 --- a/libsylph/socket.c +++ b/libsylph/socket.c @@ -81,11 +81,17 @@ struct _SockConnectData { gint id; gchar *hostname; gushort port; +#ifdef G_OS_UNIX GList *addr_list; GList *cur_addr; SockLookupData *lookup_data; GIOChannel *channel; guint io_tag; +#else + gint flag; + GThread *thread; + SockInfo *sock; +#endif SockConnectFunc func; gpointer data; }; @@ -1317,6 +1323,78 @@ static gint sock_get_address_info_async_cancel(SockLookupData *lookup_data) return 0; } +#else /* G_OS_UNIX */ + +gpointer sock_connect_async_func(gpointer data) +{ + SockConnectData *conn_data = (SockConnectData *)data; + + g_print("sock_connect_async_func: connect\n"); + conn_data->sock = sock_connect(conn_data->hostname, conn_data->port); + conn_data->flag = 1; + + g_print("sock_connect_async_func: connected\n"); + g_main_context_wakeup(NULL); + + return GINT_TO_POINTER(0); +} + +gint sock_connect_async(const gchar *hostname, gushort port) +{ + static gint id = 1; + SockConnectData *data; + + data = g_new0(SockConnectData, 1); + data->id = id++; + data->hostname = g_strdup(hostname); + data->port = port; + data->flag = 0; + + data->thread = g_thread_create(sock_connect_async_func, data, TRUE, + NULL); + if (!data->thread) { + g_free(data->hostname); + g_free(data); + return -1; + } + + sock_connect_data_list = g_list_append(sock_connect_data_list, data); + + return data->id; +} + +gint sock_connect_async_wait(gint id, SockInfo **sock) +{ + SockConnectData *conn_data = NULL; + GList *cur; + + for (cur = sock_connect_data_list; cur != NULL; cur = cur->next) { + if (((SockConnectData *)cur->data)->id == id) { + conn_data = (SockConnectData *)cur->data; + break; + } + } + + if (!conn_data) { + g_warning("sock_connect_async_wait: id %d not found.", id); + return -1; + } + + g_print("sock_connect_async_wait: waiting thread\n"); + while (conn_data->flag == 0) + g_main_context_iteration(NULL, TRUE); + + g_print("sock_connect_async_wait: flagged\n"); + g_thread_join(conn_data->thread); + g_print("sock_connect_async_wait: thread exited\n"); + + *sock = conn_data->sock; + + sock_connect_data_list = g_list_remove(sock_connect_data_list, + conn_data); + g_free(conn_data->hostname); + g_free(conn_data); +} #endif /* G_OS_UNIX */ diff --git a/libsylph/socket.h b/libsylph/socket.h index 5bf8b98f..0ddf0374 100644 --- a/libsylph/socket.h +++ b/libsylph/socket.h @@ -103,6 +103,9 @@ SockInfo *sock_connect (const gchar *hostname, gushort port); gint sock_connect_async (const gchar *hostname, gushort port, SockConnectFunc func, gpointer data); gint sock_connect_async_cancel (gint id); +#else +gint sock_connect_async (const gchar *hostname, gushort port); +gint sock_connect_async_wait (gint id, SockInfo **sock); #endif /* Basic I/O functions */ diff --git a/libsylph/utils.c b/libsylph/utils.c index 574f8427..0139302e 100644 --- a/libsylph/utils.c +++ b/libsylph/utils.c @@ -3862,6 +3862,62 @@ gint execute_command_line(const gchar *cmdline, gboolean async) return ret; } +typedef struct _CmdData +{ + const gchar *cmdline; + gint flag; + gint status; +} CmdData; + +static gpointer execute_command_line_async_func(gpointer data) +{ + CmdData *cmd_data = (CmdData *)data; + gchar **argv; + + g_print("execute_command_line_async_func\n"); + argv = strsplit_with_quote(cmd_data->cmdline, " ", 0); + cmd_data->status = execute_sync(argv); + g_strfreev(argv); + + g_print("execute_command_line_async_func: exec done.\n"); + cmd_data->flag = 1; + g_main_context_wakeup(NULL); + + return GINT_TO_POINTER(0); +} + +gint execute_command_line_async_wait(const gchar *cmdline) +{ + volatile CmdData data = {NULL, 0, 0}; + GThread *thread; + + if (debug_mode) { + gchar *utf8_cmdline; + + utf8_cmdline = g_filename_to_utf8 + (cmdline, -1, NULL, NULL, NULL); + debug_print("execute_command_line(): executing: %s\n", + utf8_cmdline ? utf8_cmdline : cmdline); + g_free(utf8_cmdline); + } + + data.cmdline = cmdline; + thread = g_thread_create(execute_command_line_async_func, &data, TRUE, + NULL); + if (!thread) + return -1; + + g_print("execute_command_line_async_wait: waiting thread\n"); + while (data.flag == 0) + g_main_context_iteration(NULL, TRUE); + + g_print("execute_command_line_async_wait: flagged\n"); + g_thread_join(thread); + g_print("execute_command_line_async_wait: thread exited\n"); + + return data.status; +} + gint execute_open_file(const gchar *file, const gchar *content_type) { g_return_val_if_fail(file != NULL, -1); diff --git a/libsylph/utils.h b/libsylph/utils.h index 97221fb9..3bbc42cb 100644 --- a/libsylph/utils.h +++ b/libsylph/utils.h @@ -469,6 +469,9 @@ gint execute_async (gchar *const argv[]); gint execute_sync (gchar *const argv[]); gint execute_command_line (const gchar *cmdline, gboolean async); +gint execute_command_line_async_wait + (const gchar *cmdline); + gint execute_open_file (const gchar *file, const gchar *content_type); gint execute_print_file (const gchar *file); diff --git a/src/compose.c b/src/compose.c index 69ec4844..c24729d7 100644 --- a/src/compose.c +++ b/src/compose.c @@ -7777,10 +7777,14 @@ static gboolean autosave_timeout(gpointer data) { Compose *compose = (Compose *)data; + gdk_threads_enter(); + debug_print("auto-saving...\n"); if (compose->modified) compose_draft_cb(data, 1, NULL); + gdk_threads_leave(); + return TRUE; } diff --git a/src/folderview.c b/src/folderview.c index f938e5c1..b0976750 100644 --- a/src/folderview.c +++ b/src/folderview.c @@ -3001,6 +3001,9 @@ static gint auto_expand_timeout(gpointer data) FolderView *folderview = data; GtkTreeView *treeview = GTK_TREE_VIEW(folderview->treeview); GtkTreePath *path = NULL; + gint ret; + + gdk_threads_enter(); gtk_tree_view_get_drag_dest_row(treeview, &path, NULL); @@ -3009,9 +3012,13 @@ static gint auto_expand_timeout(gpointer data) gtk_tree_path_free(path); folderview->expand_timeout = 0; - return FALSE; + ret = FALSE; } else - return TRUE; + ret = TRUE; + + gdk_threads_leave(); + + return ret; } static void remove_auto_expand_timeout(FolderView *folderview) @@ -3026,9 +3033,13 @@ static gint auto_scroll_timeout(gpointer data) { FolderView *folderview = data; + gdk_threads_enter(); + gtkut_tree_view_vertical_autoscroll (GTK_TREE_VIEW(folderview->treeview)); + gdk_threads_leave(); + return TRUE; } diff --git a/src/inc.c b/src/inc.c index 2e038d50..b9641b3b 100644 --- a/src/inc.c +++ b/src/inc.c @@ -1564,13 +1564,18 @@ static gint inc_autocheck_func(gpointer data) { MainWindow *mainwin = (MainWindow *)data; + gdk_threads_enter(); + if (inc_lock_count) { debug_print("autocheck is locked.\n"); inc_autocheck_timer_set_interval(1000); + gdk_threads_leave(); return FALSE; } inc_all_account_mail(mainwin, TRUE); + gdk_threads_leave(); + return FALSE; } diff --git a/src/main.c b/src/main.c index d012c90b..cb14d223 100644 --- a/src/main.c +++ b/src/main.c @@ -208,6 +208,9 @@ int main(int argc, char *argv[]) return 0; } +#if USE_THREADS + gdk_threads_enter(); +#endif gtk_set_locale(); gtk_init(&argc, &argv); @@ -217,13 +220,6 @@ int main(int argc, char *argv[]) gtk_widget_set_default_colormap(gdk_rgb_get_cmap()); gtk_widget_set_default_visual(gdk_rgb_get_visual()); -#if USE_THREADS || USE_LDAP - if (!g_thread_supported()) - g_thread_init(NULL); - if (!g_thread_supported()) - g_error(_("g_thread is not supported by glib.\n")); -#endif - parse_gtkrc_files(); setup_rc_dir(); @@ -341,6 +337,9 @@ int main(int argc, char *argv[]) update_check(FALSE); gtk_main(); +#if USE_THREADS + gdk_threads_leave(); +#endif return 0; } @@ -582,6 +581,14 @@ static gint get_queued_message_num(void) static void app_init(void) { +#if USE_THREADS + if (!g_thread_supported()) + g_thread_init(NULL); + if (!g_thread_supported()) + g_error("g_thread is not supported by glib."); + else + gdk_threads_init(); +#endif syl_init(); prog_version = PROG_VERSION; diff --git a/src/rpop3.c b/src/rpop3.c index 347f1a83..aee98956 100644 --- a/src/rpop3.c +++ b/src/rpop3.c @@ -608,6 +608,8 @@ static void rpop3_clear_list(void) static gboolean rpop3_ping_cb(gpointer data) { + gdk_threads_enter(); + if (rpop3_window.ping_tag > 0) { g_source_remove(rpop3_window.ping_tag); rpop3_window.ping_tag = 0; @@ -615,6 +617,8 @@ static gboolean rpop3_ping_cb(gpointer data) if (rpop3_window.session->state == POP3_IDLE) rpop3_noop_send(rpop3_window.session); + gdk_threads_leave(); + return FALSE; } diff --git a/src/send_message.c b/src/send_message.c index db474602..c44232d4 100644 --- a/src/send_message.c +++ b/src/send_message.c @@ -795,9 +795,12 @@ static gint send_recv_message(Session *session, const gchar *msg, gpointer data) g_return_val_if_fail(dialog != NULL, -1); + gdk_threads_enter(); + switch (smtp_session->state) { case SMTP_READY: case SMTP_CONNECTED: + gdk_threads_leave(); return 0; case SMTP_HELO: g_snprintf(buf, sizeof(buf), _("Sending HELO...")); @@ -832,14 +835,18 @@ static gint send_recv_message(Session *session, const gchar *msg, gpointer data) break; case SMTP_ERROR: g_warning("send: error: %s\n", msg); + gdk_threads_leave(); return 0; default: + gdk_threads_leave(); return 0; } progress_dialog_set_label(dialog->dialog, buf); progress_dialog_set_row_status(dialog->dialog, 0, state_str); + gdk_threads_leave(); + return 0; } @@ -855,6 +862,8 @@ static gint send_send_data_progressive(Session *session, guint cur_len, SMTP_SESSION(session)->state != SMTP_EOM) return 0; + gdk_threads_enter(); + g_snprintf(buf, sizeof(buf), _("Sending message (%d / %d bytes)"), cur_len, total_len); progress_dialog_set_label(dialog->dialog, buf); @@ -866,6 +875,7 @@ static gint send_send_data_progressive(Session *session, guint cur_len, #ifdef G_OS_WIN32 GTK_EVENTS_FLUSH(); #endif + gdk_threads_leave(); return 0; } @@ -877,6 +887,7 @@ static gint send_send_data_finished(Session *session, guint len, gpointer data) g_return_val_if_fail(dialog != NULL, -1); send_send_data_progressive(session, len, len, dialog); + return 0; } diff --git a/src/sigstatus.c b/src/sigstatus.c index 5d4cafa1..d4d23723 100644 --- a/src/sigstatus.c +++ b/src/sigstatus.c @@ -161,10 +161,14 @@ static gint timeout_cb(gpointer data) { GpgmegtkSigStatus hd = data; + gdk_threads_enter(); + hd->running = 0; hd->timeout_id_valid = 0; do_destroy(hd); + gdk_threads_leave(); + return FALSE; } diff --git a/src/trayicon.c b/src/trayicon.c index b142916e..9416141f 100644 --- a/src/trayicon.c +++ b/src/trayicon.c @@ -203,8 +203,11 @@ static guint notify_tag = 0; gboolean notify_timeout_cb(gpointer data) { + gdk_threads_enter(); gtk_status_icon_set_blinking(trayicon.status_icon, FALSE); notify_tag = 0; + gdk_threads_leave(); + return FALSE; } -- cgit v1.2.3