Revision
15587
Author
anthm
Date
2009-11-20 19:00:58 -0600 (Fri, 20 Nov 2009)

Log Message

fix thread saftey issue in expiring media bugs

Modified Paths

Diff

Modified: freeswitch/trunk/src/include/switch_core.h (15586 => 15587)


--- freeswitch/trunk/src/include/switch_core.h	2009-11-21 00:04:27 UTC (rev 15586)
+++ freeswitch/trunk/src/include/switch_core.h	2009-11-21 01:00:58 UTC (rev 15587)
@@ -217,6 +217,7 @@
   \return SWITCH_STATUS_SUCCESS if the operation was a success
 */
 SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove(_In_ switch_core_session_t *session, _Inout_ switch_media_bug_t **bug);
+SWITCH_DECLARE(uint32_t) switch_core_media_bug_prune(switch_core_session_t *session);
 
 /*!
   \brief Remove media bug callback

Modified: freeswitch/trunk/src/include/switch_types.h (15586 => 15587)


--- freeswitch/trunk/src/include/switch_types.h	2009-11-21 00:04:27 UTC (rev 15586)
+++ freeswitch/trunk/src/include/switch_types.h	2009-11-21 01:00:58 UTC (rev 15587)
@@ -1141,7 +1141,8 @@
 	SMBF_READ_PING = (1 << 4),
 	SMBF_STEREO = (1 << 5),
 	SMBF_ANSWER_REQ = (1 << 6),
-	SMBF_THREAD_LOCK = (1 << 7)
+	SMBF_THREAD_LOCK = (1 << 7),
+	SMBF_PRUNE = (1 << 8)
 } switch_media_bug_flag_enum_t;
 typedef uint32_t switch_media_bug_flag_t;
 

Modified: freeswitch/trunk/src/switch_core_io.c (15586 => 15587)


--- freeswitch/trunk/src/switch_core_io.c	2009-11-21 00:04:27 UTC (rev 15586)
+++ freeswitch/trunk/src/switch_core_io.c	2009-11-21 01:00:58 UTC (rev 15587)
@@ -330,13 +330,19 @@
 		}
 
 		if (session->bugs && !switch_channel_test_flag(session->channel, CF_PAUSE_BUGS)) {
-			switch_media_bug_t *bp, *dp, *last = NULL;
+			switch_media_bug_t *bp;
 			switch_bool_t ok = SWITCH_TRUE;
 			switch_thread_rwlock_rdlock(session->bug_rwlock);
+			int prune = 0;
+			
 			for (bp = session->bugs; bp; bp = bp->next) {
 				if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
 					continue;
 				}
+				if (switch_test_flag(bp, SMBF_PRUNE)) {
+					prune++;
+					continue;
+				}
 
 				if (bp->ready && switch_test_flag(bp, SMBF_READ_STREAM)) {
 					switch_mutex_lock(bp->read_mutex);
@@ -358,28 +364,17 @@
 					}
 				}
 				
-				if (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) {
-					ok = SWITCH_FALSE;
+				if ((bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL)) || ok == SWITCH_FALSE) {
+					switch_set_flag(bp, SMBF_PRUNE);
+					prune++;
 				}
-
-				if (ok == SWITCH_FALSE) {
-					bp->ready = 0;
-					if (last) {
-						last->next = bp->next;
-					} else {
-						session->bugs = bp->next;
-					}
-					dp = bp;
-					bp = last;
-					switch_core_media_bug_close(&dp);
-					if (!bp) {
-						break;
-					}
-					continue;
-				}
-				last = bp;
+				
+				
 			}
 			switch_thread_rwlock_unlock(session->bug_rwlock);
+			if (prune) {
+				switch_core_media_bug_prune(session);
+			}
 		}
 
 		if (do_bugs) {
@@ -496,14 +491,20 @@
 			switch_set_flag((*frame), SFF_CNG);
 		}
 		if (session->bugs && !switch_channel_test_flag(session->channel, CF_PAUSE_BUGS)) {
-			switch_media_bug_t *bp, *dp, *last = NULL;
+			switch_media_bug_t *bp;
 			switch_bool_t ok = SWITCH_TRUE;
+			int prune = 0;
 			switch_thread_rwlock_rdlock(session->bug_rwlock);
 			for (bp = session->bugs; bp; bp = bp->next) {
 				if (!switch_channel_test_flag(session->channel, CF_ANSWERED) && switch_core_media_bug_test_flag(bp, SMBF_ANSWER_REQ)) {
 					continue;
 				}
 
+				if (switch_test_flag(bp, SMBF_PRUNE)) {
+					prune++;
+					continue;
+				}
+
 				if (bp->ready && switch_test_flag(bp, SMBF_READ_PING)) {
 					switch_mutex_lock(bp->read_mutex);
 					if (bp->callback) {
@@ -516,23 +517,14 @@
 				}
 
 				if (ok == SWITCH_FALSE) {
-					bp->ready = 0;
-					if (last) {
-						last->next = bp->next;
-					} else {
-						session->bugs = bp->next;
-					}
-					dp = bp;
-					bp = last;
-					switch_core_media_bug_close(&dp);
-					if (!bp) {
-						break;
-					}
-					continue;
+					switch_set_flag(bp, SMBF_PRUNE);
+                    prune++;
 				}
-				last = bp;
 			}
 			switch_thread_rwlock_unlock(session->bug_rwlock);
+			if (prune) {
+				switch_core_media_bug_prune(session);
+			}
 		}
 	}
 
@@ -760,8 +752,9 @@
 	
 
 	if (session->bugs && !switch_channel_test_flag(session->channel, CF_PAUSE_BUGS)) {
-		switch_media_bug_t *bp, *dp, *last = NULL;
-		
+		switch_media_bug_t *bp;
+		int prune = 0;
+
 		switch_thread_rwlock_rdlock(session->bug_rwlock);
 		for (bp = session->bugs; bp; bp = bp->next) {
 			switch_bool_t ok = SWITCH_TRUE;
@@ -773,6 +766,11 @@
 				continue;
 			}
 
+			if (switch_test_flag(bp, SMBF_PRUNE)) {
+				prune++;
+				continue;
+			}
+
 			if (switch_test_flag(bp, SMBF_WRITE_STREAM)) {
 
 				switch_mutex_lock(bp->write_mutex);
@@ -800,23 +798,14 @@
 
 
 			if (ok == SWITCH_FALSE) {
-				bp->ready = 0;
-				if (last) {
-					last->next = bp->next;
-				} else {
-					session->bugs = bp->next;
-				}
-				dp = bp;
-				bp = last;
-				switch_core_media_bug_close(&dp);
-				if (!bp) {
-					break;
-				}
-				continue;
+				switch_set_flag(bp, SMBF_PRUNE);
+				prune++;
 			}
-			last = bp;
 		}
 		switch_thread_rwlock_unlock(session->bug_rwlock);
+		if (prune) {
+			switch_core_media_bug_prune(session);
+		}
 	}
 
 	if (do_bugs) {

Modified: freeswitch/trunk/src/switch_core_media_bug.c (15586 => 15587)


--- freeswitch/trunk/src/switch_core_media_bug.c	2009-11-21 00:04:27 UTC (rev 15586)
+++ freeswitch/trunk/src/switch_core_media_bug.c	2009-11-21 01:00:58 UTC (rev 15587)
@@ -437,6 +437,46 @@
 }
 
 
+SWITCH_DECLARE(uint32_t) switch_core_media_bug_prune(switch_core_session_t *session)
+{
+	switch_media_bug_t *bp = NULL, *last = NULL;
+	switch_status_t status = SWITCH_STATUS_FALSE;
+	int ttl = 0;
+
+
+ top:
+
+	if (session->bugs) {
+		switch_thread_rwlock_wrlock(session->bug_rwlock);
+		for (bp = session->bugs; bp; bp = bp->next) {
+			if (switch_core_media_bug_test_flag(bp, SMBF_PRUNE)) {
+				if (last) {
+					last->next = bp->next;
+				} else {
+					session->bugs = bp->next;
+				}
+				break;
+			}
+
+			last = bp;
+		}
+		switch_thread_rwlock_unlock(session->bug_rwlock);
+		if (bp) {
+			status = switch_core_media_bug_close(&bp);
+			ttl++;
+			goto top;
+		}
+	}
+	
+	if (!session->bugs && switch_core_codec_ready(&session->bug_codec)) {
+		switch_core_codec_destroy(&session->bug_codec);
+		memset(&session->bug_codec, 0, sizeof(session->bug_codec));
+	}
+
+	return ttl;
+}
+
+
 SWITCH_DECLARE(switch_status_t) switch_core_media_bug_remove_callback(switch_core_session_t *session, switch_media_bug_callback_t callback)
 {
 	switch_media_bug_t *cur = NULL, *bp = NULL, *last = NULL;