[asterisk-commits] kpfleming: branch sruffell/asterisk-1.4-transcoder r167368 - /team/sruffell/a...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jan 6 17:54:34 CST 2009


Author: kpfleming
Date: Tue Jan  6 17:54:32 2009
New Revision: 167368

URL: http://svn.digium.com/view/asterisk?view=rev&rev=167368
Log:
when a SIP request or response arrives for a channel that is locked, and we cannot obtain the lock in a reasonable period of time, then attempt to queue the request for later processing, instead of dropping it. queued requests will be processed when another request/response arrives and the channel lock is obtained, or if a timer expires and the lock can be obtained at that time. if neither of those occurs, the requests will stay in the queue until they can be processed.

as a side effect, reduce the number of lock attempts made to get the channel lock, since if we can't get it in ten attempts adding 90 more attempts probably won't help, we're better off to just queue the request


Modified:
    team/sruffell/asterisk-1.4-transcoder/channels/chan_sip.c

Modified: team/sruffell/asterisk-1.4-transcoder/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/sruffell/asterisk-1.4-transcoder/channels/chan_sip.c?view=diff&rev=167368&r1=167367&r2=167368
==============================================================================
--- team/sruffell/asterisk-1.4-transcoder/channels/chan_sip.c (original)
+++ team/sruffell/asterisk-1.4-transcoder/channels/chan_sip.c Tue Jan  6 17:54:32 2009
@@ -629,6 +629,13 @@
 	char data[SIP_MAX_PACKET];
 	unsigned int sdp_start; /*!< the line number where the SDP begins */
 	unsigned int sdp_end;   /*!< the line number where the SDP ends */
+};
+
+struct request_queue_entry {
+	struct sip_request request;
+	/* this is not really necessary, it's in sip_pvt->recv */
+	struct sockaddr_in sin;
+	AST_LIST_ENTRY(request_queue_entry) next;
 };
 
 /*
@@ -1022,6 +1029,8 @@
 	struct sip_history_head *history;	/*!< History of this SIP dialog */
 	size_t history_entries;			/*!< Number of entires in the history */
 	struct ast_variable *chanvars;		/*!< Channel variables to set for inbound call */
+	AST_LIST_HEAD_NOLOCK(request_queue, request_queue_entry) request_queue;
+	int request_queue_sched_id;
 	struct sip_pvt *next;			/*!< Next dialog in chain */
 	struct sip_invite_param *options;	/*!< Options for INVITE */
 	int autoframing;
@@ -3155,6 +3164,7 @@
 	AST_SCHED_DEL(sched, p->initid);
 	AST_SCHED_DEL(sched, p->waitid);
 	AST_SCHED_DEL(sched, p->autokillid);
+	AST_SCHED_DEL(sched, p->request_queue_sched_id);
 
 	if (p->rtp) {
 		ast_rtp_destroy(p->rtp);
@@ -4497,6 +4507,7 @@
 	p->initid = -1;
 	p->waitid = -1;
 	p->autokillid = -1;
+	p->request_queue_sched_id = -1;
 	p->subscribed = NONE;
 	p->stateid = -1;
 	p->prefs = default_prefs;		/* Set default codecs for this call */
@@ -4594,6 +4605,8 @@
 		p->t38.jointcapability = p->t38.capability;
 	}
 	ast_string_field_set(p, context, default_context);
+
+	AST_LIST_HEAD_INIT_NOLOCK(&p->request_queue);
 
 	/* Add to active dialog list */
 	ast_mutex_lock(&iflock);
@@ -15918,6 +15931,86 @@
 	return res;
 }
 
