[svn-commits] rmudgett: branch 1.6.2 r307624 - in /branches/1.6.2: ./ channels/chan_dahdi.c

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Feb 10 19:02:26 CST 2011


Author: rmudgett
Date: Thu Feb 10 19:02:22 2011
New Revision: 307624

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=307624
Log:
Merged revisions 307623 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r307623 | rmudgett | 2011-02-10 18:29:17 -0600 (Thu, 10 Feb 2011) | 13 lines
  
  Reentrancy problem if outgoing call gets different B channel than requested.
  
  The chan_dahdi pri_fixup_principle() routine needs to protect the Asterisk
  channel with the channel lock when it changes the technology private
  pointer to a new private structure.
  
  * Added lock protection while pri_fixup_principle() moves a call from one
  private structure to another.
  
  * Made some pri_fixup_principle() messages more meaningful.
  
  Partial backport from v1.8 -r300714.
........

Modified:
    branches/1.6.2/   (props changed)
    branches/1.6.2/channels/chan_dahdi.c

Propchange: branches/1.6.2/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Modified: branches/1.6.2/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.6.2/channels/chan_dahdi.c?view=diff&rev=307624&r1=307623&r2=307624
==============================================================================
--- branches/1.6.2/channels/chan_dahdi.c (original)
+++ branches/1.6.2/channels/chan_dahdi.c Thu Feb 10 19:02:22 2011
@@ -12502,6 +12502,51 @@
 #endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Obtain the DAHDI owner channel lock if the owner exists.
+ * \since 1.8
+ *
+ * \param pri DAHDI PRI control structure.
+ * \param chanpos Channel position in the span.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the pri->pvts[chanpos]->lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_lock_owner(struct dahdi_pri *pri, int chanpos)
+{
+	for (;;) {
+		if (!pri->pvts[chanpos]->owner) {
+			/* There is no owner lock to get. */
+			break;
+		}
+		if (!ast_channel_trylock(pri->pvts[chanpos]->owner)) {
+			/* We got the lock */
+			break;
+		}
+		/* We must unlock the PRI to avoid the possibility of a deadlock */
+		ast_mutex_unlock(&pri->lock);
+		DEADLOCK_AVOIDANCE(&pri->pvts[chanpos]->lock);
+		ast_mutex_lock(&pri->lock);
+	}
+}
+#endif	/* defined(HAVE_PRI) */
+
+#if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Find the private structure for the libpri call.
+ *
+ * \param pri Span controller structure.
+ * \param channel LibPRI encoded channel ID.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval array-index into private pointer array on success.
+ * \retval -1 on error.
+ */
 static int pri_find_principle(struct dahdi_pri *pri, int channel)
 {
 	int x;
@@ -12532,6 +12577,19 @@
 #endif	/* defined(HAVE_PRI) */
 
 #if defined(HAVE_PRI)
+/*!
+ * \internal
+ * \brief Fixup the private structure associated with the libpri call.
+ *
+ * \param pri Span controller structure.
+ * \param principle Array-index into private array to move call to if not already there.
+ * \param c LibPRI opaque call pointer to find if need to move call.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval principle on success.
+ * \retval -1 on error.
+ */
 static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c)
 {
 	int x;
@@ -12555,13 +12613,27 @@
 			if (principle != x) {
 				struct dahdi_pvt *new = pri->pvts[principle], *old = pri->pvts[x];
 
-				ast_verb(3, "Moving call from channel %d to channel %d\n",
-					 old->channel, new->channel);
+				/* Get locks to safely move to the new private structure. */
+				ast_mutex_lock(&old->lock);
+				sig_pri_lock_owner(pri, x);
+				ast_mutex_lock(&new->lock);
+
+				ast_verb(3, "Moving call (%s) from channel %d to %d.\n",
+					old->owner ? old->owner->name : "",
+					old->channel, new->channel);
 				if (new->owner) {
-					ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
-						old->channel, new->channel, new->channel);
+					ast_log(LOG_WARNING,
+						"Can't move call (%s) from channel %d to %d.  It is already in use.\n",
+						old->owner ? old->owner->name : "",
+						old->channel, new->channel);
+					ast_mutex_unlock(&new->lock);
+					if (old->owner) {
+						ast_channel_unlock(old->owner);
+					}
+					ast_mutex_unlock(&old->lock);
 					return -1;
 				}
+
 				/* Fix it all up now */
 				new->owner = old->owner;
 				old->owner = NULL;
@@ -12599,6 +12671,12 @@
 				/* More stuff to transfer to the new channel. */
 				new->call_level = old->call_level;
 				old->call_level = DAHDI_CALL_LEVEL_IDLE;
+ 
+				ast_mutex_unlock(&old->lock);
+				if (new->owner) {
+					ast_channel_unlock(new->owner);
+				}
+				ast_mutex_unlock(&new->lock);
 			}
 			return principle;
 		}




More information about the svn-commits mailing list