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



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@140246 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.6.2
Doug Bailey 17 years ago
parent be000109dc
commit 3aca08d924

@ -276,12 +276,9 @@ AST_MUTEX_DEFINE_STATIC(monlock);
/*! \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;
@ -503,6 +500,24 @@ struct dahdi_subchannel {
#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;
struct ast_channel *owner; /*!< Our current active owner (if applicable) */
@ -595,6 +610,7 @@ static struct dahdi_pvt {
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 @@ quit_no_clean:
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)
/*
* 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)
{
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);
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;
pvt->mwisend_data.mwisend_current = 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->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;
}
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;
}
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;
}
static int mwi_send_process_buffer(struct dahdi_pvt * pvt, int num_read)
{
struct timeval now;
int res;
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) {
/* 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 - 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_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_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 @@ static void *mwi_send_thread(void *data)
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 @@ static void *mwi_send_thread(void *data)
}
}
quit:
if(mtd->pvt->cidspill) {
ast_free(mtd->pvt->cidspill);
mtd->pvt->cidspill = NULL;
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;
}
mtd->pvt->mwisendactive = 0;
ast_free(mtd);
return 0;
quit:
return -1;
}
ast_mutex_lock(&mwi_thread_lock);
mwi_thread_count--;
ast_cond_signal(&mwi_thread_complete);
ast_mutex_unlock(&mwi_thread_lock);
static int mwi_send_process_event(struct dahdi_pvt * pvt, int event)
{
int handled = 0;
return NULL;
}
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 @@ static void *do_monitor(void *data)
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 @@ static void *do_monitor(void *data)
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 @@ static void *do_monitor(void *data)
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 @@ static void *do_monitor(void *data)
}
}
}
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 @@ static void *do_monitor(void *data)
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 @@ static int dahdi_restart(void)
}
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 @@ static int __unload_module(void)
}
#endif
ast_cond_destroy(&mwi_thread_complete);
ast_cond_destroy(&ss_thread_complete);
return 0;
}
@ -14822,7 +14802,6 @@ static int load_module(void)
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;

Loading…
Cancel
Save