From e4af910d04a1e4733e3912e85fa891425e813187 Mon Sep 17 00:00:00 2001 From: "Dirk-Jan C. Binnema" Date: Sat, 29 Apr 2023 00:52:37 +0300 Subject: [PATCH] utils: implement g_cancellable_new_with_timeout --- lib/utils/mu-utils-file.cc | 49 ++++++++++++++++++++++++++++++++++++++ lib/utils/mu-utils-file.hh | 12 ++++++++++ 2 files changed, 61 insertions(+) diff --git a/lib/utils/mu-utils-file.cc b/lib/utils/mu-utils-file.cc index 021d4c6e..e1b9a10d 100644 --- a/lib/utils/mu-utils-file.cc +++ b/lib/utils/mu-utils-file.cc @@ -178,6 +178,55 @@ Mu::runtime_path(Mu::RuntimePath path, const std::string& muhome) } } +static gpointer +cancel_wait(gpointer data) +{ + guint timeout, deadline; + GCancellable *cancel; + + cancel = (GCancellable*)data; + timeout = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(cancel), "timeout")); + deadline = g_get_monotonic_time() + 1000 * timeout; + + while (g_get_monotonic_time() < deadline && !g_cancellable_is_cancelled(cancel)) { + g_usleep(50 * 1000); /* 50 ms */ + g_thread_yield(); + } + + g_cancellable_cancel(cancel); + + return NULL; +} + +static void +cancel_wait_free(gpointer data) +{ + GThread *thread; + GCancellable *cancel; + + cancel = (GCancellable*)data; + thread = (GThread*)g_object_get_data(G_OBJECT(cancel), "thread"); + + g_cancellable_cancel(cancel); + g_thread_join(thread); +} + +GCancellable* +Mu::g_cancellable_new_with_timeout(guint timeout) +{ + GCancellable *cancel; + + cancel = g_cancellable_new(); + + g_object_set_data(G_OBJECT(cancel), "timeout", GUINT_TO_POINTER(timeout)); + g_object_set_data(G_OBJECT(cancel), "thread", + g_thread_new("cancel-wait", cancel_wait, cancel)); + g_object_set_data_full(G_OBJECT(cancel), "cancel", cancel, cancel_wait_free); + + + return cancel; +} + #ifdef BUILD_TESTS diff --git a/lib/utils/mu-utils-file.hh b/lib/utils/mu-utils-file.hh index b9e6d920..5fae29c7 100644 --- a/lib/utils/mu-utils-file.hh +++ b/lib/utils/mu-utils-file.hh @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -157,6 +158,17 @@ std::string join_paths(S&& s, Args...args) { } +/** + * Like g_cancellable_new(), but automatically cancels itself + * after timeout + * + * @param timeout timeout in millisecs + * + * @return A GCancellable* instances; free with g_object_unref() when + * no longer needed. + */ +GCancellable* g_cancellable_new_with_timeout(guint timeout); + } // namespace Mu #endif /* MU_UTILS_FILE_HH__ */