|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
# HG changeset patch
|
|
David Woodhouse |
b9afc8a |
# User Jakub Adam <jakub.adam@ktknet.cz>
|
|
David Woodhouse |
b9afc8a |
# Date 1440146141 -7200
|
|
David Woodhouse |
b9afc8a |
# Node ID 79fe6b95f1057b65505559ffdc66136e2145cf25
|
|
David Woodhouse |
b9afc8a |
# Parent c00a1fd0d27b52db5abddbafaa8457f90a3d3e69
|
|
David Woodhouse |
b9afc8a |
Fix a race condition in appsrc read/write callbacks
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
We can't use writable_timer_id as a token because the timeout is added
|
|
David Woodhouse |
b9afc8a |
into libpurple's main event loop, which runs in a different thread than
|
|
David Woodhouse |
b9afc8a |
from where call_appsrc_writable_locked() was called. Consequently, the
|
|
David Woodhouse |
b9afc8a |
callback may run even before purple_timeout_add() returns the timer ID
|
|
David Woodhouse |
b9afc8a |
to us.
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
The same applies to readable_timer_id in call_appsink_readable_locked().
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
diff --git a/libpurple/mediamanager.c b/libpurple/mediamanager.c
|
|
David Woodhouse |
b9afc8a |
--- a/libpurple/mediamanager.c
|
|
David Woodhouse |
b9afc8a |
+++ b/libpurple/mediamanager.c
|
|
David Woodhouse |
b9afc8a |
@@ -105,6 +105,7 @@
|
|
David Woodhouse |
b9afc8a |
/* Application data streams */
|
|
David Woodhouse |
b9afc8a |
GList *appdata_info; /* holds PurpleMediaAppDataInfo */
|
|
David Woodhouse |
b9afc8a |
GMutex appdata_mutex;
|
|
David Woodhouse |
b9afc8a |
+ guint appdata_cb_token; /* last used read/write callback token */
|
|
David Woodhouse |
b9afc8a |
#endif
|
|
David Woodhouse |
b9afc8a |
};
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
@@ -124,6 +125,8 @@
|
|
David Woodhouse |
b9afc8a |
guint sample_offset;
|
|
David Woodhouse |
b9afc8a |
gboolean writable;
|
|
David Woodhouse |
b9afc8a |
gboolean connected;
|
|
David Woodhouse |
b9afc8a |
+ guint writable_cb_token;
|
|
David Woodhouse |
b9afc8a |
+ guint readable_cb_token;
|
|
David Woodhouse |
b9afc8a |
guint writable_timer_id;
|
|
David Woodhouse |
b9afc8a |
guint readable_timer_id;
|
|
David Woodhouse |
b9afc8a |
GCond readable_cond;
|
|
David Woodhouse |
b9afc8a |
@@ -562,6 +565,11 @@
|
|
David Woodhouse |
b9afc8a |
g_free (info->session_id);
|
|
David Woodhouse |
b9afc8a |
g_free (info->participant);
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
+ /* This lets the potential read or write callbacks waiting for appdata_mutex
|
|
David Woodhouse |
b9afc8a |
+ * know the info structure has been destroyed. */
|
|
David Woodhouse |
b9afc8a |
+ info->readable_cb_token = 0;
|
|
David Woodhouse |
b9afc8a |
+ info->writable_cb_token = 0;
|
|
David Woodhouse |
b9afc8a |
+
|
|
David Woodhouse |
b9afc8a |
if (info->readable_timer_id) {
|
|
David Woodhouse |
b9afc8a |
purple_timeout_remove (info->readable_timer_id);
|
|
David Woodhouse |
b9afc8a |
info->readable_timer_id = 0;
|
|
David Woodhouse |
b9afc8a |
@@ -750,19 +758,19 @@
|
|
David Woodhouse |
b9afc8a |
gchar *participant;
|
|
David Woodhouse |
b9afc8a |
gboolean writable;
|
|
David Woodhouse |
b9afc8a |
gpointer cb_data;
|
|
David Woodhouse |
b9afc8a |
- guint *timer_id_ptr = &info->writable_timer_id;
|
|
David Woodhouse |
b9afc8a |
- guint timer_id = *timer_id_ptr;
|
|
David Woodhouse |
b9afc8a |
+ guint *cb_token_ptr = &info->writable_cb_token;
|
|
David Woodhouse |
b9afc8a |
+ guint cb_token = *cb_token_ptr;
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
g_mutex_lock (&manager->priv->appdata_mutex);
|
|
David Woodhouse |
b9afc8a |
- if (timer_id == 0 || timer_id != *timer_id_ptr) {
|
|
David Woodhouse |
b9afc8a |
+ if (cb_token == 0 || cb_token != *cb_token_ptr) {
|
|
David Woodhouse |
b9afc8a |
/* In case info was freed while we were waiting for the mutex to unlock
|
|
David Woodhouse |
b9afc8a |
- * we still have a pointer to the timer_id which should still be
|
|
David Woodhouse |
b9afc8a |
+ * we still have a pointer to the cb_token which should still be
|
|
David Woodhouse |
b9afc8a |
* accessible since it's in the Glib slice allocator. It gets set to 0
|
|
David Woodhouse |
b9afc8a |
* just after the timeout is canceled which happens also before the
|
|
David Woodhouse |
b9afc8a |
* AppDataInfo is freed, so even if that memory slice gets reused, the
|
|
David Woodhouse |
b9afc8a |
- * timer_id would be different from its previous value (unless
|
|
David Woodhouse |
b9afc8a |
- * extremely unlucky). So checking if the value for the timer_id changed
|
|
David Woodhouse |
b9afc8a |
+ * cb_token would be different from its previous value (unless
|
|
David Woodhouse |
b9afc8a |
+ * extremely unlucky). So checking if the value for the cb_token changed
|
|
David Woodhouse |
b9afc8a |
* should be enough to prevent any kind of race condition in which the
|
|
David Woodhouse |
b9afc8a |
* media/AppDataInfo gets destroyed in one thread while the timeout was
|
|
David Woodhouse |
b9afc8a |
* triggered and is waiting on the mutex to get unlocked in this thread
|
|
David Woodhouse |
b9afc8a |
@@ -777,7 +785,7 @@
|
|
David Woodhouse |
b9afc8a |
writable = info->writable && info->connected;
|
|
David Woodhouse |
b9afc8a |
cb_data = info->user_data;
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
- info->writable_timer_id = 0;
|
|
David Woodhouse |
b9afc8a |
+ info->writable_cb_token = 0;
|
|
David Woodhouse |
b9afc8a |
g_mutex_unlock (&manager->priv->appdata_mutex);
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
@@ -805,10 +813,18 @@
|
|
David Woodhouse |
b9afc8a |
static void
|
|
David Woodhouse |
b9afc8a |
call_appsrc_writable_locked (PurpleMediaAppDataInfo *info)
|
|
David Woodhouse |
b9afc8a |
{
|
|
David Woodhouse |
b9afc8a |
+ PurpleMediaManager *manager = purple_media_manager_get ();
|
|
David Woodhouse |
b9afc8a |
+
|
|
David Woodhouse |
b9afc8a |
/* We already have a writable callback scheduled, don't create another one */
|
|
David Woodhouse |
b9afc8a |
- if (info->writable_timer_id || info->callbacks.writable == NULL)
|
|
David Woodhouse |
b9afc8a |
+ if (info->writable_cb_token || info->callbacks.writable == NULL)
|
|
David Woodhouse |
b9afc8a |
return;
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
+ /* We can't use writable_timer_id as a token, because the timeout is added
|
|
David Woodhouse |
b9afc8a |
+ * into libpurple's main event loop, which runs in a different thread than
|
|
David Woodhouse |
b9afc8a |
+ * from where call_appsrc_writable_locked() was called. Consequently, the
|
|
David Woodhouse |
b9afc8a |
+ * callback may run even before purple_timeout_add() returns the timer ID
|
|
David Woodhouse |
b9afc8a |
+ * to us. */
|
|
David Woodhouse |
b9afc8a |
+ info->writable_cb_token = ++manager->priv->appdata_cb_token;
|
|
David Woodhouse |
b9afc8a |
info->writable_timer_id = purple_timeout_add (0, appsrc_writable, info);
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
@@ -930,11 +946,11 @@
|
|
David Woodhouse |
b9afc8a |
gchar *session_id;
|
|
David Woodhouse |
b9afc8a |
gchar *participant;
|
|
David Woodhouse |
b9afc8a |
gpointer cb_data;
|
|
David Woodhouse |
b9afc8a |
- guint *timer_id_ptr = &info->readable_timer_id;
|
|
David Woodhouse |
b9afc8a |
- guint timer_id = *timer_id_ptr;
|
|
David Woodhouse |
b9afc8a |
+ guint *cb_token_ptr = &info->readable_cb_token;
|
|
David Woodhouse |
b9afc8a |
+ guint cb_token = *cb_token_ptr;
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
g_mutex_lock (&manager->priv->appdata_mutex);
|
|
David Woodhouse |
b9afc8a |
- if (timer_id == 0 || timer_id != *timer_id_ptr) {
|
|
David Woodhouse |
b9afc8a |
+ if (cb_token == 0 || cb_token != *cb_token_ptr) {
|
|
David Woodhouse |
b9afc8a |
/* Avoided a race condition (see writable callback) */
|
|
David Woodhouse |
b9afc8a |
g_mutex_unlock (&manager->priv->appdata_mutex);
|
|
David Woodhouse |
b9afc8a |
return FALSE;
|
|
David Woodhouse |
b9afc8a |
@@ -956,13 +972,13 @@
|
|
David Woodhouse |
b9afc8a |
g_object_unref (media);
|
|
David Woodhouse |
b9afc8a |
g_free (session_id);
|
|
David Woodhouse |
b9afc8a |
g_free (participant);
|
|
David Woodhouse |
b9afc8a |
- if (timer_id == 0 || timer_id != *timer_id_ptr) {
|
|
David Woodhouse |
b9afc8a |
+ if (cb_token == 0 || cb_token != *cb_token_ptr) {
|
|
David Woodhouse |
b9afc8a |
/* We got cancelled */
|
|
David Woodhouse |
b9afc8a |
g_mutex_unlock (&manager->priv->appdata_mutex);
|
|
David Woodhouse |
b9afc8a |
return FALSE;
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
- info->readable_timer_id = 0;
|
|
David Woodhouse |
b9afc8a |
+ info->readable_cb_token = 0;
|
|
David Woodhouse |
b9afc8a |
g_mutex_unlock (&manager->priv->appdata_mutex);
|
|
David Woodhouse |
b9afc8a |
return FALSE;
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
@@ -970,13 +986,16 @@
|
|
David Woodhouse |
b9afc8a |
static void
|
|
David Woodhouse |
b9afc8a |
call_appsink_readable_locked (PurpleMediaAppDataInfo *info)
|
|
David Woodhouse |
b9afc8a |
{
|
|
David Woodhouse |
b9afc8a |
+ PurpleMediaManager *manager = purple_media_manager_get ();
|
|
David Woodhouse |
b9afc8a |
+
|
|
David Woodhouse |
b9afc8a |
/* We must signal that a new sample has arrived to release blocking reads */
|
|
David Woodhouse |
b9afc8a |
g_cond_broadcast (&info->readable_cond);
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
/* We already have a writable callback scheduled, don't create another one */
|
|
David Woodhouse |
b9afc8a |
- if (info->readable_timer_id || info->callbacks.readable == NULL)
|
|
David Woodhouse |
b9afc8a |
+ if (info->readable_cb_token || info->callbacks.readable == NULL)
|
|
David Woodhouse |
b9afc8a |
return;
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
+ info->readable_cb_token = ++manager->priv->appdata_cb_token;
|
|
David Woodhouse |
b9afc8a |
info->readable_timer_id = purple_timeout_add (0, appsink_readable, info);
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
@@ -1663,14 +1682,14 @@
|
|
David Woodhouse |
b9afc8a |
if (info->notify)
|
|
David Woodhouse |
b9afc8a |
info->notify (info->user_data);
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
- if (info->readable_timer_id) {
|
|
David Woodhouse |
b9afc8a |
+ if (info->readable_cb_token) {
|
|
David Woodhouse |
b9afc8a |
purple_timeout_remove (info->readable_timer_id);
|
|
David Woodhouse |
b9afc8a |
- info->readable_timer_id = 0;
|
|
David Woodhouse |
b9afc8a |
+ info->readable_cb_token = 0;
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
- if (info->writable_timer_id) {
|
|
David Woodhouse |
b9afc8a |
+ if (info->writable_cb_token) {
|
|
David Woodhouse |
b9afc8a |
purple_timeout_remove (info->writable_timer_id);
|
|
David Woodhouse |
b9afc8a |
- info->writable_timer_id = 0;
|
|
David Woodhouse |
b9afc8a |
+ info->writable_cb_token = 0;
|
|
David Woodhouse |
b9afc8a |
}
|
|
David Woodhouse |
b9afc8a |
|
|
David Woodhouse |
b9afc8a |
if (callbacks) {
|
|
David Woodhouse |
b9afc8a |
|