summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--channels/chan_dahdi.c542
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;
}