[svn-commits] branch group/sip-threading r26173 - /team/group/sip-threading/channels/

svn-commits at lists.digium.com svn-commits at lists.digium.com
Tue May 9 09:25:26 MST 2006


Author: file
Date: Tue May  9 11:25:25 2006
New Revision: 26173

URL: http://svn.digium.com/view/asterisk?rev=26173&view=rev
Log:
Add what I have done so far since we are out of here

Modified:
    team/group/sip-threading/channels/chan_sip.c

Modified: team/group/sip-threading/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/group/sip-threading/channels/chan_sip.c?rev=26173&r1=26172&r2=26173&view=diff
==============================================================================
--- team/group/sip-threading/channels/chan_sip.c (original)
+++ team/group/sip-threading/channels/chan_sip.c Tue May  9 11:25:25 2006
@@ -864,6 +864,24 @@
 	int packetlen;				/*!< Length of packet */
 	char data[0];
 };	
+
+/*! \brief sip thread - thread used for handling incoming sip requests and responses */
+struct sip_thread {
+	ast_mutex_t lock;                       /*!< Thread lock */
+	ast_cond_t cond;                        /*!< Thread condition -- used to wake it up */
+	pthread_t thread;                       /*!< Actual thread of this structure */
+	int num;                                /*!< Thread number */
+	int die;                                /*!< Tells the thread to die a horrible death */
+	struct sip_request req;                 /*!< SIP request to process */
+	struct sockaddr_in sin;                 /*!< Address information of originator */
+	AST_LIST_ENTRY(sip_thread) entry;       /*!< Linked list information */
+};
+
+static AST_LIST_HEAD_STATIC(idle_list, sip_thread);
+static AST_LIST_HEAD_STATIC(active_list, sip_thread);
+
+/* Maximum thread count */
+static int sipmaxthreads = 10;
 
 /*! \brief Structure for SIP user data. User's place calls to us */
 struct sip_user {
@@ -11879,6 +11897,98 @@
 	return res;
 }
 
