* [gentoo-commits] gentoo-x86 commit in sys-apps/dbus/files: dbus-1.2.24-thread-safety.patch
@ 2010-08-05 19:17 Maciej Mrozowski (reavertm)
0 siblings, 0 replies; 2+ messages in thread
From: Maciej Mrozowski (reavertm) @ 2010-08-05 19:17 UTC (permalink / raw
To: gentoo-commits
reavertm 10/08/05 19:17:21
Added: dbus-1.2.24-thread-safety.patch
Log:
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)
Revision Changes Path
1.1 sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch
file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch?rev=1.1&view=markup
plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/sys-apps/dbus/files/dbus-1.2.24-thread-safety.patch?rev=1.1&content-type=text/plain
Index: dbus-1.2.24-thread-safety.patch
===================================================================
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;
}
^ permalink raw reply [flat|nested] 2+ messages in thread
* [gentoo-commits] gentoo-x86 commit in sys-apps/dbus/files: dbus-1.2.24-thread-safety.patch
@ 2010-12-19 1:18 Samuli Suominen (ssuominen)
0 siblings, 0 replies; 2+ messages in thread
From: Samuli Suominen (ssuominen) @ 2010-12-19 1:18 UTC (permalink / raw
To: gentoo-commits
ssuominen 10/12/19 01:18:07
Removed: dbus-1.2.24-thread-safety.patch
Log:
punt old
(Portage version: 2.2.0_alpha9/cvs/Linux x86_64)
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2010-12-19 1:18 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-08-05 19:17 [gentoo-commits] gentoo-x86 commit in sys-apps/dbus/files: dbus-1.2.24-thread-safety.patch Maciej Mrozowski (reavertm)
-- strict thread matches above, loose matches on Subject: below --
2010-12-19 1:18 Samuli Suominen (ssuominen)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox