summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaciej Mrozowski <reavertm@gentoo.org>2010-08-05 19:17:22 +0000
committerMaciej Mrozowski <reavertm@gentoo.org>2010-08-05 19:17:22 +0000
commit1ed0a63891508090ced1b40c21aaa0dcad31e8e4 (patch)
tree7f599fa458e1fdd87fe6e820655bcfd1e536e215 /sys-apps/dbus/files
parentMask www-client/chromium dev channel release. (diff)
downloadgentoo-2-1ed0a63891508090ced1b40c21aaa0dcad31e8e4.tar.gz
gentoo-2-1ed0a63891508090ced1b40c21aaa0dcad31e8e4.tar.bz2
gentoo-2-1ed0a63891508090ced1b40c21aaa0dcad31e8e4.zip
Commited backport from master to 1.2.24 (bug https://bugs.freedesktop.org/show_bug.cgi?id=17754) - patch to fix thread safety in protected_change_timeout for further review.
(Portage version: 2.2_rc67/cvs/Linux x86_64)
Diffstat (limited to 'sys-apps/dbus/files')
-rw-r--r--sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch393
1 files changed, 393 insertions, 0 deletions
diff --git a/sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch b/sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch
new file mode 100644
index 000000000000..79ffd51e2dd0
--- /dev/null
+++ b/sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch
@@ -0,0 +1,393 @@
+https://bugs.freedesktop.org/show_bug.cgi?id=17754
+
+backport from 6ff1d079316cb730a54b4e0e95bd3e6e31f439de (master)
+
+diff -ru ../dbus-1.2.24/dbus/dbus-connection.c ./dbus/dbus-connection.c
+--- ../dbus-1.2.24/dbus/dbus-connection.c 2010-03-23 20:01:32.000000000 +0100
++++ ./dbus/dbus-connection.c 2010-08-04 07:20:00.310381625 +0200
+@@ -73,6 +73,14 @@
+ _dbus_mutex_unlock ((connection)->mutex); \
+ } while (0)
+
++#define SLOTS_LOCK(connection) do { \
++ _dbus_mutex_lock ((connection)->slot_mutex); \
++ } while (0)
++
++#define SLOTS_UNLOCK(connection) do { \
++ _dbus_mutex_unlock ((connection)->slot_mutex); \
++ } while (0)
++
+ #define DISPATCH_STATUS_NAME(s) \
+ ((s) == DBUS_DISPATCH_COMPLETE ? "complete" : \
+ (s) == DBUS_DISPATCH_DATA_REMAINS ? "data remains" : \
+@@ -257,6 +265,7 @@
+
+ DBusList *filter_list; /**< List of filters. */
+
++ DBusMutex *slot_mutex; /**< Lock on slot_list so overall connection lock need not be taken */
+ DBusDataSlotList slot_list; /**< Data stored by allocated integer ID */
+
+ DBusHashTable *pending_replies; /**< Hash of message serials to #DBusPendingCall. */
+@@ -647,39 +656,42 @@
+ DBusWatchToggleFunction toggle_function,
+ dbus_bool_t enabled)
+ {
+- DBusWatchList *watches;
+ dbus_bool_t retval;
+-
++
+ HAVE_LOCK_CHECK (connection);
+
+- /* This isn't really safe or reasonable; a better pattern is the "do everything, then
+- * drop lock and call out" one; but it has to be propagated up through all callers
++ /* The original purpose of protected_change_watch() was to hold a
++ * ref on the connection while dropping the connection lock, then
++ * calling out to the app. This was a broken hack that did not
++ * work, since the connection was in a hosed state (no WatchList
++ * field) while calling out.
++ *
++ * So for now we'll just keep the lock while calling out. This means
++ * apps are not allowed to call DBusConnection methods inside a
++ * watch function or they will deadlock.
++ *
++ * The "real fix" is to use the _and_unlock() pattern found
++ * elsewhere in the code, to defer calling out to the app until
++ * we're about to drop locks and return flow of control to the app
++ * anyway.
++ *
++ * See http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144
+ */
+-
+- watches = connection->watches;
+- if (watches)
+- {
+- connection->watches = NULL;
+- _dbus_connection_ref_unlocked (connection);
+- CONNECTION_UNLOCK (connection);
+
++ if (connection->watches)
++ {
+ if (add_function)
+- retval = (* add_function) (watches, watch);
++ retval = (* add_function) (connection->watches, watch);
+ else if (remove_function)
+ {
+ retval = TRUE;
+- (* remove_function) (watches, watch);
++ (* remove_function) (connection->watches, watch);
+ }
+ else
+ {
+ retval = TRUE;
+- (* toggle_function) (watches, watch, enabled);
++ (* toggle_function) (connection->watches, watch, enabled);
+ }
+-
+- CONNECTION_LOCK (connection);
+- connection->watches = watches;
+- _dbus_connection_unref_unlocked (connection);
+-
+ return retval;
+ }
+ else
+@@ -768,39 +780,42 @@
+ DBusTimeoutToggleFunction toggle_function,
+ dbus_bool_t enabled)
+ {
+- DBusTimeoutList *timeouts;
+ dbus_bool_t retval;
+-
++
+ HAVE_LOCK_CHECK (connection);
+
+- /* This isn't really safe or reasonable; a better pattern is the "do everything, then
+- * drop lock and call out" one; but it has to be propagated up through all callers
++ /* The original purpose of protected_change_timeout() was to hold a
++ * ref on the connection while dropping the connection lock, then
++ * calling out to the app. This was a broken hack that did not
++ * work, since the connection was in a hosed state (no TimeoutList
++ * field) while calling out.
++ *
++ * So for now we'll just keep the lock while calling out. This means
++ * apps are not allowed to call DBusConnection methods inside a
++ * timeout function or they will deadlock.
++ *
++ * The "real fix" is to use the _and_unlock() pattern found
++ * elsewhere in the code, to defer calling out to the app until
++ * we're about to drop locks and return flow of control to the app
++ * anyway.
++ *
++ * See http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144
+ */
+-
+- timeouts = connection->timeouts;
+- if (timeouts)
+- {
+- connection->timeouts = NULL;
+- _dbus_connection_ref_unlocked (connection);
+- CONNECTION_UNLOCK (connection);
+
++ if (connection->timeouts)
++ {
+ if (add_function)
+- retval = (* add_function) (timeouts, timeout);
++ retval = (* add_function) (connection->timeouts, timeout);
+ else if (remove_function)
+ {
+ retval = TRUE;
+- (* remove_function) (timeouts, timeout);
++ (* remove_function) (connection->timeouts, timeout);
+ }
+ else
+ {
+ retval = TRUE;
+- (* toggle_function) (timeouts, timeout, enabled);
++ (* toggle_function) (connection->timeouts, timeout, enabled);
+ }
+-
+- CONNECTION_LOCK (connection);
+- connection->timeouts = timeouts;
+- _dbus_connection_unref_unlocked (connection);
+-
+ return retval;
+ }
+ else
+@@ -1239,6 +1254,10 @@
+ if (connection->io_path_cond == NULL)
+ goto error;
+
++ _dbus_mutex_new_at_location (&connection->slot_mutex);
++ if (connection->slot_mutex == NULL)
++ goto error;
++
+ disconnect_message = dbus_message_new_signal (DBUS_PATH_LOCAL,
+ DBUS_INTERFACE_LOCAL,
+ "Disconnected");
+@@ -1315,6 +1334,7 @@
+ _dbus_mutex_free_at_location (&connection->mutex);
+ _dbus_mutex_free_at_location (&connection->io_path_mutex);
+ _dbus_mutex_free_at_location (&connection->dispatch_mutex);
++ _dbus_mutex_free_at_location (&connection->slot_mutex);
+ dbus_free (connection);
+ }
+ if (pending_replies)
+@@ -2558,9 +2578,14 @@
+
+ /* The connection lock is better than the global
+ * lock in the atomic increment fallback
++ *
++ * (FIXME but for now we always use the atomic version,
++ * to avoid taking the connection lock, due to
++ * the mess with set_timeout_functions()/set_watch_functions()
++ * calling out to the app without dropping locks)
+ */
+
+-#ifdef DBUS_HAVE_ATOMIC_INT
++#if 1
+ _dbus_atomic_inc (&connection->refcount);
+ #else
+ CONNECTION_LOCK (connection);
+@@ -2672,6 +2697,8 @@
+ _dbus_mutex_free_at_location (&connection->io_path_mutex);
+ _dbus_mutex_free_at_location (&connection->dispatch_mutex);
+
++ _dbus_mutex_free_at_location (&connection->slot_mutex);
++
+ _dbus_mutex_free_at_location (&connection->mutex);
+
+ dbus_free (connection);
+@@ -2706,9 +2733,14 @@
+
+ /* The connection lock is better than the global
+ * lock in the atomic increment fallback
++ *
++ * (FIXME but for now we always use the atomic version,
++ * to avoid taking the connection lock, due to
++ * the mess with set_timeout_functions()/set_watch_functions()
++ * calling out to the app without dropping locks)
+ */
+
+-#ifdef DBUS_HAVE_ATOMIC_INT
++#if 1
+ last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
+ #else
+ CONNECTION_LOCK (connection);
+@@ -4652,9 +4684,11 @@
+ * should be that dbus_connection_set_watch_functions() has no effect,
+ * but the add_function and remove_function may have been called.
+ *
+- * @todo We need to drop the lock when we call the
+- * add/remove/toggled functions which can be a side effect
+- * of setting the watch functions.
++ * @note The thread lock on DBusConnection is held while
++ * watch functions are invoked, so inside these functions you
++ * may not invoke any methods on DBusConnection or it will deadlock.
++ * See the comments in the code or http://lists.freedesktop.org/archives/dbus/2007-July/tread.html#8144
++ * if you encounter this issue and want to attempt writing a patch.
+ *
+ * @param connection the connection.
+ * @param add_function function to begin monitoring a new descriptor.
+@@ -4673,42 +4707,17 @@
+ DBusFreeFunction free_data_function)
+ {
+ dbus_bool_t retval;
+- DBusWatchList *watches;
+
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+
+ CONNECTION_LOCK (connection);
+
+-#ifndef DBUS_DISABLE_CHECKS
+- if (connection->watches == NULL)
+- {
+- _dbus_warn_check_failed ("Re-entrant call to %s is not allowed\n",
+- _DBUS_FUNCTION_NAME);
+- return FALSE;
+- }
+-#endif
+-
+- /* ref connection for slightly better reentrancy */
+- _dbus_connection_ref_unlocked (connection);
+-
+- /* This can call back into user code, and we need to drop the
+- * connection lock when it does. This is kind of a lame
+- * way to do it.
+- */
+- watches = connection->watches;
+- connection->watches = NULL;
+- CONNECTION_UNLOCK (connection);
+-
+- retval = _dbus_watch_list_set_functions (watches,
++ retval = _dbus_watch_list_set_functions (connection->watches,
+ add_function, remove_function,
+ toggled_function,
+ data, free_data_function);
+- CONNECTION_LOCK (connection);
+- connection->watches = watches;
+-
++
+ CONNECTION_UNLOCK (connection);
+- /* drop our paranoid refcount */
+- dbus_connection_unref (connection);
+
+ return retval;
+ }
+@@ -4738,6 +4747,12 @@
+ * given remove_function. The timer interval may change whenever the
+ * timeout is added, removed, or toggled.
+ *
++ * @note The thread lock on DBusConnection is held while
++ * timeout functions are invoked, so inside these functions you
++ * may not invoke any methods on DBusConnection or it will deadlock.
++ * See the comments in the code or http://lists.freedesktop.org/archives/dbus/2007-July/thread.html#8144
++ * if you encounter this issue and want to attempt writing a patch.
++ *
+ * @param connection the connection.
+ * @param add_function function to add a timeout.
+ * @param remove_function function to remove a timeout.
+@@ -4755,38 +4770,17 @@
+ DBusFreeFunction free_data_function)
+ {
+ dbus_bool_t retval;
+- DBusTimeoutList *timeouts;
+
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+
+ CONNECTION_LOCK (connection);
+
+-#ifndef DBUS_DISABLE_CHECKS
+- if (connection->timeouts == NULL)
+- {
+- _dbus_warn_check_failed ("Re-entrant call to %s is not allowed\n",
+- _DBUS_FUNCTION_NAME);
+- return FALSE;
+- }
+-#endif
+-
+- /* ref connection for slightly better reentrancy */
+- _dbus_connection_ref_unlocked (connection);
+-
+- timeouts = connection->timeouts;
+- connection->timeouts = NULL;
+- CONNECTION_UNLOCK (connection);
+-
+- retval = _dbus_timeout_list_set_functions (timeouts,
++ retval = _dbus_timeout_list_set_functions (connection->timeouts,
+ add_function, remove_function,
+ toggled_function,
+ data, free_data_function);
+- CONNECTION_LOCK (connection);
+- connection->timeouts = timeouts;
+-
++
+ CONNECTION_UNLOCK (connection);
+- /* drop our paranoid refcount */
+- dbus_connection_unref (connection);
+
+ return retval;
+ }
+@@ -5749,6 +5743,15 @@
+ * the connection is finalized. The slot number
+ * must have been allocated with dbus_connection_allocate_data_slot().
+ *
++ * @note This function does not take the
++ * main thread lock on DBusConnection, which allows it to be
++ * used from inside watch and timeout functions. (See the
++ * note in docs for dbus_connection_set_watch_functions().)
++ * A side effect of this is that you need to know there's
++ * a reference held on the connection while invoking
++ * dbus_connection_set_data(), or the connection could be
++ * finalized during dbus_connection_set_data().
++ *
+ * @param connection the connection
+ * @param slot the slot number
+ * @param data the data to store
+@@ -5768,14 +5771,14 @@
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+ _dbus_return_val_if_fail (slot >= 0, FALSE);
+
+- CONNECTION_LOCK (connection);
++ SLOTS_LOCK (connection);
+
+ retval = _dbus_data_slot_list_set (&slot_allocator,
+ &connection->slot_list,
+ slot, data, free_data_func,
+ &old_free_func, &old_data);
+
+- CONNECTION_UNLOCK (connection);
++ SLOTS_UNLOCK (connection);
+
+ if (retval)
+ {
+@@ -5791,6 +5794,15 @@
+ * Retrieves data previously set with dbus_connection_set_data().
+ * The slot must still be allocated (must not have been freed).
+ *
++ * @note This function does not take the
++ * main thread lock on DBusConnection, which allows it to be
++ * used from inside watch and timeout functions. (See the
++ * note in docs for dbus_connection_set_watch_functions().)
++ * A side effect of this is that you need to know there's
++ * a reference held on the connection while invoking
++ * dbus_connection_get_data(), or the connection could be
++ * finalized during dbus_connection_get_data().
++ *
+ * @param connection the connection
+ * @param slot the slot to get data from
+ * @returns the data, or #NULL if not found
+@@ -5803,13 +5815,13 @@
+
+ _dbus_return_val_if_fail (connection != NULL, NULL);
+
+- CONNECTION_LOCK (connection);
++ SLOTS_LOCK (connection);
+
+ res = _dbus_data_slot_list_get (&slot_allocator,
+ &connection->slot_list,
+ slot);
+
+- CONNECTION_UNLOCK (connection);
++ SLOTS_UNLOCK (connection);
+
+ return res;
+ }