From 8c25302726a60b1b5c216326a14c474fc41f1aed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sat, 31 Jul 2021 10:50:12 +0000 Subject: [PATCH 1/3] GWin32RegistryKey: Change STATUS_SUCCESS handling This function can, in fact, return STATUS_SUCCESS. We shouldn't assert that it doesn't. For now interpret it just like STATUS_PENDING (i.e. APC will be called), see how it goes (it isn't documented how the function behaves in this case, we have to play it by ear). Note that while we *can* use a better-documented RegNotifyChangeKeyValue() here, it communicates back to us via event objects, which means that the registry watcher would have to interact with the main loop directly and insert its events (plural; one event per key) there. That would make the API more complicated. Whereas the internal NT function communicates by calling an APC - we're good as long as something somewhere puts the thread in alertable state. --- gio/gwin32registrykey.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index 398d8f45b..d1ac09041 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -2550,9 +2550,7 @@ g_win32_registry_key_watch (GWin32RegistryKey *key, 0, TRUE); - g_assert (status != STATUS_SUCCESS); - - if (status == STATUS_PENDING) + if (status == STATUS_PENDING || status == STATUS_SUCCESS) return TRUE; g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN); From 6885a29428dd6f522a9486d0cbd8225f4198696e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sat, 31 Jul 2021 10:57:44 +0000 Subject: [PATCH 2/3] GWin32RegistryKey: ensure reqeueing works correctly If a key watch is renewed from the key watch callback, it results in the callback being NULL, since we clear it after we call it. Rearrange the function to make sure that the changes done by the callback function are preserved properly. --- gio/gwin32registrykey.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index d1ac09041..5e2b006dd 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -2425,17 +2425,20 @@ key_changed (PVOID closure, ULONG reserved) { GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (closure); + gpointer user_data; + GWin32RegistryKeyWatchCallbackFunc callback; + + callback = g_steal_pointer (&key->priv->callback); + user_data = g_steal_pointer (&key->priv->user_data); g_free (status_block); g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_CHANGED); g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED); key->priv->update_flags = G_WIN32_REGISTRY_UPDATED_NOTHING; - if (key->priv->callback) - key->priv->callback (key, key->priv->user_data); + if (callback) + callback (key, user_data); - key->priv->callback = NULL; - key->priv->user_data = NULL; g_object_unref (key); } From 4e9e7bfd34f33c66a4d25a082f91e9e2a3e231a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sat, 31 Jul 2021 11:01:06 +0000 Subject: [PATCH 3/3] GWin32AppInfo: re-trigger registry watcher from the callback To ensure that the watch is properly re-set every time, call watch_keys() from the watch callback. Previously the watch was only renewed after a data update was done in a worker thread, which made no sense, since the update function was implemented in such a way that it can (and should) be re-triggered on each key change, until the changes stop coming, and that can only happen if we renew the registry watcher right away. --- gio/gwin32appinfo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 5403225e2..4074f402c 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -3828,6 +3828,9 @@ update_registry_data (void) return; } +static void +watch_keys (void); + /* This function is called when any of our registry watchers detect * changes in the registry. */ @@ -3835,6 +3838,7 @@ static void keys_updated (GWin32RegistryKey *key, gpointer user_data) { + watch_keys (); /* Indicate the tree as not up-to-date, push a new job for the AppInfo thread */ g_atomic_int_inc (&gio_win32_appinfo_update_counter); /* We don't use the data pointer, but it must be non-NULL */ @@ -4029,7 +4033,6 @@ gio_win32_appinfo_init (gboolean do_wait) g_mutex_lock (&gio_win32_appinfo_mutex); while (g_atomic_int_get (&gio_win32_appinfo_update_counter) > 0) g_cond_wait (&gio_win32_appinfo_cond, &gio_win32_appinfo_mutex); - watch_keys (); g_mutex_unlock (&gio_win32_appinfo_mutex); } }