[asterisk-commits] dbailey: trunk r140246 - /trunk/channels/chan_dahdi.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Aug 26 16:59:32 CDT 2008


Author: dbailey
Date: Tue Aug 26 16:59:31 2008
New Revision: 140246

URL: http://svn.digium.com/view/asterisk?view=rev&rev=140246
Log:
Move the mwi send thread functionality back into the do_monitor thread so that it is easier to manage CID spill resources when do_monitor needs to be killed. 
(closes issue #13213)
Reported by: bbryant


Modified:
    trunk/channels/chan_dahdi.c

Modified: trunk/channels/chan_dahdi.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=140246&r1=140245&r2=140246
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Tue Aug 26 16:59:31 2008
@@ -276,12 +276,9 @@
 /*! \brief This is the thread for the monitor which checks for input on the channels
    which are not currently in use. */
 static pthread_t monitor_thread = AST_PTHREADT_NULL;
-static ast_cond_t mwi_thread_complete;
 static ast_cond_t ss_thread_complete;
-AST_MUTEX_DEFINE_STATIC(mwi_thread_lock);
 AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
 AST_MUTEX_DEFINE_STATIC(restart_lock);
-static int mwi_thread_count = 0;
 static int ss_thread_count = 0;
 static int num_restart_pending = 0;
 
@@ -502,6 +499,24 @@
 #define CONF_USER_THIRDCALL	(1 << 1)
 
 #define MAX_SLAVES	4
+
+/* States for sending MWI message
+ * First three states are required for send Ring Pulse Alert Signal 
+ */
+typedef enum {
+ MWI_SEND_NULL = 0,
+ MWI_SEND_SA,
+ MWI_SEND_SA_WAIT,
+ MWI_SEND_PAUSE,
+ MWI_SEND_SPILL,
+ MWI_SEND_CLEANUP,
+ MWI_SEND_DONE,
+} mwisend_states ;
+
+struct mwisend_info {
+	struct	timeval	pause;
+	mwisend_states 	mwisend_current;
+};
 
 static struct dahdi_pvt {
 	ast_mutex_t lock;
@@ -595,6 +610,7 @@
 	unsigned int setup_ack:1;
 #endif
 	unsigned int use_smdi:1;		/* Whether to use SMDI on this channel */
+	struct mwisend_info mwisend_data;
 	struct ast_smdi_interface *smdi_iface;	/* The serial port to listen for SMDI data on */
 
 	struct dahdi_distRings drings;
@@ -7480,135 +7496,80 @@
 	return NULL;
 }
 
-/* States for sending MWI message
- * First three states are required for send Ring Pulse Alert Signal 
- */
-enum mwisend_states {
-	MWI_SEND_SA,
- MWI_SEND_SA_WAIT,
- MWI_SEND_PAUSE,
- MWI_SEND_SPILL,
- MWI_SEND_CLEANUP,
- MWI_SEND_DONE
-};
-
-static void *mwi_send_thread(void *data)
-{
-	struct mwi_thread_data *mtd = data;
-	struct timeval timeout_basis, suspend, now;
-	int x, i, res;
-	int num_read;
-	enum mwisend_states mwi_send_state = MWI_SEND_SPILL; /*Assume FSK only */
-
-	ast_mutex_lock(&mwi_thread_lock);
-	mwi_thread_count++;
-	ast_mutex_unlock(&mwi_thread_lock);
-
+/*
+* The following three functions (mwi_send_init, mwi_send_process_buffer,
+* mwi_send_process_event) work with the do_monitor thread to generate mwi spills
+* that are sent out via FXA port on voicemail state change.  The execution of
+* the mwi send is state driven and can either generate a ring pulse prior to
+* sending the fsk spill or simply send an fsk spill.
+*/
+static int mwi_send_init(struct dahdi_pvt * pvt)
+{
+	int x, res;
+
+	pvt->mwisendactive = 1;
+	pvt->mwisend_data.mwisend_current = MWI_SEND_SPILL; /*Assume FSK only */
 	/* Determine how this spill is to be sent */
 	if(mwisend_rpas) {
-		mwi_send_state = MWI_SEND_SA;
-	}
-
-	gettimeofday(&timeout_basis, NULL);
-	
-	mtd->pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE);
-	if (!mtd->pvt->cidspill) {
-		mtd->pvt->mwisendactive = 0;
-		ast_free(mtd);
-		return NULL;
+		pvt->mwisend_data.mwisend_current = MWI_SEND_SA;
+	}
+
+	pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE);
+	if (!pvt->cidspill) {
+		pvt->mwisendactive = 0;
+		return -1;
 	}
 	x = DAHDI_FLUSH_BOTH;
-	res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
+	res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
 	x = 3000;
-	ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
-	mtd->pvt->cidlen = vmwi_generate(mtd->pvt->cidspill, has_voicemail(mtd->pvt), CID_MWI_TYPE_MDMF_FULL,
-									 AST_LAW(mtd->pvt), mtd->pvt->cid_name, mtd->pvt->cid_num, 0);
-	mtd->pvt->cidpos = 0;
-
-	while (MWI_SEND_DONE != mwi_send_state) {
-		num_read = 0;
-		gettimeofday(&now, NULL);
-		if ( 10 < (now.tv_sec - timeout_basis.tv_sec)) {
-			ast_log(LOG_WARNING, "MWI Send TIMEOUT in state %d\n", mwi_send_state);
-			goto quit;
-		}
-
-		i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
-		if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
-			ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
-			goto quit;
-		}
-
-		if (i & DAHDI_IOMUX_SIGEVENT) {
-			/* If we get an event, screen out events that we do not act on.
-			* Otherwise, let handle_init_event determine what is needed
-			*/
-			res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
-			switch (res) {
-				case DAHDI_EVENT_RINGEROFF:
-					if(mwi_send_state == MWI_SEND_SA_WAIT) {
-						if (dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
-							ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s\n", strerror(errno));
-							goto quit;
-						}
-						mwi_send_state = MWI_SEND_PAUSE;
-						gettimeofday(&suspend, NULL);
-					}
-					break;
-				case DAHDI_EVENT_RINGERON:
-				case DAHDI_EVENT_HOOKCOMPLETE:
-					break;
-				default:
-					/* Got to the default init event handler */
-					if (0 < handle_init_event(mtd->pvt, res)) {
-						/* I've spawned a thread, get out */
-						goto quit;
-					}
-					break;
-			}
-		} else if (i & DAHDI_IOMUX_READ) {
-			if ((num_read = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
-				if (errno != ELAST) {
-					ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
-					goto quit;
-				}
-				break;
-			}
-		}
-		/* Perform mwi send action */
-		switch ( mwi_send_state) {
+	ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
+	pvt->cidlen = vmwi_generate(pvt->cidspill, has_voicemail(pvt), CID_MWI_TYPE_MDMF_FULL,
+								AST_LAW(pvt), pvt->cid_name, pvt->cid_num, 0);
+	pvt->cidpos = 0;
+	return 0;
+}
+
+static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
+{
+	struct timeval 	now;
+	int 			res;
+
+	/* sanity check to catch if this had been interrupted previously
+	*	i.e. state says there is more to do but there is no spill allocated
+	*/
+	if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current && !pvt->cidspill) {
+		pvt->mwisend_data.mwisend_current = MWI_SEND_DONE;
+	} else if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
+		/* Normal processing -- Perform mwi send action */
+		switch ( pvt->mwisend_data.mwisend_current) {
 			case MWI_SEND_SA:
 				/* Send the Ring Pulse Signal Alert */
-				res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
+				res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
 				if (res) {
 					ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
 					goto quit;
 				}
-				dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RING);
-				mwi_send_state = MWI_SEND_SA_WAIT;
+				res = dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RING);
+				pvt->mwisend_data.mwisend_current = MWI_SEND_SA_WAIT;
 				break;
-				case MWI_SEND_SA_WAIT:  /* do nothing until I get RINGEROFF event */
-					break;
-					case MWI_SEND_PAUSE:  /* Wait between alert and spill - min of 500 mS*/
-						gettimeofday(&now, NULL);
-						if ((int)(now.tv_sec - suspend.tv_sec) * 1000000 + (int)now.tv_usec - (int)suspend.tv_usec > 500000) {
-							mwi_send_state = MWI_SEND_SPILL;
-						}
-						break;
+			case MWI_SEND_SA_WAIT:  /* do nothing until I get RINGEROFF event */
+				break;
+			case MWI_SEND_PAUSE:  /* Wait between alert and spill - min of 500 mS*/
+				gettimeofday(&now, NULL);
+				if ((int)(now.tv_sec - pvt->mwisend_data.pause.tv_sec) * 1000000 + (int)now.tv_usec - (int)pvt->mwisend_data.pause.tv_usec > 500000) {
+					pvt->mwisend_data.mwisend_current = MWI_SEND_SPILL;
+				}
+				break;
 			case MWI_SEND_SPILL:
 				/* We read some number of bytes.  Write an equal amount of data */
 				if(0 < num_read) {
-					if (num_read > mtd->pvt->cidlen - mtd->pvt->cidpos)
-						num_read = mtd->pvt->cidlen - mtd->pvt->cidpos;
-					res = write(mtd->pvt->subs[SUB_REAL].dfd, mtd->pvt->cidspill + mtd->pvt->cidpos, num_read);
+					if (num_read > pvt->cidlen - pvt->cidpos)
+						num_read = pvt->cidlen - pvt->cidpos;
+					res = write(pvt->subs[SUB_REAL].dfd, pvt->cidspill + pvt->cidpos, num_read);
 					if (res > 0) {
-						mtd->pvt->cidpos += res;
-						if (mtd->pvt->cidpos >= mtd->pvt->cidlen) {
-							ast_free(mtd->pvt->cidspill);
-							mtd->pvt->cidspill = NULL;
-							mtd->pvt->cidpos = 0;
-							mtd->pvt->cidlen = 0;
-							mwi_send_state = MWI_SEND_CLEANUP;
+						pvt->cidpos += res;
+						if (pvt->cidpos >= pvt->cidlen) {
+							pvt->mwisend_data.mwisend_current = MWI_SEND_CLEANUP;
 						}
 					} else {
 						ast_log(LOG_WARNING, "MWI Send Write failed: %s\n", strerror(errno));
@@ -7618,7 +7579,7 @@
 				break;
 			case MWI_SEND_CLEANUP:
 				/* For now, do nothing */
-				mwi_send_state = MWI_SEND_DONE;
+				pvt->mwisend_data.mwisend_current = MWI_SEND_DONE;
 				break;
 			default:
 				/* Should not get here, punt*/
@@ -7627,22 +7588,54 @@
 		}
 	}
 
+	if (MWI_SEND_DONE == pvt->mwisend_data.mwisend_current) {
+		if(pvt->cidspill) {
+			ast_free(pvt->cidspill);
+			pvt->cidspill = NULL;
+			pvt->cidpos = 0;
+			pvt->cidlen = 0;
+		}
+		pvt->mwisendactive = 0;
+	}
+	return 0;
 quit:
-	if(mtd->pvt->cidspill) {
-		ast_free(mtd->pvt->cidspill);
-		mtd->pvt->cidspill = NULL;
-	}
-	mtd->pvt->mwisendactive = 0;
-	ast_free(mtd);
-
-	ast_mutex_lock(&mwi_thread_lock);
-	mwi_thread_count--;
-	ast_cond_signal(&mwi_thread_complete);
-	ast_mutex_unlock(&mwi_thread_lock);
-
-	return NULL;
-}
-
+	return -1;
+}
+
+static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
+{
+	int handled = 0;
+
+	if (MWI_SEND_DONE != pvt->mwisend_data.mwisend_current) {
+		switch (event) {
+		case DAHDI_EVENT_RINGEROFF:
+
+			if(pvt->mwisend_data.mwisend_current == MWI_SEND_SA_WAIT) {
+				handled = 1;
+				
+				if (dahdi_set_hook(pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
+					ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s mwi send aborted\n", strerror(errno));
+					if(pvt->cidspill) {
+						ast_free(pvt->cidspill);
+						pvt->cidspill = NULL;
+					}
+					pvt->mwisend_data.mwisend_current = MWI_SEND_DONE;
+					pvt->mwisendactive = 0;
+				} else {
+					pvt->mwisend_data.mwisend_current = MWI_SEND_PAUSE;
+					gettimeofday(&pvt->mwisend_data.pause, NULL);
+				}
+			}
+			break;
+		case DAHDI_EVENT_RINGERON:
+		case DAHDI_EVENT_HOOKCOMPLETE:
+			break;
+		default:
+			break;
+		}
+	}
+	return handled;
+}
 
 /* destroy a DAHDI channel, identified by its number */
 static int dahdi_destroy_channel_bynum(int channel)
@@ -7941,14 +7934,14 @@
 		i = iflist;
 		while (i) {
 			if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
-				if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive && !i->mwisendactive) {
+				if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive ) {
 					/* This needs to be watched, as it lacks an owner */
 					pfds[count].fd = i->subs[SUB_REAL].dfd;
 					pfds[count].events = POLLPRI;
 					pfds[count].revents = 0;
 					/* If we are monitoring for VMWI or sending CID, we need to
 					   read from the channel as well */
-					if (i->cidspill || i->mwimonitor_fsk)
+					if (i->cidspill || i->mwisendactive || i->mwimonitor_fsk)
 						pfds[count].events |= POLLIN;
 					count++;
 				}
@@ -7987,29 +7980,18 @@
 						if (!last->mwisendactive &&	 last->sig & __DAHDI_SIG_FXO) {
 							res = has_voicemail(last);
 							if (last->msgstate != res) {
-
-								/* This channel has a new voicemail state,
-								* initiate a thread to send an MWI message
-								*/
-								pthread_attr_t attr;
-								pthread_t threadid;
-								struct mwi_thread_data *mtd;
+								/* Set driver resources for signalling VMWI */
 								res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, res);
 								if (res2) {
 									ast_log(LOG_DEBUG, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
 								}
-								pthread_attr_init(&attr);
-								pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-								if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
-									last->msgstate = res;
-									mtd->pvt = last;
-									last->mwisendactive = 1;
-									if (ast_pthread_create_background(&threadid, &attr, mwi_send_thread, mtd)) {
-										ast_log(LOG_WARNING, "Unable to start mwi send thread on channel %d\n", last->channel);
-										ast_free(mtd);
-										last->mwisendactive = 0;
-									}
+								/* This channel has a new voicemail state,
+								* initiate a mechanism to send an MWI message
+								*/
+								if (mwi_send_init(last)) {
+									ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
 								}
+								last->msgstate = res;
 								found ++;
 							}
 						}
@@ -8042,8 +8024,8 @@
 						i = i->next;
 						continue;
 					}
