/*! \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);
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;
}
} 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
}
} 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
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;
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;
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;
}
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";
p->pri = NULL;
}
#endif
- restart_monitor();
+ if (num_restart_pending == 0)
+ restart_monitor();
}
p->callwaitingrepeat = 0;
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) {
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);
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';
/* Since we send release complete here, we won't get one */
p->call = NULL;
}
- return NULL;
+ goto quit;
break;
#endif
case SIG_FEATD:
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:
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);
/* 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);
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';
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) {
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);
/* 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)) {
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);
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:
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;
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,
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 */
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")) {
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);
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))) {
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
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)
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);
ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
callerid_free(cs);
ast_hangup(chan);
- return NULL;
+ goto quit;
}
break;
}
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 ||
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);
ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
callerid_free(cs);
ast_hangup(chan);
- return NULL;
+ goto quit;
}
break;
}
"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) {
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);
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 */
ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
callerid_free(cs);
ast_hangup(chan);
- return NULL;
+ goto quit;
}
break;
}
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);
ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
callerid_free(cs);
ast_hangup(chan);
- return NULL;
+ goto quit;
}
break;
}
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);
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;
}
{
struct mwi_thread_data *mtd = data;
struct callerid_state *cs;
- pthread_attr_t attr;
pthread_t threadid;
int samples = 0;
char *name, *number;
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)
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;
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;
}
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;
}
}
ast_debug(1, "Monitor starting...\n");
#endif
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+
for (;;) {
/* Lock the interface list */
ast_mutex_lock(&iflock);
/* 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))
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;
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);
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);
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 */
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, '@');
}
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) {
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;
}
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)
{
};
#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)
} 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;
/* 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) {
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]) {
}
#endif
#ifdef HAVE_SS7
- if (!reload) {
+ if (reload != 1) {
int x;
for (x = 0; x < NUM_SPANS; x++) {
if (linksets[x].ss7) {
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;
}