+/*! \brief Helper function that processes a SIP request */
+static int sipsock_helper(struct sip_request *req, struct sockaddr_in *sin)
+{
+	struct sip_pvt *p = NULL;
+	int recount, nounlock = 0;
+
+	/* Parse the request */
+	parse_request(req);
+
+	/* Setup parameteres */
+        req->method = find_sip_method(req->rlPart1);
+        if (ast_test_flag(req, SIP_PKT_DEBUG)) {
+                ast_verbose("--- (%d headers %d lines)", req->headers, req->lines);
+                if (req->headers + req->lines == 0)
+                        ast_verbose(" Nat keepalive ");
+                ast_verbose("---\n");
+        }
+
+        if (req->headers < 2) {
+                /* Must have at least two headers */
+		ast_log(LOG_NOTICE, "Must have at least two headers but we only have %d\n", req->headers);
+                return 1;
+        }
+
+retrylock:
+	if ((p = find_call(req, sin, req->method))) {
+		if (p->owner && ast_channel_trylock(p->owner)) {
+                        if (option_debug)
+                                ast_log(LOG_DEBUG, "Failed to grab lock, trying again...\n");
+                        ast_mutex_unlock(&p->lock);
+                        usleep(1);
+                        goto retrylock;
+                }
+                p->recv = *sin;
+		if (recordhistory) /* This is a request or response, note what it was for */
+                        append_history(p, "Rx", "%s / %s / %s", req->data, get_header(req, "CSeq"), req->rlPart2);
+		if (handle_request(p, req, 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>");
+                }
+
+                if (p->owner && !nounlock)
+                        ast_channel_unlock(p->owner);
+                ast_mutex_unlock(&p->lock);
+        } else {
+                if (option_debug)
+                        ast_log(LOG_DEBUG, "Invalid SIP message - rejected , bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
+        }
+
+        if (recount)
+                ast_update_use_count();
+
+	return 0;
+}
+
+/*! \brief SIP Thread (used to offload request and response processing) */
+static void *sipsock_thread(void *data)
+{
+	struct sip_thread *thread = data;
+
+	if (!thread)
+		return NULL;
+
+	ast_log(LOG_DEBUG, "Sip thread %d starting\n", thread->num);
+
+	ast_mutex_lock(&thread->lock);
+	for (;;) {
+		/* Wait for data to come in */
+		ast_cond_wait(&thread->cond, &thread->lock);
+		/* See if we are being destroyed */
+		if (thread->die)
+			break;
+		/* Otherwise handle provided data */
+		sipsock_helper(&thread->req, &thread->sin);
+		/* Move ourselves from active to idle */
+		AST_LIST_LOCK(&active_list);
+		AST_LIST_REMOVE(&active_list, thread, entry);
+		AST_LIST_UNLOCK(&active_list);
+		AST_LIST_LOCK(&idle_list);
+		AST_LIST_INSERT_TAIL(&idle_list, thread, entry);
+		AST_LIST_UNLOCK(&idle_list);
+		ast_log(LOG_DEBUG, "Thread %d woke up and is servicing data\n", thread->num);
+	}
+	ast_log(LOG_DEBUG, "Thread %d is being destroyed\n", thread->num);
+	ast_mutex_unlock(&thread->lock);
+
+	/* We will actually be freed elsewhere */
+
+	return NULL;
+}
+
 /*! \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
@@ -11886,14 +11996,17 @@
 */
 static int sipsock_read(int *id, int fd, short events, void *ignore)
 {
+	struct sip_thread *thread = NULL;
 	struct sip_request req;
 	struct sockaddr_in sin = { 0, };
-	struct sip_pvt *p;
 	int res;
 	socklen_t len;
-	int nounlock;
-	int recount = 0;
 	char iabuf[INET_ADDRSTRLEN];
+
+	/* Find an idle thread if possible */
+	AST_LIST_LOCK(&idle_list);
+	thread = AST_LIST_REMOVE_HEAD(&idle_list, entry);
+	AST_LIST_UNLOCK(&idle_list);
 
 	len = sizeof(sin);
 	memset(&req, 0, sizeof(req));
@@ -11920,59 +12033,20 @@
 	if (ast_test_flag(&req, SIP_PKT_DEBUG))
 		ast_verbose("\n<-- SIP read from %s:%d: \n%s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), req.data);
 
-	parse_request(&req);
-	req.method = find_sip_method(req.rlPart1);
-	if (ast_test_flag(&req, SIP_PKT_DEBUG)) {
-		ast_verbose("--- (%d headers %d lines)", req.headers, req.lines);
-		if (req.headers + req.lines == 0) 
-			ast_verbose(" Nat keepalive ");
-		ast_verbose("---\n");
-	}
-
-	if (req.headers < 2) {
-		/* Must have at least two headers */
-		return 1;
-	}
-
-
-	/* Process request, with netlock held */
-retrylock:
-	ast_mutex_lock(&netlock);
-
-	/* Find the active SIP dialog or create a new one */
-	p = find_call(&req, &sin, req.method);	/* returns p locked */
-	if (p) {
-		/* Go ahead and lock the owner if it has one -- we may need it */
-		/* becaues this is deadlock-prone, we need to try and unlock if failed */
-		if (p->owner && ast_channel_trylock(p->owner)) {
-			if (option_debug)
-				ast_log(LOG_DEBUG, "Failed to grab lock, trying again...\n");
-			ast_mutex_unlock(&p->lock);
-			ast_mutex_unlock(&netlock);
-			/* Sleep infintismly short amount of time */
-			usleep(1);
-			goto retrylock;
-		}
-		p->recv = sin;
-		if (recordhistory) /* This is a request or response, note what it was for */
-			append_history(p, "Rx", "%s / %s / %s", req.data, get_header(&req, "CSeq"), req.rlPart2);
-		nounlock = 0;
-		if (handle_request(p, &req, &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>");
-		}
-		
-		if (p->owner && !nounlock)
-			ast_channel_unlock(p->owner);
-		ast_mutex_unlock(&p->lock);
+	/* If we have a thread available... pass it there -- otherwise do it in this thread */
+	if (thread) {
+		/* Lock the thread... signal it, and add it to the active list */
+		AST_LIST_LOCK(&active_list);
+		ast_mutex_lock(&thread->lock);
+		ast_cond_signal(&thread->cond);
+		thread->sin = sin;
+		thread->req = req;
+		AST_LIST_INSERT_TAIL(&active_list, thread, entry);
+		AST_LIST_UNLOCK(&active_list);
+		ast_mutex_unlock(&thread->lock);
 	} else {
-		if (option_debug)
-			ast_log(LOG_DEBUG, "Invalid SIP message - rejected , bad request: %-70.70s\n", p->callid[0] ? p->callid : "<no callid>");
-	}
-	ast_mutex_unlock(&netlock);
-	if (recount)
-		ast_update_use_count();
+		sipsock_helper(&req, &sin);
+	}
 
 	return 1;
 }
@@ -13121,6 +13195,8 @@
 	int registry_count = 0, peer_count = 0, user_count = 0;
 	int temp_tos = 0;
 	struct ast_flags debugflag = {0};
+	struct sip_thread *thread = NULL;
+	int threadcount = 0;
 
 	cfg = ast_config_load(config);
 
@@ -13420,6 +13496,35 @@
 		allow_external_domains = 1;
 	}
 	
+	/* Spawn SIP threads if possible */
+	if (sipmaxthreads > 0 && AST_LIST_EMPTY(&idle_list) && AST_LIST_EMPTY(&active_list)) {
+		ast_log(LOG_NOTICE, "Spawning threads\n");
+		while (sipmaxthreads > threadcount) {
+			/* Allocate memory for this thread, and set it up */
+			thread = ast_calloc(1, sizeof(*thread));
+			ast_mutex_init(&thread->lock);
+			ast_cond_init(&thread->cond, NULL);
+			thread->num = threadcount++;
+			/* Good, now fire up an actual thread with this structure and let it go */
+			ast_mutex_lock(&thread->lock);
+			if (ast_pthread_create(&thread->thread, NULL, sipsock_thread, thread) < 0) {
+				/* Bail out ;( */
+				ast_log(LOG_ERROR, "Failed to create SIP thread\n");
+				ast_mutex_unlock(&thread->lock);
+				ast_cond_destroy(&thread->cond);
+				ast_mutex_destroy(&thread->lock);
+				free(thread);
+				break;
+			} else {
+				/* Everything was fine so add it to the list and unlock it */
+				AST_LIST_LOCK(&idle_list);
+				AST_LIST_INSERT_TAIL(&idle_list, thread, entry);
+				AST_LIST_UNLOCK(&idle_list);
+				ast_mutex_unlock(&thread->lock);
+			}
+		}
+	}
+
 	/* Build list of authentication to various SIP realms, i.e. service providers */
  	for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
  		/* Format for authentication is auth = username:password at realm */
@@ -13999,6 +14104,7 @@
 
 static int unload_module(void *mod)
 {
+	struct sip_thread *thread = NULL;
 	struct sip_pvt *p, *pl;
 	
 	/* First, take us out of the channel type list */
@@ -14018,6 +14124,35 @@
 
 	ast_manager_unregister("SIPpeers");
 	ast_manager_unregister("SIPshowpeer");
+
+	/* Stop idle and active threads */
+	AST_LIST_LOCK(&idle_list);
+	while ((thread = AST_LIST_REMOVE_HEAD(&idle_list, entry))) {
+		ast_mutex_lock(&thread->lock);
+		thread->die = 1;
+		ast_cond_signal(&thread->cond);
+		ast_mutex_unlock(&thread->lock);
+		pthread_join(thread->thread, NULL);
+		/* Free the data */
+		ast_mutex_destroy(&thread->lock);
+		ast_cond_destroy(&thread->cond);
+		free(thread);
+	}
+	AST_LIST_UNLOCK(&idle_list);
+
+	AST_LIST_LOCK(&active_list);
+	while ((thread = AST_LIST_REMOVE_HEAD(&active_list, entry))) {
+                ast_mutex_lock(&thread->lock);
+                thread->die = 1;
+                ast_cond_signal(&thread->cond);
+                ast_mutex_unlock(&thread->lock);
+                pthread_join(thread->thread, NULL);
+                /* Free the data */
+                ast_mutex_destroy(&thread->lock);
+                ast_cond_destroy(&thread->cond);
+                free(thread);
+	}
+	AST_LIST_UNLOCK(&active_list);
 
 	if (!ast_mutex_lock(&iflock)) {
 		/* Hangup all interfaces if they have an owner */



More information about the svn-commits mailing list