Merged revisions 138119,138151,138238 via svnmerge from
authorJeff Peeler <jpeeler@digium.com>
Fri, 15 Aug 2008 23:46:09 +0000 (23:46 +0000)
committerJeff Peeler <jpeeler@digium.com>
Fri, 15 Aug 2008 23:46:09 +0000 (23:46 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
r138119 | jpeeler | 2008-08-15 14:21:51 -0500 (Fri, 15 Aug 2008) | 4 lines

Fixes the dahdi restart functionality. Dahdi restart allows one to restart all DAHDI channels, even if they are currently in use. This is different from unloading and then loading the module since unloading requires the use count to be zero. Reloading the module is different in that the signalling is not changed from what it was originally configured. Also, this fixes not closing all the file descriptors for D-channels upon module unload (which would prevent loading the module afterwards).

(closes issue #11017)

........
r138151 | jpeeler | 2008-08-15 14:41:29 -0500 (Fri, 15 Aug 2008) | 1 line

declared static mutexes using AST_MUTEX_DEFINE_STATIC macro
........
r138238 | jpeeler | 2008-08-15 16:28:26 -0500 (Fri, 15 Aug 2008) | 1 line

initialize condition variable ss_thread_complete using ast_cond_init
........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@138311 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c

index c1931e9..9c70f18 100644 (file)
@@ -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;
 }