summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <David.Woodhouse@intel.com>2010-06-25 18:09:09 +0100
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-06-28 14:04:51 +0100
commit13557c29ce41064a2850bb3f1e0d3c84a23d79d8 (patch)
tree18ca91b95f3a2434168517efa5f6f519ad2630fd
parent7542842bcaf47323d519a1ec49b818315baf2dcd (diff)
downloadevolution-data-server-13557c29ce41064a2850bb3f1e0d3c84a23d79d8.tar.gz
Fix idle thread exit and locking
If we trigger its exit and wait for it while still holding the lock, it may deadlock on the same lock. Also fix a multiple-unlock bug. (cherry picked from commit ab8442ff77654a54cd6556bc73533bc386408c60)
-rw-r--r--camel/providers/imapx/camel-imapx-server.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/camel/providers/imapx/camel-imapx-server.c b/camel/providers/imapx/camel-imapx-server.c
index 7b1c8159f..01449fc94 100644
--- a/camel/providers/imapx/camel-imapx-server.c
+++ b/camel/providers/imapx/camel-imapx-server.c
@@ -2054,16 +2054,19 @@ imapx_idle_thread (gpointer data)
while (TRUE) {
CamelIMAPXFolder *ifolder;
+
e_flag_clear (is->idle->idle_start_watch);
IDLE_LOCK(is->idle);
while ((ifolder = (CamelIMAPXFolder *) is->select_folder) &&
- is->idle->state == IMAPX_IDLE_PENDING) {
+ is->idle->state == IMAPX_IDLE_PENDING &&
+ !is->idle->idle_exit) {
time_t dwelled = time(NULL) - is->idle->started;
if (dwelled < IMAPX_IDLE_DWELL_TIME) {
IDLE_UNLOCK(is->idle);
g_usleep((IMAPX_IDLE_DWELL_TIME - dwelled) * G_USEC_PER_SEC);
+ IDLE_LOCK(is->idle);
continue;
}
IDLE_UNLOCK(is->idle);
@@ -2078,6 +2081,7 @@ imapx_idle_thread (gpointer data)
/* No way to asyncronously notify UI ? */
camel_exception_clear (ex);
}
+ IDLE_LOCK(is->idle);
}
IDLE_UNLOCK(is->idle);
@@ -2136,6 +2140,7 @@ static void
imapx_exit_idle (CamelIMAPXServer *is)
{
CamelIMAPXIdle *idle = is->idle;
+ GThread *thread = NULL;
if (!idle)
return;
@@ -2146,13 +2151,16 @@ imapx_exit_idle (CamelIMAPXServer *is)
idle->idle_exit = TRUE;
e_flag_set (idle->idle_start_watch);
- if (idle->idle_thread)
- g_thread_join (idle->idle_thread);
+ thread = idle->idle_thread;
+ idle->idle_thread = 0;
}
idle->idle_thread = NULL;
IDLE_UNLOCK (idle);
+ if (thread)
+ g_thread_join (thread);
+
g_mutex_free (idle->idle_lock);
if (idle->idle_start_watch)
e_flag_free (idle->idle_start_watch);