[asterisk-commits] russell: branch russell/chan_refcount r82328 - in /team/russell/chan_refcount...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Sep 13 11:30:50 CDT 2007


Author: russell
Date: Thu Sep 13 11:30:50 2007
New Revision: 82328

URL: http://svn.digium.com/view/asterisk?view=rev&rev=82328
Log:
* constify some args to manager functions
* add two new functions ao2_lock_both() and ao2_unlock_both()
  - These functions are intended to be used when two objects must be locked
    at the same time, and thus deadlocks must be avoided.  However, instead of
	using an expensive trylock/unlock/lock/sleep/trylock loop, it just locks
	the object with a lower pointer address first to ensure that the locking
	is always done in the same order.

Modified:
    team/russell/chan_refcount/include/asterisk/astobj2.h
    team/russell/chan_refcount/include/asterisk/channel.h
    team/russell/chan_refcount/include/asterisk/manager.h
    team/russell/chan_refcount/main/astobj2.c
    team/russell/chan_refcount/main/manager.c

Modified: team/russell/chan_refcount/include/asterisk/astobj2.h
URL: http://svn.digium.com/view/asterisk/team/russell/chan_refcount/include/asterisk/astobj2.h?view=diff&rev=82328&r1=82327&r2=82328
==============================================================================
--- team/russell/chan_refcount/include/asterisk/astobj2.h (original)
+++ team/russell/chan_refcount/include/asterisk/astobj2.h Thu Sep 13 11:30:50 2007
@@ -193,6 +193,21 @@
 int ao2_lock(void *a);
 
 /*!
+ * \brief Lock two objects.
+ *
+ * \param obj1 a pointer to the first object to lock
+ * \param obj2 a pointer to the second object to lock
+ *
+ * This function should be used in all cases where two objects need to be
+ * locked at the same time.  It avoids deadlocks by ensuring the same locking
+ * order is always used, by locking the object with a lower pointer address
+ * first.
+ *
+ * \return 0 on success, other values on error
+ */
+int ao2_lock_both(void *obj1, void *obj2);
+
+/*!
  * \brief Try to lock an object.
  * 
  * \param a A pointer to the object we want lock.
@@ -208,6 +223,20 @@
  * \return 0 on success, other values on error.
  */
 int ao2_unlock(void *a);
+
+/*!
+ * \brief Unlock two objects.
+ *
+ * \param obj1 a pointer to the first object to lock
+ * \param obj2 a pointer to the second object to lock
+ *
+ * This function can be used with ao2_lock_both, but isn't necessarily
+ * required, as the order in which objects are unlocked is not as important
+ * as the order in which they are locked.
+ *
+ * \return 0 on success, other values on error
+ */
+int ao2_unlock_both(void *obj1, void *obj2);
 
 /*!
  *

Modified: team/russell/chan_refcount/include/asterisk/channel.h
URL: http://svn.digium.com/view/asterisk/team/russell/chan_refcount/include/asterisk/channel.h?view=diff&rev=82328&r1=82327&r2=82328
==============================================================================
--- team/russell/chan_refcount/include/asterisk/channel.h (original)
+++ team/russell/chan_refcount/include/asterisk/channel.h Thu Sep 13 11:30:50 2007
@@ -1487,6 +1487,9 @@
 #define ast_channel_unlock(c) ao2_unlock(c)
 #define ast_channel_trylock(c) ao2_trylock(c)
 
+#define ast_channel_lock_both(c1, c2) ao2_lock_both(c1, c2)
+#define ast_channel_unlock_both(c1, c2) ao2_unlock_both(c1, c2)
+
 static force_inline struct ast_channel *ast_channel_ref(struct ast_channel *chan)
 {
 	ao2_ref(chan, +1);

Modified: team/russell/chan_refcount/include/asterisk/manager.h
URL: http://svn.digium.com/view/asterisk/team/russell/chan_refcount/include/asterisk/manager.h?view=diff&rev=82328&r1=82327&r2=82328
==============================================================================
--- team/russell/chan_refcount/include/asterisk/manager.h (original)
+++ team/russell/chan_refcount/include/asterisk/manager.h Thu Sep 13 11:30:50 2007
@@ -180,7 +180,7 @@
 struct ast_variable *astman_get_variables(const struct message *m);
 
 /*! Send error in manager transaction */
