mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-12-27 07:56:14 +01:00
Merge branch 'appinfo-shellany-thread-pool' into 'master'
GWin32AppInfo: Use a thread pool for async appinfo tree rebuilds See merge request GNOME/glib!1754
This commit is contained in:
commit
c16e1db576
@ -49,6 +49,7 @@
|
|||||||
#include "gmemorymonitordbus.h"
|
#include "gmemorymonitordbus.h"
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
#include "gregistrysettingsbackend.h"
|
#include "gregistrysettingsbackend.h"
|
||||||
|
#include "giowin32-priv.h"
|
||||||
#endif
|
#endif
|
||||||
#include <glib/gstdio.h>
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
@ -1068,7 +1069,10 @@ DllMain (HINSTANCE hinstDLL,
|
|||||||
LPVOID lpvReserved)
|
LPVOID lpvReserved)
|
||||||
{
|
{
|
||||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||||
|
{
|
||||||
gio_dll = hinstDLL;
|
gio_dll = hinstDLL;
|
||||||
|
gio_win32_appinfo_init (FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,8 @@ GOutputStream *
|
|||||||
g_win32_output_stream_new_from_fd (gint fd,
|
g_win32_output_stream_new_from_fd (gint fd,
|
||||||
gboolean close_fd);
|
gboolean close_fd);
|
||||||
|
|
||||||
|
void
|
||||||
|
gio_win32_appinfo_init (gboolean do_wait);
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __G_IO_MODULE_PRIV_H__ */
|
#endif /* __G_IO_MODULE_PRIV_H__ */
|
||||||
|
@ -36,6 +36,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include <glib/gstdioprivate.h>
|
#include <glib/gstdioprivate.h>
|
||||||
|
#include "giowin32-priv.h"
|
||||||
#include "glib-private.h"
|
#include "glib-private.h"
|
||||||
|
|
||||||
/* We need to watch 8 places:
|
/* We need to watch 8 places:
|
||||||
@ -519,7 +520,26 @@ g_win32_appinfo_application_init (GWin32AppInfoApplication *self)
|
|||||||
self->verbs = g_ptr_array_new_with_free_func (g_object_unref);
|
self->verbs = g_ptr_array_new_with_free_func (g_object_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
G_LOCK_DEFINE_STATIC (gio_win32_appinfo);
|
/* The AppInfo threadpool that does asynchronous AppInfo tree rebuilds */
|
||||||
|
static GThreadPool *gio_win32_appinfo_threadpool;
|
||||||
|
|
||||||
|
/* This mutex is held by a thread that reads or writes the AppInfo tree.
|
||||||
|
* (tree object references can be obtained and later read without
|
||||||
|
* holding this mutex, since objects are practically immutable).
|
||||||
|
*/
|
||||||
|
static GMutex gio_win32_appinfo_mutex;
|
||||||
|
|
||||||
|
/* Any thread wanting to access AppInfo can wait on this condition */
|
||||||
|
static GCond gio_win32_appinfo_cond;
|
||||||
|
|
||||||
|
/* Increased to indicate that AppInfo tree does needs to be rebuilt.
|
||||||
|
* AppInfo thread checks this to see if it needs to
|
||||||
|
* do a tree re-build. If the value changes during a rebuild,
|
||||||
|
* another rebuild is triggered after that.
|
||||||
|
* Other threads check this to see if they need
|
||||||
|
* to wait for a tree re-build to finish.
|
||||||
|
*/
|
||||||
|
static gint gio_win32_appinfo_update_counter = 0;
|
||||||
|
|
||||||
/* Map of owned ".ext" (with '.', UTF-8, folded)
|
/* Map of owned ".ext" (with '.', UTF-8, folded)
|
||||||
* to GWin32AppInfoFileExtension ptr
|
* to GWin32AppInfoFileExtension ptr
|
||||||
@ -3046,6 +3066,19 @@ update_registry_data (void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This function is called when any of our registry watchers detect
|
||||||
|
* changes in the registry.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
keys_updated (GWin32RegistryKey *key,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
/* 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 */
|
||||||
|
g_thread_pool_push (gio_win32_appinfo_threadpool, (gpointer) keys_updated, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
watch_keys (void)
|
watch_keys (void)
|
||||||
{
|
{
|
||||||
@ -3055,7 +3088,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3065,7 +3098,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3075,7 +3108,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3085,7 +3118,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3095,7 +3128,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3105,7 +3138,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3115,7 +3148,7 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
@ -3125,14 +3158,45 @@ watch_keys (void)
|
|||||||
G_WIN32_REGISTRY_WATCH_NAME |
|
G_WIN32_REGISTRY_WATCH_NAME |
|
||||||
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
G_WIN32_REGISTRY_WATCH_ATTRIBUTES |
|
||||||
G_WIN32_REGISTRY_WATCH_VALUES,
|
G_WIN32_REGISTRY_WATCH_VALUES,
|
||||||
NULL,
|
keys_updated,
|
||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This is the main function of the AppInfo thread */
|
||||||
static void
|
static void
|
||||||
g_win32_appinfo_init (void)
|
gio_win32_appinfo_thread_func (gpointer data,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
gint saved_counter;
|
||||||
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
|
saved_counter = g_atomic_int_get (&gio_win32_appinfo_update_counter);
|
||||||
|
|
||||||
|
if (saved_counter > 0)
|
||||||
|
update_registry_data ();
|
||||||
|
/* If the counter didn't change while we were working, then set it to zero.
|
||||||
|
* Otherwise we need to rebuild the tree again, so keep it greater than zero.
|
||||||
|
* Numeric value doesn't matter - even if we're asked to rebuild N times,
|
||||||
|
* we just need to rebuild once, and as long as there were no new rebuild
|
||||||
|
* requests while we were working, we're done.
|
||||||
|
*/
|
||||||
|
if (g_atomic_int_compare_and_exchange (&gio_win32_appinfo_update_counter,
|
||||||
|
saved_counter,
|
||||||
|
0))
|
||||||
|
g_cond_broadcast (&gio_win32_appinfo_cond);
|
||||||
|
|
||||||
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes Windows AppInfo. Creates the registry watchers,
|
||||||
|
* the AppInfo thread, and initiates an update of the AppInfo tree.
|
||||||
|
* Called with do_wait = `FALSE` at startup to prevent it from
|
||||||
|
* blocking until the tree is updated. All subsequent calls
|
||||||
|
* from everywhere else are made with do_wait = `TRUE`, blocking
|
||||||
|
* until the tree is re-built (if needed).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
gio_win32_appinfo_init (gboolean do_wait)
|
||||||
{
|
{
|
||||||
static gsize initialized;
|
static gsize initialized;
|
||||||
|
|
||||||
@ -3165,11 +3229,31 @@ g_win32_appinfo_init (void)
|
|||||||
|
|
||||||
watch_keys ();
|
watch_keys ();
|
||||||
|
|
||||||
update_registry_data ();
|
/* We don't really require an exclusive pool, but the implementation
|
||||||
|
* details might cause the g_thread_pool_push() call below to block
|
||||||
|
* if the pool is not exclusive (specifically - for POSIX threads backend
|
||||||
|
* lacking thread scheduler settings).
|
||||||
|
*/
|
||||||
|
gio_win32_appinfo_threadpool = g_thread_pool_new (gio_win32_appinfo_thread_func,
|
||||||
|
NULL,
|
||||||
|
1,
|
||||||
|
TRUE,
|
||||||
|
NULL);
|
||||||
|
g_mutex_init (&gio_win32_appinfo_mutex);
|
||||||
|
g_cond_init (&gio_win32_appinfo_cond);
|
||||||
|
g_atomic_int_set (&gio_win32_appinfo_update_counter, 1);
|
||||||
|
/* Trigger initial tree build. Fake data pointer. */
|
||||||
|
g_thread_pool_push (gio_win32_appinfo_threadpool, (gpointer) keys_updated, NULL);
|
||||||
|
|
||||||
g_once_init_leave (&initialized, TRUE);
|
g_once_init_leave (&initialized, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!do_wait)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If any of the keys had a change, then we've already initiated
|
||||||
|
* a tree re-build in keys_updated(). Just wait for it to finish.
|
||||||
|
*/
|
||||||
if ((url_associations_key && g_win32_registry_key_has_changed (url_associations_key)) ||
|
if ((url_associations_key && g_win32_registry_key_has_changed (url_associations_key)) ||
|
||||||
(file_exts_key && g_win32_registry_key_has_changed (file_exts_key)) ||
|
(file_exts_key && g_win32_registry_key_has_changed (file_exts_key)) ||
|
||||||
(user_clients_key && g_win32_registry_key_has_changed (user_clients_key)) ||
|
(user_clients_key && g_win32_registry_key_has_changed (user_clients_key)) ||
|
||||||
@ -3179,10 +3263,11 @@ g_win32_appinfo_init (void)
|
|||||||
(system_registered_apps_key && g_win32_registry_key_has_changed (system_registered_apps_key)) ||
|
(system_registered_apps_key && g_win32_registry_key_has_changed (system_registered_apps_key)) ||
|
||||||
(classes_root_key && g_win32_registry_key_has_changed (classes_root_key)))
|
(classes_root_key && g_win32_registry_key_has_changed (classes_root_key)))
|
||||||
{
|
{
|
||||||
G_LOCK (gio_win32_appinfo);
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
update_registry_data ();
|
while (g_atomic_int_get (&gio_win32_appinfo_update_counter) > 0)
|
||||||
|
g_cond_wait (&gio_win32_appinfo_cond, &gio_win32_appinfo_mutex);
|
||||||
watch_keys ();
|
watch_keys ();
|
||||||
G_UNLOCK (gio_win32_appinfo);
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3248,8 +3333,8 @@ g_win32_app_info_new_from_app (GWin32AppInfoApplication *app,
|
|||||||
|
|
||||||
new_info->app = g_object_ref (app);
|
new_info->app = g_object_ref (app);
|
||||||
|
|
||||||
g_win32_appinfo_init ();
|
gio_win32_appinfo_init (TRUE);
|
||||||
G_LOCK (gio_win32_appinfo);
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
g_hash_table_iter_init (&iter, new_info->app->supported_exts);
|
g_hash_table_iter_init (&iter, new_info->app->supported_exts);
|
||||||
@ -3274,7 +3359,7 @@ g_win32_app_info_new_from_app (GWin32AppInfoApplication *app,
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
G_UNLOCK (gio_win32_appinfo);
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
new_info->supported_types[i] = NULL;
|
new_info->supported_types[i] = NULL;
|
||||||
|
|
||||||
@ -4216,13 +4301,13 @@ g_app_info_get_default_for_uri_scheme (const char *uri_scheme)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_win32_appinfo_init ();
|
gio_win32_appinfo_init (TRUE);
|
||||||
G_LOCK (gio_win32_appinfo);
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
g_set_object (&scheme, g_hash_table_lookup (urls, scheme_down));
|
g_set_object (&scheme, g_hash_table_lookup (urls, scheme_down));
|
||||||
g_free (scheme_down);
|
g_free (scheme_down);
|
||||||
|
|
||||||
G_UNLOCK (gio_win32_appinfo);
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
result = NULL;
|
result = NULL;
|
||||||
|
|
||||||
@ -4252,14 +4337,14 @@ g_app_info_get_default_for_type (const char *content_type,
|
|||||||
if (!ext_down)
|
if (!ext_down)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
g_win32_appinfo_init ();
|
gio_win32_appinfo_init (TRUE);
|
||||||
G_LOCK (gio_win32_appinfo);
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
/* Assuming that "content_type" is a file extension, not a MIME type */
|
/* Assuming that "content_type" is a file extension, not a MIME type */
|
||||||
g_set_object (&ext, g_hash_table_lookup (extensions, ext_down));
|
g_set_object (&ext, g_hash_table_lookup (extensions, ext_down));
|
||||||
g_free (ext_down);
|
g_free (ext_down);
|
||||||
|
|
||||||
G_UNLOCK (gio_win32_appinfo);
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
if (ext == NULL)
|
if (ext == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -4309,15 +4394,15 @@ g_app_info_get_all (void)
|
|||||||
GList *apps;
|
GList *apps;
|
||||||
GList *apps_i;
|
GList *apps_i;
|
||||||
|
|
||||||
g_win32_appinfo_init ();
|
gio_win32_appinfo_init (TRUE);
|
||||||
G_LOCK (gio_win32_appinfo);
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
apps = NULL;
|
apps = NULL;
|
||||||
g_hash_table_iter_init (&iter, apps_by_id);
|
g_hash_table_iter_init (&iter, apps_by_id);
|
||||||
while (g_hash_table_iter_next (&iter, NULL, &value))
|
while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||||
apps = g_list_prepend (apps, g_object_ref (G_OBJECT (value)));
|
apps = g_list_prepend (apps, g_object_ref (G_OBJECT (value)));
|
||||||
|
|
||||||
G_UNLOCK (gio_win32_appinfo);
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
infos = NULL;
|
infos = NULL;
|
||||||
for (apps_i = apps; apps_i; apps_i = apps_i->next)
|
for (apps_i = apps; apps_i; apps_i = apps_i->next)
|
||||||
@ -4345,14 +4430,14 @@ g_app_info_get_all_for_type (const char *content_type)
|
|||||||
if (!ext_down)
|
if (!ext_down)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
g_win32_appinfo_init ();
|
gio_win32_appinfo_init (TRUE);
|
||||||
G_LOCK (gio_win32_appinfo);
|
g_mutex_lock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
/* Assuming that "content_type" is a file extension, not a MIME type */
|
/* Assuming that "content_type" is a file extension, not a MIME type */
|
||||||
g_set_object (&ext, g_hash_table_lookup (extensions, ext_down));
|
g_set_object (&ext, g_hash_table_lookup (extensions, ext_down));
|
||||||
g_free (ext_down);
|
g_free (ext_down);
|
||||||
|
|
||||||
G_UNLOCK (gio_win32_appinfo);
|
g_mutex_unlock (&gio_win32_appinfo_mutex);
|
||||||
|
|
||||||
if (ext == NULL)
|
if (ext == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Loading…
Reference in New Issue
Block a user