diff --git a/gio/ChangeLog b/gio/ChangeLog index 484ef2973..333d74e6e 100644 --- a/gio/ChangeLog +++ b/gio/ChangeLog @@ -1,3 +1,28 @@ +2007-12-19 Alexander Larsson + + * giomodule.c: + Make g_io_modules_load_all_in_directory not unuse + loaded modules so that users of it can do stuff + before unloading. + Init internal "module" types. + Initialize static prio and name for types so that + we don't have to load modules to get it. + + * gnativevolumemonitor.h: + * gvolumemonitor.h: + Move is_supported to parent class so that + non-native monitors can avoid being initialized + too. (For instance GDaemonVolumeMonitor if we're + not using GDaemonVfs.) + + * glocaldirectorymonitor.[ch]: + * glocalfilemonitor.[ch]: + * gunionvolumemonitor.c: + * gunixvolumemonitor.c: + * gvfs.c: + Find plugins using the static prio+name to + avoid unnecessarily loading the modules. + 2007-12-19 Alexander Larsson * giomodule.c: diff --git a/gio/giomodule.c b/gio/giomodule.c index 2e0a92625..1b0b3887a 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -24,6 +24,10 @@ #include "giomodule.h" #include "giomodule-priv.h" +#include "glocalfilemonitor.h" +#include "glocaldirectorymonitor.h" +#include "gnativevolumemonitor.h" +#include "gvfs.h" #include "gioalias.h" @@ -179,9 +183,13 @@ is_valid_module_name (const gchar *basename) * g_io_modules_load_all_in_directory: * @dirname: pathname for a directory containing modules to load. * - * Loads all the modules in the the specified directory. + * Loads all the modules in the the specified directory. * - * Returns: a list of #GIOModules loaded from the directory + * Returns: a list of #GIOModules loaded from the directory, + * All the modules are loaded into memory, if you want to + * unload them (enabling on-demand loading) you must call + * g_type_module_unuse() on all the modules. Free the list + * with g_list_free(). **/ GList * g_io_modules_load_all_in_directory (const char *dirname) @@ -218,8 +226,6 @@ g_io_modules_load_all_in_directory (const char *dirname) g_free (path); - g_type_module_unuse (G_TYPE_MODULE (module)); - modules = g_list_prepend (modules, module); } } @@ -231,20 +237,89 @@ g_io_modules_load_all_in_directory (const char *dirname) G_LOCK_DEFINE_STATIC (loaded_dirs); +extern GType _g_inotify_directory_monitor_get_type (void); +extern GType _g_inotify_file_monitor_get_type (void); +extern GType _g_unix_volume_monitor_get_type (void); +extern GType _g_local_vfs_get_type (void); + void _g_io_modules_ensure_loaded (void) { - GList *modules; + GList *modules, *l; static gboolean loaded_dirs = FALSE; - + int i; + GType *types; + guint n_types; + GQuark private_q, name_q; + G_LOCK (loaded_dirs); if (!loaded_dirs) { loaded_dirs = TRUE; modules = g_io_modules_load_all_in_directory (GIO_MODULE_DIR); + + private_q = g_quark_from_static_string ("gio-prio"); + name_q = g_quark_from_static_string ("gio-name"); + + /* Initialize types from built-in "modules" */ +#if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H) + _g_inotify_directory_monitor_get_type (); + _g_inotify_file_monitor_get_type (); +#endif +#ifdef G_OS_UNIX + _g_unix_volume_monitor_get_type (); +#endif + _g_local_vfs_get_type (); + + /* Copy over all prios to static gtype data so + * we can avoid loading the module again + */ + + types = g_type_children (G_TYPE_LOCAL_FILE_MONITOR, &n_types); + for (i = 0; i < n_types; i++) + { + GLocalFileMonitorClass *klass = g_type_class_ref (types[i]); + g_type_set_qdata (types[i], private_q, GINT_TO_POINTER (klass->prio)); + g_type_class_unref (klass); + } + g_free (types); + + types = g_type_children (G_TYPE_LOCAL_DIRECTORY_MONITOR, &n_types); + for (i = 0; i < n_types; i++) + { + GLocalDirectoryMonitorClass *klass = g_type_class_ref (types[i]); + g_type_set_qdata (types[i], private_q, GINT_TO_POINTER (klass->prio)); + g_type_class_unref (klass); + } + g_free (types); + + types = g_type_children (G_TYPE_NATIVE_VOLUME_MONITOR, &n_types); + for (i = 0; i < n_types; i++) + { + GNativeVolumeMonitorClass *klass = g_type_class_ref (types[i]); + g_type_set_qdata (types[i], private_q, GINT_TO_POINTER (klass->priority)); + g_type_set_qdata (types[i], name_q, g_strdup (klass->name)); + g_type_class_unref (klass); + } + g_free (types); + + types = g_type_children (G_TYPE_VFS, &n_types); + for (i = 0; i < n_types; i++) + { + GVfsClass *klass = g_type_class_ref (types[i]); + g_type_set_qdata (types[i], private_q, GINT_TO_POINTER (klass->priority)); + g_type_set_qdata (types[i], name_q, g_strdup (klass->name)); + g_type_class_unref (klass); + } + g_free (types); + + for (l = modules; l != NULL; l = l->next) + g_type_module_unuse (G_TYPE_MODULE (l->data)); + + g_list_free (modules); } - + G_UNLOCK (loaded_dirs); } diff --git a/gio/glocaldirectorymonitor.c b/gio/glocaldirectorymonitor.c index 5f8262ff7..1ee3de75d 100644 --- a/gio/glocaldirectorymonitor.c +++ b/gio/glocaldirectorymonitor.c @@ -196,76 +196,70 @@ mounts_changed (GUnixMountMonitor *mount_monitor, } static gint -_compare_monitor_class_by_prio (gconstpointer a, - gconstpointer b, - gpointer user_data) +_compare_monitor_type_by_prio (gconstpointer _a, + gconstpointer _b, + gpointer user_data) { - GType *type1 = (GType *) a, *type2 = (GType *) b; - GLocalDirectoryMonitorClass *klass1, *klass2; + const GType *a = _a, *b = _b; + int prio_a, prio_b; gint ret; + GQuark private_q; - klass1 = G_LOCAL_DIRECTORY_MONITOR_CLASS (g_type_class_ref (*type1)); - klass2 = G_LOCAL_DIRECTORY_MONITOR_CLASS (g_type_class_ref (*type2)); + private_q = g_quark_from_static_string ("gio-prio"); - ret = klass1->prio - klass2->prio; + prio_a = GPOINTER_TO_INT (g_type_get_qdata (*a, private_q)); + prio_b = GPOINTER_TO_INT (g_type_get_qdata (*b, private_q)); - g_type_class_unref (klass1); - g_type_class_unref (klass2); + ret = prio_b - prio_a; return ret; } -extern GType _g_inotify_directory_monitor_get_type (void); - static gpointer get_default_local_directory_monitor (gpointer data) { - GType *monitor_impls, chosen_type; + GType *monitor_impls; guint n_monitor_impls; - GType *ret = (GType *) data; gint i; - -#if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H) - /* Register Inotify monitor */ - _g_inotify_directory_monitor_get_type (); -#endif + GLocalDirectoryMonitorClass *chosen_class; + GLocalDirectoryMonitorClass **ret = data; _g_io_modules_ensure_loaded (); monitor_impls = g_type_children (G_TYPE_LOCAL_DIRECTORY_MONITOR, &n_monitor_impls); - chosen_type = G_TYPE_INVALID; - - /* Ref all classes once so we don't load/unload them a lot */ - for (i = 0; i < n_monitor_impls; i++) - g_type_class_ref (monitor_impls[i]); - g_qsort_with_data (monitor_impls, n_monitor_impls, sizeof (GType), - _compare_monitor_class_by_prio, + _compare_monitor_type_by_prio, NULL); - for (i = n_monitor_impls - 1; i >= 0 && chosen_type == G_TYPE_INVALID; i--) + chosen_class = NULL; + for (i = 0; i < n_monitor_impls; i++) { GLocalDirectoryMonitorClass *klass; - + klass = G_LOCAL_DIRECTORY_MONITOR_CLASS (g_type_class_ref (monitor_impls[i])); - + if (klass->is_supported()) - chosen_type = monitor_impls[i]; - - g_type_class_unref (klass); + { + chosen_class = klass; + break; + } + else + g_type_class_unref (klass); } - for (i = 0; i < n_monitor_impls; i++) - g_type_class_unref (g_type_class_peek (monitor_impls[i])); - g_free (monitor_impls); - *ret = chosen_type; - - return NULL; + + if (chosen_class) + { + *ret = chosen_class; + return (gpointer)G_TYPE_FROM_CLASS (chosen_class); + } + else + return (gpointer)G_TYPE_INVALID; } /** @@ -280,14 +274,28 @@ _g_local_directory_monitor_new (const char* dirname, GFileMonitorFlags flags) { static GOnce once_init = G_ONCE_INIT; - static GType monitor_type = G_TYPE_INVALID; + GTypeClass *type_class; + GDirectoryMonitor *monitor; + GType type; - g_once (&once_init, get_default_local_directory_monitor, &monitor_type); + type_class = NULL; + g_once (&once_init, get_default_local_directory_monitor, &type_class); + type = (GType)once_init.retval; - if (monitor_type != G_TYPE_INVALID) - return G_DIRECTORY_MONITOR (g_object_new (monitor_type, "dirname", dirname, NULL)); + monitor = NULL; + if (type != G_TYPE_INVALID) + monitor = G_DIRECTORY_MONITOR (g_object_new (type, "dirname", dirname, NULL)); - return NULL; + /* This is non-null on first pass here. Unref the class now. + * This is to avoid unloading the module and then loading it + * again which would happen if we unrefed the class + * before creating the monitor. + */ + + if (type_class) + g_type_class_unref (type_class); + + return monitor; } static gboolean diff --git a/gio/glocaldirectorymonitor.h b/gio/glocaldirectorymonitor.h index 40fa1c210..bdb9e926f 100644 --- a/gio/glocaldirectorymonitor.h +++ b/gio/glocaldirectorymonitor.h @@ -51,6 +51,7 @@ struct _GLocalDirectoryMonitor struct _GLocalDirectoryMonitorClass { GDirectoryMonitorClass parent_class; gint prio; + char *name; /* Not used atm */ gboolean mount_notify; gboolean (*is_supported) (void); }; diff --git a/gio/glocalfilemonitor.c b/gio/glocalfilemonitor.c index 3b6621e74..b18c1c788 100644 --- a/gio/glocalfilemonitor.c +++ b/gio/glocalfilemonitor.c @@ -124,77 +124,70 @@ g_local_file_monitor_class_init (GLocalFileMonitorClass* klass) } static gint -_compare_monitor_class_by_prio (gconstpointer a, - gconstpointer b, - gpointer user_data) +_compare_monitor_type_by_prio (gconstpointer _a, + gconstpointer _b, + gpointer user_data) { - GType *type1 = (GType *) a, *type2 = (GType *) b; - GLocalFileMonitorClass *klass1, *klass2; + const GType *a = _a, *b = _b; + int prio_a, prio_b; gint ret; + GQuark private_q; - klass1 = G_LOCAL_FILE_MONITOR_CLASS (g_type_class_ref (*type1)); - klass2 = G_LOCAL_FILE_MONITOR_CLASS (g_type_class_ref (*type2)); + private_q = g_quark_from_static_string ("gio-prio"); - ret = klass1->prio - klass2->prio; + prio_a = GPOINTER_TO_INT (g_type_get_qdata (*a, private_q)); + prio_b = GPOINTER_TO_INT (g_type_get_qdata (*b, private_q)); - g_type_class_unref (klass1); - g_type_class_unref (klass2); + ret = prio_b - prio_a; return ret; } -extern GType _g_inotify_file_monitor_get_type (void); - static gpointer get_default_local_file_monitor (gpointer data) { - GType *monitor_impls, chosen_type; + GType *monitor_impls; guint n_monitor_impls; gint i; - GType *ret = (GType *) data; - -#if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H) - /* Register Inotify monitor */ - _g_inotify_file_monitor_get_type (); -#endif + GLocalFileMonitorClass *chosen_class; + GLocalFileMonitorClass **ret = data; _g_io_modules_ensure_loaded (); monitor_impls = g_type_children (G_TYPE_LOCAL_FILE_MONITOR, &n_monitor_impls); - chosen_type = G_TYPE_INVALID; - - /* Ref all classes once so we don't load/unload them a lot */ - for (i = 0; i < n_monitor_impls; i++) - g_type_class_ref (monitor_impls[i]); - g_qsort_with_data (monitor_impls, n_monitor_impls, sizeof (GType), - _compare_monitor_class_by_prio, + _compare_monitor_type_by_prio, NULL); - for (i = n_monitor_impls - 1; i >= 0 && chosen_type == G_TYPE_INVALID; i--) + chosen_class = NULL; + for (i = 0; i < n_monitor_impls; i++) { GLocalFileMonitorClass *klass; - + klass = G_LOCAL_FILE_MONITOR_CLASS (g_type_class_ref (monitor_impls[i])); - + if (klass->is_supported()) - chosen_type = monitor_impls[i]; - - g_type_class_unref (klass); + { + chosen_class = klass; + break; + } + else + g_type_class_unref (klass); } - for (i = 0; i < n_monitor_impls; i++) - g_type_class_unref (g_type_class_peek (monitor_impls[i])); - g_free (monitor_impls); - - *ret = chosen_type; - - return NULL; + + if (chosen_class) + { + *ret = chosen_class; + return (gpointer)G_TYPE_FROM_CLASS (chosen_class); + } + else + return (gpointer)G_TYPE_INVALID; } /** @@ -209,14 +202,28 @@ _g_local_file_monitor_new (const char *pathname, GFileMonitorFlags flags) { static GOnce once_init = G_ONCE_INIT; - static GType monitor_type = G_TYPE_INVALID; + GTypeClass *type_class; + GFileMonitor *monitor; + GType type; - g_once (&once_init, get_default_local_file_monitor, &monitor_type); + type_class = NULL; + g_once (&once_init, get_default_local_file_monitor, &type_class); + type = (GType)once_init.retval; - if (monitor_type != G_TYPE_INVALID) - return G_FILE_MONITOR (g_object_new (monitor_type, "filename", pathname, NULL)); + monitor = NULL; + if (type != G_TYPE_INVALID) + monitor = G_FILE_MONITOR (g_object_new (type, "filename", pathname, NULL)); - return NULL; + /* This is non-null on first pass here. Unref the class now. + * This is to avoid unloading the module and then loading it + * again which would happen if we unrefed the class + * before creating the monitor. + */ + + if (type_class) + g_type_class_unref (type_class); + + return monitor; } #define __G_LOCAL_FILE_MONITOR_C__ diff --git a/gio/glocalfilemonitor.h b/gio/glocalfilemonitor.h index 3b31661ef..e01ab0657 100644 --- a/gio/glocalfilemonitor.h +++ b/gio/glocalfilemonitor.h @@ -46,6 +46,7 @@ struct _GLocalFileMonitor struct _GLocalFileMonitorClass { GFileMonitorClass parent_class; gint prio; + char *name; /* Not used atm */ gboolean (*is_supported) (void); }; diff --git a/gio/gnativevolumemonitor.h b/gio/gnativevolumemonitor.h index ac1675522..f679e74cd 100644 --- a/gio/gnativevolumemonitor.h +++ b/gio/gnativevolumemonitor.h @@ -27,7 +27,6 @@ struct _GNativeVolumeMonitorClass { GMount * (*get_mount_for_mount_path) (const char *mount_path, GCancellable *cancellable); - gboolean (*is_supported) (void); }; GType g_native_volume_monitor_get_type (void) G_GNUC_CONST; diff --git a/gio/gunionvolumemonitor.c b/gio/gunionvolumemonitor.c index 772a060f1..8d50cd6af 100644 --- a/gio/gunionvolumemonitor.c +++ b/gio/gunionvolumemonitor.c @@ -398,24 +398,34 @@ compare_monitor_type (gconstpointer a, gconstpointer b, gpointer user_data) { - const GNativeVolumeMonitorClass *class_a, *class_b; + GType a_type, b_type; + char *a_name, *b_name; + int a_prio, b_prio; gint res; const char *use_this_monitor; + GQuark private_q, name_q; - class_a = a; - class_b = b; + private_q = g_quark_from_static_string ("gio-prio"); + name_q = g_quark_from_static_string ("gio-name"); + use_this_monitor = user_data; + a_type = *(GType *)a; + b_type = *(GType *)b; + a_prio = GPOINTER_TO_INT (g_type_get_qdata (a_type, private_q)); + a_name = g_type_get_qdata (a_type, name_q); + b_prio = GPOINTER_TO_INT (g_type_get_qdata (b_type, private_q)); + b_name = g_type_get_qdata (b_type, name_q); - if (class_a == class_b) + if (a_type == b_type) res = 0; else if (use_this_monitor != NULL && - strcmp (class_a->name, use_this_monitor) == 0) + strcmp (a_name, use_this_monitor) == 0) res = -1; else if (use_this_monitor != NULL && - strcmp (class_b->name, use_this_monitor) == 0) + strcmp (b_name, use_this_monitor) == 0) res = 1; else - res = class_b->priority - class_a->priority; + res = b_prio - a_prio; return res; } @@ -423,59 +433,42 @@ compare_monitor_type (gconstpointer a, static GType get_default_native_class (gpointer data) { - GNativeVolumeMonitorClass *klass; + GNativeVolumeMonitorClass *klass, *native_class, **native_class_out; GType *monitors; guint n_monitors; - GList *l; - GTypeClass *native_class; const char *use_this; int i; - GTypeClass **native_class_out; - GList *classes; native_class_out = data; use_this = g_getenv ("GIO_USE_VOLUME_MONITOR"); -#ifdef G_OS_UNIX - /* Ensure GUnixVolumeMonitor type is available */ - { - volatile GType unix_type; - /* volatile is required to avoid any G_GNUC_CONST optimizations */ - unix_type = _g_unix_volume_monitor_get_type (); - } -#endif - /* Ensure vfs in modules loaded */ _g_io_modules_ensure_loaded (); monitors = g_type_children (G_TYPE_NATIVE_VOLUME_MONITOR, &n_monitors); - classes = NULL; - /* Ref all classes once so we don't load/unload them a lot */ - for (i = 0; i < n_monitors; i++) - classes = g_list_prepend (classes, g_type_class_ref (monitors[i])); - - g_free (monitors); - - classes = g_list_sort_with_data (classes, - compare_monitor_type, - (gpointer)use_this); + g_qsort_with_data (monitors, + n_monitors, + sizeof (GType), + compare_monitor_type, + (gpointer)use_this); native_class = NULL; - for (l = classes; l != NULL; l = l->next) - { - klass = l->data; - - if (klass->is_supported ()) + for (i = 0; i < n_monitors; i++) + { + klass = g_type_class_ref (monitors[i]); + if (G_VOLUME_MONITOR_CLASS (klass)->is_supported()) { - native_class = (GTypeClass *)klass; + native_class = klass; break; } else g_type_class_unref (klass); } + g_free (monitors); + if (native_class) { *native_class_out = native_class; @@ -512,6 +505,7 @@ g_union_volume_monitor_init (GUnionVolumeMonitor *union_monitor) GType *monitors; guint n_monitors; GNativeVolumeMonitorClass *native_class; + GVolumeMonitorClass *klass; int i; native_class = get_native_class (); @@ -531,10 +525,15 @@ g_union_volume_monitor_init (GUnionVolumeMonitor *union_monitor) if (monitors[i] == G_TYPE_UNION_VOLUME_MONITOR || g_type_is_a (monitors[i], G_TYPE_NATIVE_VOLUME_MONITOR)) continue; - - monitor = g_object_new (monitors[i], NULL); - g_union_volume_monitor_add_monitor (union_monitor, monitor); - g_object_unref (monitor); + + klass = g_type_class_ref (monitors[i]); + if (klass->is_supported == NULL || klass->is_supported()) + { + monitor = g_object_new (monitors[i], NULL); + g_union_volume_monitor_add_monitor (union_monitor, monitor); + g_object_unref (monitor); + } + g_type_class_unref (klass); } g_free (monitors); diff --git a/gio/gunixvolumemonitor.c b/gio/gunixvolumemonitor.c index 4fc81e9f0..69b8e3663 100644 --- a/gio/gunixvolumemonitor.c +++ b/gio/gunixvolumemonitor.c @@ -166,10 +166,10 @@ g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass *klass) monitor_class->get_connected_drives = get_connected_drives; monitor_class->get_volume_for_uuid = get_volume_for_uuid; monitor_class->get_mount_for_uuid = get_mount_for_uuid; + monitor_class->is_supported = is_supported; native_class->priority = 0; native_class->name = "unix"; - native_class->is_supported = is_supported; native_class->get_mount_for_mount_path = get_mount_for_mount_path; } diff --git a/gio/gvfs.c b/gio/gvfs.c index 783f16ced..2d16516f1 100644 --- a/gio/gvfs.c +++ b/gio/gvfs.c @@ -175,32 +175,38 @@ compare_vfs_type (gconstpointer a, gconstpointer b, gpointer user_data) { - GVfsClass *class_a, *class_b; + GType a_type, b_type; + char *a_name, *b_name; + int a_prio, b_prio; gint res; - const char *use_this_vfs; - - class_a = g_type_class_ref (*(GType *)a); - class_b = g_type_class_ref (*(GType *)b); - use_this_vfs = user_data; + const char *use_this_monitor; + GQuark private_q, name_q; - if (class_a == class_b) + private_q = g_quark_from_static_string ("gio-prio"); + name_q = g_quark_from_static_string ("gio-name"); + + use_this_monitor = user_data; + a_type = *(GType *)a; + b_type = *(GType *)b; + a_prio = GPOINTER_TO_INT (g_type_get_qdata (a_type, private_q)); + a_name = g_type_get_qdata (a_type, name_q); + b_prio = GPOINTER_TO_INT (g_type_get_qdata (b_type, private_q)); + b_name = g_type_get_qdata (b_type, name_q); + + if (a_type == b_type) res = 0; - else if (use_this_vfs != NULL && - strcmp (class_a->name, use_this_vfs) == 0) + else if (use_this_monitor != NULL && + strcmp (a_name, use_this_monitor) == 0) res = -1; - else if (use_this_vfs != NULL && - strcmp (class_b->name, use_this_vfs) == 0) + else if (use_this_monitor != NULL && + strcmp (b_name, use_this_monitor) == 0) res = 1; else - res = class_b->priority - class_a->priority; - - g_type_class_unref (class_a); - g_type_class_unref (class_b); + res = b_prio - a_prio; return res; } - static gpointer get_default_vfs (gpointer arg) { @@ -210,15 +216,9 @@ get_default_vfs (gpointer arg) guint n_vfs_impls; const char *use_this; GVfs *vfs; - GType (*casted_get_type)(void); use_this = g_getenv ("GIO_USE_VFS"); - /* Ensure GLocalVfs type is available - the cast is required to avoid any G_GNUC_CONST optimizations */ - casted_get_type = _g_local_vfs_get_type; - local_type = casted_get_type (); - /* Ensure vfs in modules loaded */ _g_io_modules_ensure_loaded (); diff --git a/gio/gvolumemonitor.h b/gio/gvolumemonitor.h index 726627828..45fb6b793 100644 --- a/gio/gvolumemonitor.h +++ b/gio/gvolumemonitor.h @@ -88,6 +88,8 @@ struct _GVolumeMonitorClass { /* Vtable */ + gboolean (*is_supported) (void); + GList * (*get_connected_drives) (GVolumeMonitor *volume_monitor); GList * (*get_volumes) (GVolumeMonitor *volume_monitor); GList * (*get_mounts) (GVolumeMonitor *volume_monitor); @@ -101,6 +103,7 @@ struct _GVolumeMonitorClass { GVolume * (*adopt_orphan_mount) (GMount *mount); + /*< private >*/ /* Padding for future expansion */ void (*_g_reserved1) (void);