Merged revisions 218401 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r218401 | jpeeler | 2009-09-14 16:47:11 -0500 (Mon, 14 Sep 2009) | 11 lines Fix handling of DAHDI_EVENT_REMOVED event to prevent crash in do_monitor. After talking to rmudgett about some of his recent iflist locking changes, it was determined that the only place that would destroy a channel without being explicitly to do so was in handle_init_event. The loop to walk the interface list has been modified to wait to destroy the channel until the dahdi_pvt of the channel to be destroyed is no longer needed. (closes issue #15378) Reported by: samy ........ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@218430 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
ef7b0cc05f
commit
de5d26c346
|
@ -2411,6 +2411,9 @@ static enum analog_event dahdievent_to_analogevent(int event)
|
|||
case DAHDI_EVENT_PULSE_START:
|
||||
res = ANALOG_EVENT_PULSE_START;
|
||||
break;
|
||||
case DAHDI_EVENT_REMOVED:
|
||||
res = ANALOG_EVENT_REMOVED;
|
||||
break;
|
||||
case DAHDI_EVENT_NEONMWI_ACTIVE:
|
||||
res = ANALOG_EVENT_NEONMWI_ACTIVE;
|
||||
break;
|
||||
|
@ -9916,8 +9919,7 @@ static int dahdi_destroy_channel_bynum(int channel)
|
|||
return RESULT_FAILURE;
|
||||
}
|
||||
|
||||
/* returns < 0 = error, 0 event handled, >0 event handled and thread spawned */
|
||||
static int handle_init_event(struct dahdi_pvt *i, int event)
|
||||
static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
|
||||
{
|
||||
int res;
|
||||
int thread_spawned = 0;
|
||||
|
@ -10026,7 +10028,7 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
|
|||
res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
|
||||
if (res < 0)
|
||||
ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case DAHDI_EVENT_NOALARM:
|
||||
|
@ -10083,7 +10085,7 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
|
|||
default:
|
||||
ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
|
||||
res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case DAHDI_EVENT_POLARITY:
|
||||
|
@ -10118,12 +10120,11 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
|
|||
"interface %d\n", i->channel);
|
||||
}
|
||||
break;
|
||||
case DAHDI_EVENT_REMOVED: /* destroy channel */
|
||||
case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
|
||||
ast_log(LOG_NOTICE,
|
||||
"Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
|
||||
i->channel);
|
||||
dahdi_destroy_channel_bynum(i->channel);
|
||||
break;
|
||||
return i;
|
||||
case DAHDI_EVENT_NEONMWI_ACTIVE:
|
||||
if (i->mwimonitor_neon) {
|
||||
notify_message(i->mailbox, 1);
|
||||
|
@ -10137,7 +10138,7 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
|
|||
}
|
||||
break;
|
||||
}
|
||||
return thread_spawned;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *do_monitor(void *data)
|
||||
|
@ -10145,6 +10146,7 @@ static void *do_monitor(void *data)
|
|||
int count, res, res2, spoint, pollres=0;
|
||||
struct dahdi_pvt *i;
|
||||
struct dahdi_pvt *last = NULL;
|
||||
struct dahdi_pvt *doomed;
|
||||
time_t thispass = 0, lastpass = 0;
|
||||
int found;
|
||||
char buf[1024];
|
||||
|
@ -10243,7 +10245,20 @@ static void *do_monitor(void *data)
|
|||
spoint = 0;
|
||||
lastpass = thispass;
|
||||
thispass = time(NULL);
|
||||
for (i = iflist; i; i = i->next) {
|
||||
doomed = NULL;
|
||||
for (i = iflist;; i = i->next) {
|
||||
if (doomed) {
|
||||
int res;
|
||||
res = dahdi_destroy_channel_bynum(doomed->channel);
|
||||
if (!res) {
|
||||
ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
|
||||
}
|
||||
doomed = NULL;
|
||||
}
|
||||
if (!i) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (thispass != lastpass) {
|
||||
if (!found && ((i == last) || ((i == iflist) && !last))) {
|
||||
last = i;
|
||||
|
@ -10283,9 +10298,9 @@ static void *do_monitor(void *data)
|
|||
/* Don't hold iflock while handling init events */
|
||||
ast_mutex_unlock(&iflock);
|
||||
if (analog_lib_handles(i->sig, i->radio, i->oprmode))
|
||||
analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
|
||||
doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
|
||||
else
|
||||
handle_init_event(i, res);
|
||||
doomed = handle_init_event(i, res);
|
||||
ast_mutex_lock(&iflock);
|
||||
}
|
||||
continue;
|
||||
|
@ -10348,12 +10363,8 @@ static void *do_monitor(void *data)
|
|||
struct ast_channel *chan;
|
||||
ast_mutex_unlock(&iflock);
|
||||
if (analog_lib_handles(i->sig, i->radio, i->oprmode)) {
|
||||
res = analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
|
||||
} else {
|
||||
i->dtmfcid_holdoff_state = 1;
|
||||
}
|
||||
analog_handle_init_event(i->sig_pvt, ANALOG_EVENT_DTMFCID);
|
||||
i->dtmfcid_holdoff_state = 1;
|
||||
} else {
|
||||
chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0, NULL);
|
||||
if (!chan) {
|
||||
|
@ -10392,9 +10403,9 @@ static void *do_monitor(void *data)
|
|||
ast_mutex_unlock(&iflock);
|
||||
if (0 == i->mwisendactive || 0 == mwi_send_process_event(i, res)) {
|
||||
if (analog_lib_handles(i->sig, i->radio, i->oprmode))
|
||||
analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
|
||||
doomed = (struct dahdi_pvt *) analog_handle_init_event(i->sig_pvt, dahdievent_to_analogevent(res));
|
||||
else
|
||||
handle_init_event(i, res);
|
||||
doomed = handle_init_event(i, res);
|
||||
}
|
||||
ast_mutex_lock(&iflock);
|
||||
}
|
||||
|
|
|
@ -256,6 +256,9 @@ static char *analog_event2str(enum analog_event event)
|
|||
case ANALOG_EVENT_PULSE_START:
|
||||
res = "ANALOG_EVENT_PULSE_START";
|
||||
break;
|
||||
case ANALOG_EVENT_REMOVED:
|
||||
res = "ANALOG_EVENT_REMOVED";
|
||||
break;
|
||||
case ANALOG_EVENT_NEONMWI_ACTIVE:
|
||||
res = "ANALOG_EVENT_NEONMWI_ACTIVE";
|
||||
break;
|
||||
|
@ -3169,18 +3172,15 @@ struct ast_frame *analog_exception(struct analog_pvt *p, struct ast_channel *ast
|
|||
return f;
|
||||
}
|
||||
|
||||
int analog_handle_init_event(struct analog_pvt *i, int event)
|
||||
void *analog_handle_init_event(struct analog_pvt *i, int event)
|
||||
{
|
||||
int res;
|
||||
pthread_t threadid;
|
||||
pthread_attr_t attr;
|
||||
struct ast_channel *chan;
|
||||
|
||||
ast_debug(1, "channel (%d) - signaling (%d) - event (%s)\n",
|
||||
i->channel, i->sig, analog_event2str(event));
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
/* Handle an event on a given channel for the monitor thread. */
|
||||
switch (event) {
|
||||
case ANALOG_EVENT_WINKFLASH:
|
||||
|
@ -3223,7 +3223,8 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
}
|
||||
if (res < 0)
|
||||
ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
|
||||
if (ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
|
||||
|
||||
if (ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
|
||||
ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
|
||||
res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
|
||||
if (res < 0) {
|
||||
|
@ -3262,7 +3263,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
chan = analog_new_ast_channel(i, AST_STATE_RING, 0, ANALOG_SUB_REAL, NULL);
|
||||
}
|
||||
i->ss_astchan = chan;
|
||||
if (chan && ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
|
||||
if (chan && ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
|
||||
ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
|
||||
res = analog_play_tone(i, ANALOG_SUB_REAL, ANALOG_TONE_CONGESTION);
|
||||
if (res < 0) {
|
||||
|
@ -3279,7 +3280,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
|
||||
}
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case ANALOG_EVENT_NOALARM:
|
||||
|
@ -3339,7 +3340,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
default:
|
||||
ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", analog_sigtype_to_str(i->sig), i->channel);
|
||||
res = analog_play_tone(i, ANALOG_SUB_REAL, -1);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case ANALOG_EVENT_POLARITY:
|
||||
|
@ -3362,7 +3363,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
i->channel);
|
||||
chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
|
||||
i->ss_astchan = chan;
|
||||
if (chan && ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
|
||||
if (chan && ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
|
||||
ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
|
||||
}
|
||||
}
|
||||
|
@ -3383,7 +3384,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
i->channel);
|
||||
chan = analog_new_ast_channel(i, AST_STATE_PRERING, 0, ANALOG_SUB_REAL, NULL);
|
||||
i->ss_astchan = chan;
|
||||
if (chan && ast_pthread_create(&threadid, &attr, __analog_ss_thread, i)) {
|
||||
if (chan && ast_pthread_create_detached(&threadid, NULL, __analog_ss_thread, i)) {
|
||||
ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
|
||||
}
|
||||
}
|
||||
|
@ -3394,6 +3395,12 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
"interface %d\n", i->channel);
|
||||
}
|
||||
break;
|
||||
case ANALOG_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
|
||||
ast_log(LOG_NOTICE,
|
||||
"Got DAHDI_EVENT_REMOVED. Destroying channel %d\n",
|
||||
i->channel);
|
||||
return i->chan_pvt;
|
||||
break;
|
||||
case ANALOG_EVENT_NEONMWI_ACTIVE:
|
||||
analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_ACTIVE);
|
||||
break;
|
||||
|
@ -3401,8 +3408,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
|
|||
analog_handle_notify_message(NULL, i, -1, ANALOG_EVENT_NEONMWI_INACTIVE);
|
||||
break;
|
||||
}
|
||||
pthread_attr_destroy(&attr);
|
||||
return 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ enum analog_event {
|
|||
ANALOG_EVENT_RINGBEGIN,
|
||||
ANALOG_EVENT_PULSE_START,
|
||||
ANALOG_EVENT_ERROR,
|
||||
ANALOG_EVENT_REMOVED,
|
||||
ANALOG_EVENT_NEONMWI_ACTIVE,
|
||||
ANALOG_EVENT_NEONMWI_INACTIVE,
|
||||
ANALOG_EVENT_DTMFCID,
|
||||
|
@ -328,7 +329,7 @@ struct ast_channel * analog_request(struct analog_pvt *p, int *callwait, const s
|
|||
|
||||
int analog_available(struct analog_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched);
|
||||
|
||||
int analog_handle_init_event(struct analog_pvt *i, int event);
|
||||
void *analog_handle_init_event(struct analog_pvt *i, int event);
|
||||
|
||||
int analog_config_complete(struct analog_pvt *p);
|
||||
|
||||
|
|
Reference in New Issue