-void astman_send_error(struct mansession *s, const struct message *m, char *error);
+void astman_send_error(struct mansession *s, const struct message *m, const char *error);
 void astman_send_response(struct mansession *s, const struct message *m, char *resp, char *msg);
 void astman_send_ack(struct mansession *s, const struct message *m, char *msg);
 void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag);

Modified: team/russell/chan_refcount/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/russell/chan_refcount/main/astobj2.c?view=diff&rev=82328&r1=82327&r2=82328
==============================================================================
--- team/russell/chan_refcount/main/astobj2.c (original)
+++ team/russell/chan_refcount/main/astobj2.c Thu Sep 13 11:30:50 2007
@@ -25,6 +25,13 @@
 #include "asterisk/utils.h"
 #include "asterisk/cli.h"
 
+#ifndef MIN
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
 /*!
  * astobj2 objects are always preceded by this data structure,
  * which contains a lock, a reference counter,
@@ -131,6 +138,29 @@
 	return ast_mutex_lock(&p->priv_data.lock);
 }
 
+int ao2_lock_both(void *user_data1, void *user_data2)
+{
+	struct astobj2 *p1, *p2;
+	int res;
+
+	p1 = INTERNAL_OBJ(MIN(user_data1, user_data2));
+	p2 = INTERNAL_OBJ(MAX(user_data1, user_data2));
+
+	res = ast_mutex_lock(&p1->priv_data.lock);
+	if (!res) {
+#ifdef AO2_DEBUG
+		ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+#endif
+		res = ast_mutex_lock(&p2->priv_data.lock);
+#ifdef AO2_DEBUG
+		if (!res)
+			ast_atomic_fetchadd_int(&ao2.total_locked, 1);
+#endif
+	}
+
+	return res;
+}
+
 int ao2_trylock(void *user_data)
 {
 	struct astobj2 *p = INTERNAL_OBJ(user_data);
@@ -157,6 +187,29 @@
 	ast_atomic_fetchadd_int(&ao2.total_locked, -1);
 
 	return ast_mutex_unlock(&p->priv_data.lock);
+}
+
+int ao2_unlock_both(void *user_data1, void *user_data2)
+{
+	struct astobj2 *p1, *p2;
+	int res;
+
+	p1 = INTERNAL_OBJ(user_data1);
+	p2 = INTERNAL_OBJ(user_data2);
+
+	res = ast_mutex_unlock(&p1->priv_data.lock);
+	if (!res) {
+#ifdef AO2_DEBUG
+		ast_atomic_fetchadd_int(&ao2.total_locked, -1);
+#endif
+		res = ast_mutex_unlock(&p2->priv_data.lock);
+#ifdef AO2_DEBUG
+		if (!res)
+			ast_atomic_fetchadd_int(&ao2.total_locked, -1);
+#endif
+	}
+
+	return res;
 }
 
 /*

Modified: team/russell/chan_refcount/main/manager.c
URL: http://svn.digium.com/view/asterisk/team/russell/chan_refcount/main/manager.c?view=diff&rev=82328&r1=82327&r2=82328
==============================================================================
--- team/russell/chan_refcount/main/manager.c (original)
+++ team/russell/chan_refcount/main/manager.c Thu Sep 13 11:30:50 2007
@@ -886,7 +886,7 @@
  * XXX MSG_MOREDATA should go to a header file.
  */
 #define MSG_MOREDATA	((char *)astman_send_response)
-static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, char *msg, char *listflag)
+static void astman_send_response_full(struct mansession *s, const struct message *m, char *resp, const char *msg, char *listflag)
 {
 	const char *id = astman_get_header(m,"ActionID");
 
@@ -908,7 +908,7 @@
 	astman_send_response_full(s, m, resp, msg, NULL);
 }
 
-void astman_send_error(struct mansession *s, const struct message *m, char *error)
+void astman_send_error(struct mansession *s, const struct message *m, const char *error)
 {
 	astman_send_response_full(s, m, "Error", error, NULL);
 }




More information about the asterisk-commits mailing list