From 0e09ca68a5493b51aa0ecc4fac64fffab2fb33bf Mon Sep 17 00:00:00 2001
From: Mark Spencer <markster@digium.com>
Date: Tue, 22 Apr 2003 18:47:49 +0000
Subject: [PATCH] Fix race in DISCONNECT vs RELEASE

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@881 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 channels/chan_zap.c | 44 ++++++++++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 16 deletions(-)

diff --git a/channels/chan_zap.c b/channels/chan_zap.c
index d4192d8c68..770f173cef 100755
--- a/channels/chan_zap.c
+++ b/channels/chan_zap.c
@@ -295,18 +295,6 @@ static int pritype = PRI_CPE;
 #define DEFAULT_PRI_DEBUG 0
 #endif
 
-static inline int pri_grab(struct zt_pri *pri)
-{
-	int res;
-	/* Grab the lock first */
-    res = ast_pthread_mutex_lock(&pri->lock);
-	if (res)
-		return res;
-	/* Then break the select */
-	pthread_kill(pri->master, SIGURG);
-	return 0;
-}
-
 static inline void pri_rel(struct zt_pri *pri)
 {
 	ast_pthread_mutex_unlock(&pri->lock);
@@ -459,6 +447,26 @@ static struct zt_pvt {
 #endif	
 } *iflist = NULL;
 
+#ifdef ZAPATA_PRI
+static inline int pri_grab(struct zt_pvt *pvt, struct zt_pri *pri)
+{
+	int res;
+	/* Grab the lock first */
+	do {
+	    res = pthread_mutex_trylock(&pri->lock);
+		if (res) {
+			ast_pthread_mutex_unlock(&pvt->lock);
+			/* Release the lock and try again */
+			usleep(1);
+			ast_pthread_mutex_lock(&pvt->lock);
+		}
+	} while(res);
+	/* Then break the select */
+	pthread_kill(pri->master, SIGURG);
+	return 0;
+}
+#endif
+
 static struct zt_ring_cadence cadences[] = {
 	{ { 125, 125, 2000, 4000 } },			/* Quick chirp followed by normal ring */
 	{ { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /* British style ring */
@@ -1578,7 +1586,7 @@ static int zt_hangup(struct ast_channel *ast)
 #ifdef ZAPATA_PRI
 		if (p->sig == SIG_PRI) {
 			if (p->call) {
-				if (!pri_grab(p->pri)) {
+				if (!pri_grab(p, p->pri)) {
 					res = pri_disconnect(p->pri->pri, p->call, PRI_CAUSE_NORMAL_CLEARING);
 					if (p->alreadyhungup) {
 						p->call = NULL;
@@ -1688,12 +1696,15 @@ static int zt_answer(struct ast_channel *ast)
 	int index;
 	int oldstate = ast->_state;
 	ast_setstate(ast, AST_STATE_UP);
+	ast_pthread_mutex_lock(&p->lock);
 	index = zt_get_index(ast, p, 0);
 	if (index < 0)
 		index = SUB_REAL;
 	/* nothing to do if a radio channel */
-	if (p->radio)
+	if (p->radio) {
+		ast_pthread_mutex_unlock(&p->lock);
 		return 0;
+	}
 	switch(p->sig) {
 	case SIG_FXSLS:
 	case SIG_FXSGS:
@@ -1730,7 +1741,7 @@ static int zt_answer(struct ast_channel *ast)
 #ifdef ZAPATA_PRI
 	case SIG_PRI:
 		/* Send a pri acknowledge */
-		if (!pri_grab(p->pri)) {
+		if (!pri_grab(p, p->pri)) {
 			res = pri_answer(p->pri->pri, p->call, 0, 1);
 			pri_rel(p->pri);
 		} else {
@@ -1750,8 +1761,9 @@ static int zt_answer(struct ast_channel *ast)
 		return 0;
 	default:
 		ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
-		return -1;
+		res = -1;
 	}
+	ast_pthread_mutex_unlock(&p->lock);
 	return res;
 }
 
-- 
GitLab