diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index c1931e9dcc120b374cc9903839937d7981bbdb04..9c70f189bb189017deff354f66743f599fd89820 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;
 }