diff options
author | jpeeler <jpeeler@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-09-14 22:38:25 +0000 |
---|---|---|
committer | jpeeler <jpeeler@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-09-14 22:38:25 +0000 |
commit | de5d26c34607ea59f2e8cdd2d10886dccbfe8fb3 (patch) | |
tree | a58030accd40e4143d3afa9b4506fff300213d67 /channels/chan_dahdi.c | |
parent | ef7b0cc05f3b625ae16f3935043c0faafc0b8742 (diff) |
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
Diffstat (limited to 'channels/chan_dahdi.c')
-rw-r--r-- | channels/chan_dahdi.c | 49 |
1 files changed, 30 insertions, 19 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 1cc2539c1..187004ef8 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -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); } |