[asterisk-commits] rizzo: branch rizzo/astobj2 r47253 - /team/rizzo/astobj2/channels/chan_sip.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue Nov 7 06:48:44 MST 2006


Author: rizzo
Date: Tue Nov  7 07:48:44 2006
New Revision: 47253

URL: http://svn.digium.com/view/asterisk?rev=47253&view=rev
Log:
put the deadlock avoidance code to lock a pvt and its owner channel
into a single function.
There is one suspicious usage, when called by the scheduler,
where we don't have the dialoglist locked. I am unclear whether
this is safe to do (because the object cannot be destroyed
by anyone else) or not.


Modified:
    team/rizzo/astobj2/channels/chan_sip.c

Modified: team/rizzo/astobj2/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/channels/chan_sip.c?rev=47253&r1=47252&r2=47253&view=diff
==============================================================================
--- team/rizzo/astobj2/channels/chan_sip.c (original)
+++ team/rizzo/astobj2/channels/chan_sip.c Tue Nov  7 07:48:44 2006
@@ -867,7 +867,12 @@
 	enum referstatus status;			/*!< REFER status */
 };
 
-/*! \brief sip_pvt: PVT structures are used for each SIP dialog, ie. a call, a registration, a subscribe  */
+/*!
+ * PVT structures are used for each SIP dialog, ie. a call, a registration, a subscribe.
+ * Created and initialized by sip_alloc(), the descriptor goes into the list of
+ * descriptors (dialoglist), and there it stays i suppose forever
+ */
+
 struct sip_pvt {
 	ast_mutex_t pvt_lock;			/*!< Dialog private lock */
 	int method;				/*!< SIP method that opened this dialog */
@@ -1875,6 +1880,27 @@
 	return;
 }
 
+/*!
+ * Enter with a pvt locked, try to grab a lock on the owner channel too,
+ * with deadlock avoidance. Try as many times as specified (0 means forever),
+ * return 0 on success, -1 on failure.
+ * \note that we may temporarily drop the lock on pvt, so this is only
+ * safe to call if the pvt cannot disappear (i.e. dialoglist is locked,
+ * in the currently implementation).
+ */
+static int lock_pvt_and_owner(struct sip_pvt *pvt, int retries)
+{
+	while(pvt->owner && ast_channel_trylock(pvt->owner)) {
+		if (retries && retries-- <= 1)
+			return -1;	/* failed, too many loops */
+		sip_pvt_unlock(pvt);
+		usleep(1);
+		sip_pvt_lock(pvt);
+	}
+	ast_verbose("lock_pvt_and_owner %p %p success", pvt, pvt->owner);
+	return 0;
+}
+
 /*! \brief Retransmit SIP message if no answer (Called from scheduler) */
 static int retrans_pkt(void *data)
 {
@@ -1936,11 +1962,7 @@
 	pkt->retransid = -1;
 
 	if (ast_test_flag(pkt, FLAG_FATAL)) {
-		while(pkt->owner->owner && ast_channel_trylock(pkt->owner->owner)) {
-			sip_pvt_unlock(pkt->owner);	/* SIP_PVT, not channel */
-			usleep(1);
-			sip_pvt_lock(pkt->owner);
-		}
+		lock_pvt_and_owner(pkt->owner, 0 /* try forever */); /* XXX unsafe ? */
 		if (pkt->owner->owner) {
 			ast_set_flag(&pkt->owner->flags[0], SIP_ALREADYGONE);
 			ast_log(LOG_WARNING, "Hanging up call %s - no reply to our critical packet.\n", pkt->owner->callid);
@@ -8588,12 +8610,7 @@
 					ast_test_flag(&sip_pvt_ptr->flags[0], SIP_OUTGOING) ? "OUTGOING": "INCOMING",
 					sip_pvt_ptr->theirtag, sip_pvt_ptr->tag);
 
-			/* deadlock avoidance... */
-			while (sip_pvt_ptr->owner && ast_channel_trylock(sip_pvt_ptr->owner)) {
-				sip_pvt_unlock(sip_pvt_ptr);
-				usleep(1);
-				sip_pvt_lock(sip_pvt_ptr);
-			}
+			lock_pvt_and_owner(sip_pvt_ptr, 0 /* try forever */); /* safe, dialoglist is locked */
 			break;
 		}
 	}
@@ -14824,7 +14841,10 @@
 }
 
 
-/*! \brief helper function for the monitoring thread */
+/*!
+ * helper function for the monitoring thread.
+ * Called only in one place with dialoglist locked.
+ */
 static void check_rtp_timeout(struct sip_pvt *sip, time_t t)
 {
 	if (sip->rtp && sip->owner &&
@@ -14848,11 +14868,7 @@
 			     (t > sip->lastrtprx + sip->rtpholdtimeout))) {
 				/* Needs a hangup */
 				if (sip->rtptimeout) {
-					while (sip->owner && ast_channel_trylock(sip->owner)) {
-						sip_pvt_unlock(sip);
-						usleep(1);
-						sip_pvt_lock(sip);
-					}
+					lock_pvt_and_owner(sip, 0 /* forever */); /* safe, dialoglist is locked */
 					if (sip->owner) {
 						if (!(ast_rtp_get_bridged(sip->rtp))) {
 							ast_log(LOG_NOTICE,



More information about the asterisk-commits mailing list