+static void process_request_queue(struct sip_pvt *p, int *recount, int *nounlock)
+{
+	struct request_queue_entry *rqe;
+	
+	while ((rqe = AST_LIST_REMOVE_HEAD(&p->request_queue, next))) {
+		if (handle_request(p, &rqe->request, &rqe->sin, recount, nounlock) == -1) {
+			/* Request failed */
+			if (option_debug) {
+				ast_log(LOG_DEBUG, "SIP message could not be handled, bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
+			}
+		}
+		ast_free(rqe);
+	}
+}
+
+static int scheduler_process_request_queue(const void *data)
+{
+	struct sip_pvt *p = (struct sip_pvt *) data;
+	int recount = 0;
+	int nounlock = 0;
+	int lockretry;
+
+	for (lockretry = 10; lockretry > 0; lockretry--) {
+		ast_mutex_lock(&p->lock);
+
+		/* lock the owner if it has one -- we may need it */
+		/* because this is deadlock-prone, we need to try and unlock if failed */
+		if (!p->owner || !ast_channel_trylock(p->owner)) {
+			break;	/* locking succeeded */
+		}
+
+		if (lockretry != 1) {
+			ast_mutex_unlock(&p->lock);
+			/* Sleep for a very short amount of time */
+			usleep(1);
+		}
+	}
+
+	if (!lockretry) {
+		/* we couldn't get the owner lock, which is needed to process
+		   the queued requests, so return a non-zero value, which will
+		   cause the scheduler to run this request again later
+		*/
+		ast_mutex_unlock(&p->lock);
+		return 1;
+	};
+
+	process_request_queue(p, &recount, &nounlock);
+	p->request_queue_sched_id = -1;
+
+	if (p->owner && !nounlock) {
+		ast_channel_unlock(p->owner);
+	}
+	ast_mutex_unlock(&p->lock);
+
+	if (recount) {
+		ast_update_use_count();
+	}
+
+	return 0;
+}
+
+static int queue_request(struct sip_pvt *p, struct sip_request *req, struct sockaddr_in *sin)
+{
+	struct request_queue_entry *rqe;
+
+	if (!(rqe = ast_calloc(1, sizeof(*req)))) {
+		return -1;
+	}
+
+	rqe->request = *req;
+	rqe->sin = *sin;
+	AST_LIST_INSERT_TAIL(&p->request_queue, rqe, next);
+	if (p->request_queue_sched_id == -1) {
+		p->request_queue_sched_id = ast_sched_add(sched, 10, scheduler_process_request_queue, p);
+	}
+
+	return 0;
+}
+
 /*! \brief Read data from SIP socket
 \note sipsock_read locks the owner channel while we are processing the SIP message
 \return 1 on error, 0 on success
@@ -15930,7 +16023,7 @@
 	struct sip_pvt *p;
 	int res;
 	socklen_t len = sizeof(sin);
-	int nounlock;
+	int nounlock = 0;
 	int recount = 0;
 	int lockretry;
 
@@ -15970,7 +16063,7 @@
 		return 1;
 
 	/* Process request, with netlock held, and with usual deadlock avoidance */
-	for (lockretry = 100; lockretry > 0; lockretry--) {
+	for (lockretry = 10; lockretry > 0; lockretry--) {
 		ast_mutex_lock(&netlock);
 
 		/* Find the active SIP dialog or create a new one */
@@ -16005,6 +16098,13 @@
 		append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
 
 	if (!lockretry) {
+		if (!queue_request(p, &req, &sin)) {
+			/* the request has been queued for later handling */
+			ast_mutex_unlock(&p->lock);
+			ast_mutex_unlock(&netlock);
+			return 1;
+		}
+
 		/* XXX Wouldn't p->owner always exist here? */
 		/* This is unsafe, since p->owner wouldn't be locked. */
 		if (p->owner)
@@ -16018,7 +16118,15 @@
 		ast_mutex_unlock(&netlock);
 		return 1;
 	}
-	nounlock = 0;
+
+	/* if there are queued requests on this sip_pvt, process them first, so that everything is
+	   handled in order
+	*/
+	if (!AST_LIST_EMPTY(&p->request_queue)) {
+		AST_SCHED_DEL(sched, p->request_queue_sched_id);
+		process_request_queue(p, &recount, &nounlock);
+	}
+
 	if (handle_request(p, &req, &sin, &recount, &nounlock) == -1) {
 		/* Request failed */
 		if (option_debug)




More information about the asterisk-commits mailing list