summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backends/evolution/EvolutionSyncSource.h11
-rw-r--r--src/syncevo/EDSClient.cpp7
-rw-r--r--src/syncevo/SyncContext.cpp7
-rw-r--r--src/syncevo/util.cpp51
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