diff options
-rw-r--r-- | channels/chan_dahdi.c | 542 |
1 files changed, 385 insertions, 157 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index c1931e9dc..9c70f189b 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -276,6 +276,14 @@ 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; static int restart_monitor(void); @@ -559,6 +567,7 @@ static struct dahdi_pvt { unsigned int priexclusive:1; unsigned int pulse:1; unsigned int pulsedial:1; /*!< whether a pulse dial phone is detected */ + unsigned int restartpending:1; /*!< flag to ensure counted only once for restart */ unsigned int restrictcid:1; /*!< Whether restrict the callerid -> only send ANI */ unsigned int threewaycalling:1; unsigned int transfer:1; @@ -881,7 +890,8 @@ static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri) } } while (res); /* Then break the poll */ - pthread_kill(pri->master, SIGURG); + if (pri->master != AST_PTHREADT_NULL) + pthread_kill(pri->master, SIGURG); return 0; } #endif @@ -903,7 +913,8 @@ static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri) } } while (res); /* Then break the poll */ - pthread_kill(pri->master, SIGURG); + if (pri->master != AST_PTHREADT_NULL) + pthread_kill(pri->master, SIGURG); return 0; } #endif @@ -941,11 +952,11 @@ static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}}; static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok) { int res; - if (p->subs[0].owner == ast) + if (p->subs[SUB_REAL].owner == ast) res = 0; - else if (p->subs[1].owner == ast) + else if (p->subs[SUB_CALLWAIT].owner == ast) res = 1; - else if (p->subs[2].owner == ast) + else if (p->subs[SUB_THREEWAY].owner == ast) res = 2; else { res = -1; @@ -1841,7 +1852,8 @@ static inline int dahdi_set_hook(int fd, int hs) if (res < 0) { if (errno == EINPROGRESS) return 0; - ast_log(LOG_WARNING, "DAHDI hook failed: %s\n", strerror(errno)); + ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno)); + /* will expectedly fail if phone is off hook during operation, such as during a restart */ } return res; @@ -2770,7 +2782,9 @@ static void destroy_dahdi_pvt(struct dahdi_pvt **pvt) if (p->vars) ast_variables_destroy(p->vars); ast_mutex_destroy(&p->lock); - ast_free(p); + if (p->owner) + p->owner->tech_pvt = NULL; + free(p); *pvt = NULL; } @@ -2830,6 +2844,39 @@ static int destroy_channel(struct dahdi_pvt *prev, struct dahdi_pvt *cur, int no return 0; } +static void destroy_all_channels(void) +{ + int x; + struct dahdi_pvt *p, *pl; + + while (num_restart_pending) { + usleep(1); + } + + ast_mutex_lock(&iflock); + /* Destroy all the interfaces and free their memory */ + p = iflist; + while (p) { + /* Free any callerid */ + if (p->cidspill) + ast_free(p->cidspill); + /* Close the DAHDI thingy */ + if (p->subs[SUB_REAL].dfd > -1) + dahdi_close(p->subs[SUB_REAL].dfd); + pl = p; + p = p->next; + x = pl->channel; + /* Free associated memory */ + if (pl) + destroy_dahdi_pvt(&pl); + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x); + } + iflist = NULL; + ifcount = 0; + ast_mutex_unlock(&iflock); +} + #ifdef HAVE_PRI static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility"; @@ -3280,7 +3327,8 @@ static int dahdi_hangup(struct ast_channel *ast) p->pri = NULL; } #endif - restart_monitor(); + if (num_restart_pending == 0) + restart_monitor(); } p->callwaitingrepeat = 0; @@ -3292,6 +3340,11 @@ static int dahdi_hangup(struct ast_channel *ast) ast_verb(3, "Hungup '%s'\n", ast->name); ast_mutex_lock(&iflock); + + if (p->restartpending) { + num_restart_pending--; + } + tmp = iflist; prev = NULL; if (p->destroy) { @@ -6090,21 +6143,23 @@ static void *ss_thread(void *data) int res; int idx; + ast_mutex_lock(&ss_thread_lock); + ss_thread_count++; + ast_mutex_unlock(&ss_thread_lock); /* in the bizarre case where the channel has become a zombie before we even get started here, abort safely */ if (!p) { ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name); ast_hangup(chan); - return NULL; + goto quit; } - ast_verb(3, "Starting simple switch on '%s'\n", chan->name); idx = dahdi_get_index(chan, p, 1); if (idx < 0) { ast_log(LOG_WARNING, "Huh?\n"); ast_hangup(chan); - return NULL; + goto quit; } if (p->dsp) ast_dsp_digitreset(p->dsp); @@ -6130,7 +6185,7 @@ static void *ss_thread(void *data) if (res < 0) { ast_debug(1, "waitfordigit returned < 0...\n"); ast_hangup(chan); - return NULL; + goto quit; } else if (res) { exten[len++] = res; exten[len] = '\0'; @@ -6162,7 +6217,7 @@ static void *ss_thread(void *data) /* Since we send release complete here, we won't get one */ p->call = NULL; } - return NULL; + goto quit; break; #endif case SIG_FEATD: @@ -6177,7 +6232,7 @@ static void *ss_thread(void *data) case SIG_SF_FEATB: case SIG_SFWINK: if (dahdi_wink(p, idx)) - return NULL; + goto quit; /* Fall through */ case SIG_EM: case SIG_EM_E1: @@ -6214,7 +6269,7 @@ static void *ss_thread(void *data) case SIG_FEATDMF_TA: res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000); if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp); - if (dahdi_wink(p, idx)) return NULL; + if (dahdi_wink(p, idx)) goto quit; dtmfbuf[0] = 0; /* Wait for the first digit (up to 5 seconds). */ res = ast_waitfordigit(chan, 5000); @@ -6229,7 +6284,7 @@ static void *ss_thread(void *data) /* if international caca, do it again to get real ANO */ if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14)) { - if (dahdi_wink(p, idx)) return NULL; + if (dahdi_wink(p, idx)) goto quit; dtmfbuf[0] = 0; /* Wait for the first digit (up to 5 seconds). */ res = ast_waitfordigit(chan, 5000); @@ -6276,7 +6331,7 @@ static void *ss_thread(void *data) if (res < 0) { ast_debug(1, "waitfordigit returned < 0...\n"); ast_hangup(chan); - return NULL; + goto quit; } else if (res) { dtmfbuf[len++] = res; dtmfbuf[len] = '\0'; @@ -6290,11 +6345,11 @@ static void *ss_thread(void *data) if (res == -1) { ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno)); ast_hangup(chan); - return NULL; + goto quit; } else if (res < 0) { ast_debug(1, "Got hung up before digits finished\n"); ast_hangup(chan); - return NULL; + goto quit; } if (p->sig == SIG_FGC_CAMA) { @@ -6302,7 +6357,7 @@ static void *ss_thread(void *data) if (ast_safe_sleep(chan,1000) == -1) { ast_hangup(chan); - return NULL; + goto quit; } dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK); ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); @@ -6391,7 +6446,7 @@ static void *ss_thread(void *data) /* some switches require a minimum guard time between the last FGD wink and something that answers immediately. This ensures it */ - if (ast_safe_sleep(chan,100)) return NULL; + if (ast_safe_sleep(chan,100)) goto quit; } dahdi_enable_ec(p); if (NEED_MFDETECT(p)) { @@ -6413,7 +6468,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "PBX exited non-zero\n"); res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); } - return NULL; + goto quit; } else { ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, chan->context); sleep(2); @@ -6427,7 +6482,7 @@ static void *ss_thread(void *data) ast_waitstream(chan, ""); res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); ast_hangup(chan); - return NULL; + goto quit; } break; case SIG_FXOLS: @@ -6451,7 +6506,7 @@ static void *ss_thread(void *data) ast_debug(1, "waitfordigit returned < 0...\n"); res = tone_zone_play_tone(p->subs[idx].dfd, -1); ast_hangup(chan); - return NULL; + goto quit; } else if (res) { ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout); exten[len++]=res; @@ -6497,7 +6552,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "PBX exited non-zero\n"); res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); } - return NULL; + goto quit; } } else { /* It's a match, but they just typed a digit, and there is an ambiguous match, @@ -6509,7 +6564,7 @@ static void *ss_thread(void *data) res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); dahdi_wait_event(p->subs[idx].dfd); ast_hangup(chan); - return NULL; + goto quit; } else if (p->callwaiting && !strcmp(exten, "*70")) { ast_verb(3, "Disabling call waiting on %s\n", chan->name); /* Disable call waiting if enabled */ @@ -6545,11 +6600,11 @@ static void *ss_thread(void *data) dahdi_wait_event(p->subs[idx].dfd); } ast_hangup(chan); - return NULL; + goto quit; } else { ast_log(LOG_WARNING, "Huh? Got *8# on call not on real\n"); ast_hangup(chan); - return NULL; + goto quit; } } else if (!p->hidecallerid && !strcmp(exten, "*67")) { @@ -6664,7 +6719,7 @@ static void *ss_thread(void *data) if (ast_bridged_channel(p->subs[SUB_REAL].owner)) ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD); ast_hangup(chan); - return NULL; + goto quit; } else { tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); dahdi_wait_event(p->subs[idx].dfd); @@ -6673,7 +6728,7 @@ static void *ss_thread(void *data) unalloc_sub(p, SUB_THREEWAY); p->owner = p->subs[SUB_REAL].owner; ast_hangup(chan); - return NULL; + goto quit; } } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) && ((exten[0] != '*') || (strlen(exten) > 2))) { @@ -6705,7 +6760,7 @@ static void *ss_thread(void *data) if (!f) { ast_log(LOG_WARNING, "Whoa, hangup while waiting for first ring!\n"); ast_hangup(chan); - return NULL; + goto quit; } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) { res = 1; } else @@ -6760,7 +6815,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. " "Exiting simple switch\n"); ast_hangup(chan); - return NULL; + goto quit; } f = ast_read(chan); if (!f) @@ -6805,7 +6860,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } if (i & DAHDI_IOMUX_SIGEVENT) { res = dahdi_get_event(p->subs[idx].dfd); @@ -6827,7 +6882,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } break; } @@ -6870,12 +6925,12 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "CID timed out waiting for ring. " "Exiting simple switch\n"); ast_hangup(chan); - return NULL; + goto quit; } if (!(f = ast_read(chan))) { ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n"); ast_hangup(chan); - return NULL; + goto quit; } ast_frfree(f); if (chan->_state == AST_STATE_RING || @@ -6906,7 +6961,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } if (i & DAHDI_IOMUX_SIGEVENT) { res = dahdi_get_event(p->subs[idx].dfd); @@ -6929,7 +6984,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } break; } @@ -6986,7 +7041,7 @@ static void *ss_thread(void *data) "restarted by the actual ring.\n", chan->name); ast_hangup(chan); - return NULL; + goto quit; } } else if (p->use_callerid && p->cid_start == CID_START_RING) { if (p->cid_signalling == CID_SIG_DTMF) { @@ -7057,7 +7112,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } if (i & DAHDI_IOMUX_SIGEVENT) { res = dahdi_get_event(p->subs[idx].dfd); @@ -7068,7 +7123,7 @@ static void *ss_thread(void *data) p->polarity = POLARITY_IDLE; callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } res = 0; /* Let us detect callerid when the telco uses distinctive ring */ @@ -7088,7 +7143,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } break; } @@ -7126,7 +7181,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } if (i & DAHDI_IOMUX_SIGEVENT) { res = dahdi_get_event(p->subs[idx].dfd); @@ -7149,7 +7204,7 @@ static void *ss_thread(void *data) ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno)); callerid_free(cs); ast_hangup(chan); - return NULL; + goto quit; } break; } @@ -7244,7 +7299,7 @@ static void *ss_thread(void *data) ast_hangup(chan); ast_log(LOG_WARNING, "PBX exited non-zero\n"); } - return NULL; + goto quit; default: ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel); res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION); @@ -7255,6 +7310,11 @@ static void *ss_thread(void *data) if (res < 0) ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel); ast_hangup(chan); +quit: + ast_mutex_lock(&ss_thread_lock); + ss_thread_count--; + ast_cond_signal(&ss_thread_complete); + ast_mutex_unlock(&ss_thread_lock); return NULL; } @@ -7282,7 +7342,6 @@ static void *mwi_thread(void *data) { struct mwi_thread_data *mtd = data; struct callerid_state *cs; - pthread_attr_t attr; pthread_t threadid; int samples = 0; char *name, *number; @@ -7341,10 +7400,7 @@ static void *mwi_thread(void *data) mtd->pvt->ringt = mtd->pvt->ringt_base; if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, 0))) { - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - if (ast_pthread_create(&threadid, &attr, ss_thread, chan)) { + if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) { ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel); res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION); if (res < 0) @@ -7433,6 +7489,10 @@ static void *mwi_send_thread(void *data) 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); + /* Determine how this spill is to be sent */ if(mwisend_rpas) { mwi_send_state = MWI_SEND_SA; @@ -7555,15 +7615,21 @@ static void *mwi_send_thread(void *data) break; } } + quit: - if(mtd->pvt->cidspill) { - ast_free(mtd->pvt->cidspill); - mtd->pvt->cidspill = NULL; - } - mtd->pvt->mwisendactive = 0; - ast_free(mtd); + if(mtd->pvt->cidspill) { + ast_free(mtd->pvt->cidspill); + mtd->pvt->cidspill = NULL; + } + mtd->pvt->mwisendactive = 0; + ast_free(mtd); - return NULL; + ast_mutex_lock(&mwi_thread_lock); + mwi_thread_count--; + ast_cond_signal(&mwi_thread_complete); + ast_mutex_unlock(&mwi_thread_lock); + + return NULL; } @@ -7576,6 +7642,8 @@ static int dahdi_destroy_channel_bynum(int channel) tmp = iflist; while (tmp) { if (tmp->channel == channel) { + int x = DAHDI_FLASH; + ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */ destroy_channel(prev, tmp, 1); return RESULT_SUCCESS; } @@ -7837,6 +7905,8 @@ static void *do_monitor(void *data) } ast_debug(1, "Monitor starting...\n"); #endif + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + for (;;) { /* Lock the interface list */ ast_mutex_lock(&iflock); @@ -7876,10 +7946,13 @@ static void *do_monitor(void *data) /* Okay, now that we know what to do, release the interface lock */ ast_mutex_unlock(&iflock); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_testcancel(); /* Wait at least a second for something to happen */ res = poll(pfds, count, 1000); pthread_testcancel(); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + /* Okay, poll has finished. Let's see what happened. */ if (res < 0) { if ((errno != EAGAIN) && (errno != EINTR)) @@ -8032,7 +8105,7 @@ static int restart_monitor(void) pthread_kill(monitor_thread, SIGURG); } else { /* Start a new monitor */ - if (ast_pthread_create_detached_background(&monitor_thread, NULL, do_monitor, NULL) < 0) { + if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) { ast_mutex_unlock(&monlock); ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); return -1; @@ -8243,9 +8316,10 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, tmp2 = tmp2->next; } - if (!here && !reloading) { + if (!here && reloading != 1) { if (!(tmp = ast_calloc(1, sizeof(*tmp)))) { - destroy_dahdi_pvt(&tmp); + if (tmp) + free(tmp); return NULL; } ast_mutex_init(&tmp->lock); @@ -8261,9 +8335,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, if ((channel != CHAN_PSEUDO) && !pri) { snprintf(fn, sizeof(fn), "%d", channel); /* Open non-blocking */ - if (!here) + tmp->subs[SUB_REAL].dfd = dahdi_open(fn); + while (tmp->subs[SUB_REAL].dfd < 0 && reloading == 2) { /* the kernel may not call dahdi_release fast enough for the open flagbit to be cleared in time */ + usleep(1); tmp->subs[SUB_REAL].dfd = dahdi_open(fn); - /* Allocate a dahdi structure */ + } + /* Allocate a DAHDI structure */ if (tmp->subs[SUB_REAL].dfd < 0) { ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel); destroy_dahdi_pvt(&tmp); @@ -9754,7 +9831,7 @@ static void *ss7_linkset(void *data) if (p->owner) { p->owner->hangupcause = e->rel.cause; p->owner->_softhangup |= AST_SOFTHANGUP_DEV; - } else + } else if (!p->restartpending) ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic); /* End the loopback if we have one */ @@ -10338,6 +10415,9 @@ static void *pri_dchannel(void *vpri) char plancallingani[256]; char calledtonstr[10]; + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + gettimeofday(&lastidle, NULL); if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) { /* Need to do idle dialing, check to be sure though */ cc = strchr(pri->idleext, '@'); @@ -10462,8 +10542,12 @@ static void *pri_dchannel(void *vpri) } ast_mutex_unlock(&pri->lock); + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + pthread_testcancel(); e = NULL; res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000); + pthread_testcancel(); + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); ast_mutex_lock(&pri->lock); if (!res) { @@ -11884,20 +11968,148 @@ static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_ return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE; } +static void dahdi_softhangup_all(void) +{ + struct dahdi_pvt *p; +retry: + ast_mutex_lock(&iflock); + for (p = iflist; p; p = p->next) { + ast_mutex_lock(&p->lock); + if (p->owner && !p->restartpending) { + if (ast_channel_trylock(p->owner)) { + if (option_debug > 2) + ast_verbose("Avoiding deadlock\n"); + /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */ + ast_mutex_unlock(&p->lock); + ast_mutex_unlock(&iflock); + goto retry; + } + if (option_debug > 2) + ast_verbose("Softhanging up on %s\n", p->owner->name); + ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_EXPLICIT); + p->restartpending = 1; + num_restart_pending++; + ast_channel_unlock(p->owner); + } + ast_mutex_unlock(&p->lock); + } + ast_mutex_unlock(&iflock); +} + static int setup_dahdi(int reload); static int dahdi_restart(void) { + + int i, j, cancel_code; + struct dahdi_pvt *p; + + ast_mutex_lock(&restart_lock); + ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n"); - while (iflist) { - ast_debug(1, "Destroying DAHDI channel no. %d\n", iflist->channel); - /* Also updates iflist: */ - destroy_channel(NULL, iflist, 1); + dahdi_softhangup_all(); + ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n"); + +#if defined(HAVE_PRI) + for (i = 0; i < NUM_SPANS; i++) { + if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) { + cancel_code = pthread_cancel(pris[i].master); + pthread_kill(pris[i].master, SIGURG); + ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) pris[i].master, cancel_code); + pthread_join(pris[i].master, NULL); + ast_debug(4, "Joined thread of span %d\n", i); + } } - ast_debug(1, "Channels destroyed. Now re-reading config.\n"); +#endif + +#if defined(HAVE_SS7) + for (i = 0; i < NUM_SPANS; i++) { + if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) { + cancel_code = pthread_cancel(linksets[i].master); + pthread_kill(linksets[i].master, SIGURG); + ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) linksets[i].master, cancel_code); + pthread_join(linksets[i].master, NULL); + ast_debug(4, "Joined thread of span %d\n", i); + } + } +#endif + + ast_mutex_lock(&monlock); + if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { + cancel_code = pthread_cancel(monitor_thread); + pthread_kill(monitor_thread, SIGURG); + ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code); + pthread_join(monitor_thread, NULL); + ast_debug(4, "Joined monitor thread\n"); + } + 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; + ast_debug(3, "Waiting on %d ss_thread(s) to finish\n", ss_thread_count); + + for (p = iflist; p; p = p->next) { + if (p->owner) + ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */ + } + ast_cond_wait(&ss_thread_complete, &ss_thread_lock); + } + + /* ensure any created channels before monitor threads were stopped are hungup */ + dahdi_softhangup_all(); + ast_verb(4, "Final softhangup of all DAHDI channels complete.\n"); + destroy_all_channels(); + ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels()); + + ast_mutex_unlock(&monlock); + +#ifdef HAVE_PRI + for (i = 0; i < NUM_SPANS; i++) { + for (j = 0; j < NUM_DCHANS; j++) + dahdi_close(pris[i].fds[j]); + } + + memset(pris, 0, sizeof(pris)); + for (i = 0; i < NUM_SPANS; i++) { + ast_mutex_init(&pris[i].lock); + pris[i].offset = -1; + pris[i].master = AST_PTHREADT_NULL; + for (j = 0; j < NUM_DCHANS; j++) + pris[i].fds[j] = -1; + } + pri_set_error(dahdi_pri_error); + pri_set_message(dahdi_pri_message); +#endif +#ifdef HAVE_SS7 + for (i = 0; i < NUM_SPANS; i++) { + for (j = 0; j < NUM_DCHANS; j++) + dahdi_close(linksets[i].fds[j]); + } + + memset(linksets, 0, sizeof(linksets)); + for (i = 0; i < NUM_SPANS; i++) { + ast_mutex_init(&linksets[i].lock); + linksets[i].master = AST_PTHREADT_NULL; + for (j = 0; j < NUM_DCHANS; j++) + linksets[i].fds[j] = -1; + } + ss7_set_error(dahdi_ss7_error); + ss7_set_message(dahdi_ss7_message); +#endif + if (setup_dahdi(2) != 0) { ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n"); + ast_mutex_unlock(&ss_thread_lock); return 1; } + ast_mutex_unlock(&ss_thread_lock); + ast_mutex_unlock(&restart_lock); return 0; } @@ -12822,91 +13034,6 @@ static int action_dahdishowchannels(struct mansession *s, const struct message * return 0; } -static int __unload_module(void) -{ - int x; - struct dahdi_pvt *p, *pl; -#if defined(HAVE_PRI) || defined(HAVE_SS7) - int i; -#endif - -#if defined(HAVE_PRI) - for (i = 0; i < NUM_SPANS; i++) { - if (pris[i].master != AST_PTHREADT_NULL) - pthread_cancel(pris[i].master); - } - ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli)); - ast_unregister_application(dahdi_send_keypad_facility_app); -#endif - - ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry)); - ast_manager_unregister( "DAHDIDialOffhook" ); - ast_manager_unregister( "DAHDIHangup" ); - ast_manager_unregister( "DAHDITransfer" ); - ast_manager_unregister( "DAHDIDNDoff" ); - ast_manager_unregister( "DAHDIDNDon" ); - ast_manager_unregister("DAHDIShowChannels"); - ast_manager_unregister("DAHDIRestart"); - ast_channel_unregister(&dahdi_tech); - ast_mutex_lock(&iflock); - /* Hangup all interfaces if they have an owner */ - p = iflist; - while (p) { - if (p->owner) - ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); - p = p->next; - } - ast_mutex_unlock(&iflock); - ast_mutex_lock(&monlock); - if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { - pthread_cancel(monitor_thread); - pthread_kill(monitor_thread, SIGURG); - pthread_join(monitor_thread, NULL); - } - monitor_thread = AST_PTHREADT_STOP; - ast_mutex_unlock(&monlock); - - ast_mutex_lock(&iflock); - /* Destroy all the interfaces and free their memory */ - p = iflist; - while (p) { - /* Free any callerid */ - if (p->cidspill) - ast_free(p->cidspill); - /* Close the DAHDI thingy */ - if (p->subs[SUB_REAL].dfd > -1) - dahdi_close(p->subs[SUB_REAL].dfd); - pl = p; - p = p->next; - x = pl->channel; - /* Free associated memory */ - if (pl) - destroy_dahdi_pvt(&pl); - ast_verb(3, "Unregistered channel %d\n", x); - } - iflist = NULL; - ifcount = 0; - ast_mutex_unlock(&iflock); - -#if defined(HAVE_PRI) - for (i = 0; i < NUM_SPANS; i++) { - if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) - pthread_join(pris[i].master, NULL); - dahdi_close(pris[i].fds[i]); - } -#endif /* HAVE_PRI */ - -#if defined(HAVE_SS7) - for (i = 0; i < NUM_SPANS; i++) { - if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) - pthread_join(linksets[i].master, NULL); - dahdi_close(linksets[i].fds[i]); - } -#endif /* HAVE_SS7 */ - - return 0; -} - #ifdef HAVE_SS7 static int linkset_addsigchan(int sigchan) { @@ -13359,6 +13486,104 @@ static struct ast_cli_entry dahdi_ss7_cli[] = { }; #endif /* HAVE_SS7 */ +static int __unload_module(void) +{ + int x; + struct dahdi_pvt *p, *pl; +#if defined(HAVE_PRI) || defined(HAVE_SS7) + int i, j; +#endif + +#ifdef HAVE_PRI + for (i = 0; i < NUM_SPANS; i++) { + if (pris[i].master != AST_PTHREADT_NULL) + pthread_cancel(pris[i].master); + } + ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli)); + ast_unregister_application(dahdi_send_keypad_facility_app); +#endif +#if defined(HAVE_SS7) + for (i = 0; i < NUM_SPANS; i++) { + if (linksets[i].master != AST_PTHREADT_NULL) + pthread_cancel(linksets[i].master); + } + ast_cli_unregister_multiple(dahdi_ss7_cli, sizeof(dahdi_ss7_cli) / sizeof(struct ast_cli_entry)); +#endif + + ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry)); + ast_manager_unregister( "DAHDIDialOffhook" ); + ast_manager_unregister( "DAHDIHangup" ); + ast_manager_unregister( "DAHDITransfer" ); + ast_manager_unregister( "DAHDIDNDoff" ); + ast_manager_unregister( "DAHDIDNDon" ); + ast_manager_unregister("DAHDIShowChannels"); + ast_manager_unregister("DAHDIRestart"); + ast_channel_unregister(&dahdi_tech); + ast_mutex_lock(&iflock); + /* Hangup all interfaces if they have an owner */ + p = iflist; + while (p) { + if (p->owner) + ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); + p = p->next; + } + ast_mutex_unlock(&iflock); + ast_mutex_lock(&monlock); + if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) { + pthread_cancel(monitor_thread); + pthread_kill(monitor_thread, SIGURG); + pthread_join(monitor_thread, NULL); + } + monitor_thread = AST_PTHREADT_STOP; + ast_mutex_unlock(&monlock); + + ast_mutex_lock(&iflock); + /* Destroy all the interfaces and free their memory */ + p = iflist; + while (p) { + /* Free any callerid */ + if (p->cidspill) + ast_free(p->cidspill); + /* Close the DAHDI thingy */ + if (p->subs[SUB_REAL].dfd > -1) + dahdi_close(p->subs[SUB_REAL].dfd); + pl = p; + p = p->next; + x = pl->channel; + /* Free associated memory */ + if (pl) + destroy_dahdi_pvt(&pl); + ast_verb(3, "Unregistered channel %d\n", x); + } + iflist = NULL; + ifcount = 0; + ast_mutex_unlock(&iflock); + +#if defined(HAVE_PRI) + for (i = 0; i < NUM_SPANS; i++) { + if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) + pthread_join(pris[i].master, NULL); + for (j = 0; j < NUM_DCHANS; j++) { + dahdi_close(pris[i].fds[j]); + } + } +#endif + +#if defined(HAVE_SS7) + for (i = 0; i < NUM_SPANS; i++) { + if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) + pthread_join(linksets[i].master, NULL); + for (j = 0; j < NUM_DCHANS; j++) { + dahdi_close(linksets[i].fds[j]); + } + } +#endif + + ast_cond_destroy(&mwi_thread_complete); + ast_cond_destroy(&ss_thread_complete); + return 0; +} + static int unload_module(void) { #if defined(HAVE_PRI) || defined(HAVE_SS7) @@ -13803,7 +14028,7 @@ static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct } else { mwisend_rpas = 0; } - } else if (!reload){ + } else if (reload != 1) { if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) { int orig_radio = confp->chan.radio; int orig_outsigmod = confp->chan.outsigmod; @@ -14389,7 +14614,7 @@ static int setup_dahdi(int reload) /* It's a little silly to lock it, but we mind as well just to be sure */ ast_mutex_lock(&iflock); #ifdef HAVE_PRI - if (!reload) { + if (reload != 1) { /* Process trunkgroups first */ v = ast_variable_browse(cfg, "trunkgroups"); while (v) { @@ -14519,7 +14744,7 @@ static int setup_dahdi(int reload) ast_mutex_unlock(&iflock); #ifdef HAVE_PRI - if (!reload) { + if (reload != 1) { int x; for (x = 0; x < NUM_SPANS; x++) { if (pris[x].pvts[0]) { @@ -14533,7 +14758,7 @@ static int setup_dahdi(int reload) } #endif #ifdef HAVE_SS7 - if (!reload) { + if (reload != 1) { int x; for (x = 0; x < NUM_SPANS; x++) { if (linksets[x].ss7) { @@ -14612,6 +14837,9 @@ 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; } |