diff options
-rw-r--r-- | src/backends/evolution/EvolutionSyncSource.h | 11 | ||||
-rw-r--r-- | src/syncevo/EDSClient.cpp | 7 | ||||
-rw-r--r-- | src/syncevo/SyncContext.cpp | 7 | ||||
-rw-r--r-- | src/syncevo/util.cpp | 51 |
4 files changed, 53 insertions, 23 deletions
diff --git a/src/backends/evolution/EvolutionSyncSource.h b/src/backends/evolution/EvolutionSyncSource.h index ccdcf2ea..dfaa67c2 100644 --- a/src/backends/evolution/EvolutionSyncSource.h +++ b/src/backends/evolution/EvolutionSyncSource.h @@ -120,12 +120,19 @@ class EvolutionAsync { public: EvolutionAsync() { - m_loop = GMainLoopCXX(g_main_loop_new(NULL, FALSE), false); + m_loop = GMainLoopCXX(g_main_loop_new(NULL, TRUE), false); } /** start processing events */ void run() { - g_main_loop_run(m_loop.get()); + if (g_main_context_is_owner(g_main_context_default())) { + g_main_loop_run(m_loop.get()); + } else { + // Let master thread handle events. + while (g_main_loop_is_running(m_loop.get())) { + Sleep(0.1); + } + } } /** stop processing events, to be called inside run() by callback */ diff --git a/src/syncevo/EDSClient.cpp b/src/syncevo/EDSClient.cpp index 3077d9e7..ad140c87 100644 --- a/src/syncevo/EDSClient.cpp +++ b/src/syncevo/EDSClient.cpp @@ -77,7 +77,12 @@ ESourceRegistryCXX EDSRegistryLoader::sync() if (m_gerror) { m_gerror.throwError("creating source registry"); } - g_main_context_iteration(NULL, true); + // Only master thread can drive the event processing. + if (g_main_context_is_owner(g_main_context_default())) { + g_main_context_iteration(NULL, true); + } else { + Sleep(0.1); + } } } diff --git a/src/syncevo/SyncContext.cpp b/src/syncevo/SyncContext.cpp index da8a066f..148f8c68 100644 --- a/src/syncevo/SyncContext.cpp +++ b/src/syncevo/SyncContext.cpp @@ -2901,6 +2901,13 @@ void SyncContext::initMain(const char *appname) // redirect glib logging into our own logging g_log_set_default_handler(Logger::glogFunc, NULL); + + // Only the main thread may use the default GMainContext. + // Anything else is unsafe, see https://mail.gnome.org/archives/gtk-list/2013-April/msg00040.html + // util.cpp:Sleep() checks this and uses the default context + // when called by the main thread, otherwise falls back to + // select(). + g_main_context_acquire(NULL); #endif if (atoi(getEnv("SYNCEVOLUTION_DEBUG", "0")) > 3) { SySync_ConsolePrintf = Logger::sysyncPrintf; diff --git a/src/syncevo/util.cpp b/src/syncevo/util.cpp index 63b12a27..b27a7999 100644 --- a/src/syncevo/util.cpp +++ b/src/syncevo/util.cpp @@ -764,31 +764,42 @@ double Sleep(double seconds) SuspendFlags &s = SuspendFlags::getSuspendFlags(); if (s.getState() == SuspendFlags::NORMAL) { #ifdef HAVE_GLIB - bool triggered = false; - GLibEvent timeout(g_timeout_add(seconds * 1000, - SleepTimeout, - &triggered), - "glib timeout"); - while (!triggered) { - if (s.getState() != SuspendFlags::NORMAL) { - break; + // Only use glib if we are the owner of the main context. + // Otherwise we would interfere (?) with that owner or + // depend on it to drive the context (?). The glib docs + // don't say anything about this; in practice, it was + // observed that with some versions of glib, a second + // thread just blocked here when the main thread was not + // processing glib events. + if (g_main_context_is_owner(g_main_context_default())) { + bool triggered = false; + GLibEvent timeout(g_timeout_add(seconds * 1000, + SleepTimeout, + &triggered), + "glib timeout"); + while (!triggered) { + if (s.getState() != SuspendFlags::NORMAL) { + break; + } + g_main_context_iteration(NULL, true); } - g_main_context_iteration(NULL, true); - } - // done - return 0; -#else - // Only works when abort or suspend requests are delivered via signal. - // Not the case when used inside helper processes; but those have - // and depend on glib. - timeval delay; - delay.tv_sec = floor(seconds); - delay.tv_usec = (seconds - (double)delay.tv_sec) * 1e6; - if (select(0, NULL, NULL, NULL, &delay) != -1) { // done return 0; } #endif + + // Fallback when glib is not available or unusable (= outside the main thread). + // Busy loop to detect abort requests. + Timespec deadline = start + Timespec(floor(seconds), (seconds - floor(seconds)) * 1e9); + while (deadline > Timespec::monotonic()) { + timeval delay; + delay.tv_sec = 0; + delay.tv_usec = 1e5; + select(0, NULL, NULL, NULL, &delay); + if (s.getState() != SuspendFlags::NORMAL) { + break; + } + } } // not done normally, calculate remaining time |