-					if (!i->cidspill && !i->mwimonitor_fsk) {
-						ast_log(LOG_WARNING, "Whoa....  I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
+					if (!i->mwimonitor_fsk && !i->mwisendactive) {
+						ast_log(LOG_WARNING, "Whoa....  I'm not looking for MWI or sending MWI but am reading (%d)...\n", i->subs[SUB_REAL].dfd);
 						i = i->next;
 						continue;
 					}
@@ -8071,6 +8053,9 @@
 								}
 							}
 						}
+						if (i->mwisendactive) {
+							mwi_send_process_buffer(i, res);
+						}
 					} else {
 						ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
 					}
@@ -8088,8 +8073,10 @@
 					ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
 					/* Don't hold iflock while handling init events */
 					ast_mutex_unlock(&iflock);
-					handle_init_event(i, res);
-					ast_mutex_lock(&iflock);	
+					if (0 == i->mwisendactive || 0 != mwi_send_process_event(i, res)) {
+						handle_init_event(i, res);
+					}
+					ast_mutex_lock(&iflock);
 				}
 			}
 			i=i->next;
@@ -12053,12 +12040,6 @@
 	}
 	monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
 
-	ast_mutex_lock(&mwi_thread_lock);
-	while (mwi_thread_count > 0) {
-		ast_debug(3, "Waiting on %d mwi_send_thread(s) to finish\n", mwi_thread_count);
-		ast_cond_wait(&mwi_thread_complete, &mwi_thread_lock);
-	}
-	ast_mutex_unlock(&mwi_thread_lock);
 	ast_mutex_lock(&ss_thread_lock);
 	while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
 		int x = DAHDI_FLASH;
@@ -13564,7 +13545,6 @@
 	}
 #endif
 
-	ast_cond_destroy(&mwi_thread_complete);
 	ast_cond_destroy(&ss_thread_complete);
 	return 0;
 }
@@ -14822,7 +14802,6 @@
 	ast_manager_register("DAHDIShowChannels", 0, action_dahdishowchannels, "Show status DAHDI channels");
 	ast_manager_register("DAHDIRestart", 0, action_dahdirestart, "Fully Restart DAHDI channels (terminates calls)");
 
-	ast_cond_init(&mwi_thread_complete, NULL);
 	ast_cond_init(&ss_thread_complete, NULL);
 
 	return res;




More information about the asterisk-commits mailing list