race/deadlock/cleanup fix in gnome-vfs-method.c
- From: jacob berkman <jacob ximian com>
- To: Nautilus <nautilus-list lists eazel com>
- Subject: race/deadlock/cleanup fix in gnome-vfs-method.c
- Date: 09 Jul 2002 14:45:47 -0400
there was a possible race condition that i mentioned yesterday, and
after actually trying that patch out i found that it would deadlock
loading the applications: method (since that recursively tries to load
the file: method).
this patch works around that, and also cleans up / simplifies most of
the locking in that file, such that there are now only 2 locks/unlocks.
i have actually tried this patch and i haven't had any problems.
for some reason i am worried about locking in the rest of gnome-vfs...
- jacob
Index: gnome-vfs-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-method.c,v
retrieving revision 1.22
diff -u -r1.22 gnome-vfs-method.c
--- gnome-vfs-method.c 4 Sep 2001 22:22:58 -0000 1.22
+++ gnome-vfs-method.c 9 Jul 2002 18:12:46 -0000
@@ -44,21 +44,17 @@
typedef struct _ModuleElement ModuleElement;
static gboolean method_already_initialized = FALSE;
-G_LOCK_DEFINE_STATIC (method_already_initialized);
static GHashTable *module_hash = NULL;
-G_LOCK_DEFINE_STATIC (module_hash);
+G_LOCK_DEFINE_STATIC (gnome_vfs_method);
static GList *module_path_list = NULL;
-G_LOCK_DEFINE_STATIC (module_path_list);
static gboolean
init_hash_table (void)
{
- G_LOCK (module_hash);
module_hash = g_hash_table_new (g_str_hash, g_str_equal);
- G_UNLOCK (module_hash);
return TRUE;
}
@@ -101,25 +97,16 @@
init_path_list (void)
{
const gchar *user_path_list;
- gboolean retval;
- retval = TRUE;
-
- G_LOCK (module_path_list);
-
- if (module_path_list != NULL) {
- retval = TRUE;
- goto end;
- }
+ if (module_path_list != NULL)
+ return TRUE;
/* User-supplied path. */
user_path_list = getenv ("GNOME_VFS_MODULE_PATH");
if (user_path_list != NULL) {
- if (! install_path_list (user_path_list)) {
- retval = FALSE;
- goto end;
- }
+ if (! install_path_list (user_path_list))
+ return FALSE;
}
/* Default path. It comes last so that users can override it. */
@@ -127,30 +114,28 @@
module_path_list = g_list_append (module_path_list,
g_strdup (GNOME_VFS_MODULE_DIR));
- end:
- G_UNLOCK (module_path_list);
- return retval;
+ return TRUE;
}
gboolean
gnome_vfs_method_init (void)
{
- G_LOCK (method_already_initialized);
+ G_LOCK (gnome_vfs_method);
- if (method_already_initialized) {
- G_UNLOCK (method_already_initialized);
- return TRUE;
- }
+ if (method_already_initialized)
+ goto gnome_vfs_method_init_out;
if (! init_hash_table ())
- return FALSE;
+ goto gnome_vfs_method_init_out;
if (! init_path_list ())
- return FALSE;
+ goto gnome_vfs_method_init_out;
method_already_initialized = TRUE;
- G_UNLOCK (method_already_initialized);
- return TRUE;
+ gnome_vfs_method_init_out:
+ G_UNLOCK (gnome_vfs_method);
+
+ return method_already_initialized;
}
static void
@@ -270,7 +255,7 @@
}
}
-static gboolean
+static ModuleElement *
gnome_vfs_add_module_to_hash_table (const gchar *name)
{
GnomeVFSMethod *method = NULL;
@@ -281,16 +266,40 @@
gid_t saved_gid;
const char *args;
- G_LOCK (module_hash);
+ /*
+ * it's ok for this function to recurse in one thread -
+ * eg. the applications: method's init function tries to load
+ * the file: method.
+ *
+ * however, we don't want multiple threads in here mucking
+ * with the hash table at the same time, so we do use the
+ * mutex.
+ *
+ * we do not guard against cyclic method dependencies, ie
+ * method foo: trying to load bar: as it's easy for methods to
+ * Just Not Do That
+ *
+ * we use a GPrivate as a per-thread lock on the shared mutex
+ */
+ static GStaticPrivate priv_key = G_STATIC_PRIVATE_INIT;
+ gpointer was_locked;
+
+ was_locked = g_static_private_get (&priv_key);
+ if (!was_locked) {
+ g_static_private_set (&priv_key, GINT_TO_POINTER (1), NULL);
+ G_LOCK (gnome_vfs_method);
+ }
+
module_element = g_hash_table_lookup (module_hash, name);
- G_UNLOCK (module_hash);
if (module_element != NULL)
- return TRUE;
+ goto add_module_out;
module_name = gnome_vfs_configuration_get_module_path (name, &args);
- if (module_name == NULL)
- return FALSE;
+ if (module_name == NULL) {
+ module_element = NULL;
+ goto add_module_out;
+ }
/* Set the effective UID/GID to the user UID/GID to prevent attacks to
setuid/setgid executables. */
@@ -308,19 +317,25 @@
seteuid (saved_uid);
setegid (saved_gid);
- if (method == NULL && transform == NULL)
- return FALSE;
+ if (method == NULL && transform == NULL) {
+ module_element = NULL;
+ goto add_module_out;
+ }
module_element = g_new (ModuleElement, 1);
module_element->name = g_strdup (name);
module_element->method = method;
module_element->transform = transform;
- G_LOCK (module_hash);
g_hash_table_insert (module_hash, module_element->name, module_element);
- G_UNLOCK (module_hash);
- return TRUE;
+ add_module_out:
+ if (!was_locked) {
+ g_static_private_set (&priv_key, NULL, NULL);
+ G_UNLOCK (gnome_vfs_method);
+ }
+
+ return module_element;
}
GnomeVFSMethod *
@@ -330,23 +345,8 @@
g_return_val_if_fail (name != NULL, NULL);
- G_LOCK (module_hash);
- module_element = g_hash_table_lookup (module_hash, name);
- G_UNLOCK (module_hash);
-
- if (module_element != NULL)
- return module_element->method;
-
- if (gnome_vfs_add_module_to_hash_table (name)) {
- G_LOCK (module_hash);
- module_element = g_hash_table_lookup (module_hash, name);
- G_UNLOCK (module_hash);
-
- if (module_element != NULL)
- return module_element->method;
- }
-
- return NULL;
+ module_element = gnome_vfs_add_module_to_hash_table (name);
+ return module_element ? module_element->method : NULL;
}
GnomeVFSTransform *
@@ -356,21 +356,6 @@
g_return_val_if_fail (name != NULL, NULL);
- G_LOCK (module_hash);
- module_element = g_hash_table_lookup (module_hash, name);
- G_UNLOCK (module_hash);
-
- if (module_element != NULL)
- return module_element->transform;
-
- if (gnome_vfs_add_module_to_hash_table (name)) {
- G_LOCK (module_hash);
- module_element = g_hash_table_lookup (module_hash, name);
- G_UNLOCK (module_hash);
-
- if (module_element != NULL)
- return module_element->transform;
- }
-
- return NULL;
+ module_element = gnome_vfs_add_module_to_hash_table (name);
+ return module_element ? module_element->transform : NULL;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]