diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index eca3ba7b3f6aa1c6720fc27e167d0971ccfc00be..a477c97fe7aa9a7a0baffe8a003014bc1f30b010 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -1412,6 +1412,8 @@ static int iax2_getpeername(struct sockaddr_in sin, char *host, int len)
 	return res;
 }
 
+/*!\note Assumes the lock on the pvt is already held, when
+ * iax2_destroy_helper() is called. */
 static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
 {
 	/* Decrement AUTHREQ count if needed */
@@ -1430,8 +1432,8 @@ static void iax2_destroy_helper(struct chan_iax2_pvt *pvt)
 		ast_clear_flag(pvt, IAX_MAXAUTHREQ);
 	}
 	/* No more pings or lagrq's */
-	AST_SCHED_DEL(sched, pvt->pingid);
-	AST_SCHED_DEL(sched, pvt->lagid);
+	AST_SCHED_DEL_SPINLOCK(sched, pvt->pingid, &iaxsl[pvt->callno]);
+	AST_SCHED_DEL_SPINLOCK(sched, pvt->lagid, &iaxsl[pvt->callno]);
 	AST_SCHED_DEL(sched, pvt->autoid);
 	AST_SCHED_DEL(sched, pvt->authid);
 	AST_SCHED_DEL(sched, pvt->initid);
@@ -1450,7 +1452,9 @@ static void pvt_destructor(void *obj)
 	struct chan_iax2_pvt *pvt = obj;
 	struct iax_frame *cur = NULL;
 
+	ast_mutex_lock(&iaxsl[pvt->callno]);
 	iax2_destroy_helper(pvt);
+	ast_mutex_unlock(&iaxsl[pvt->callno]);
 
 	/* Already gone */
 	ast_set_flag(pvt, IAX_ALREADYGONE);	
@@ -2309,6 +2313,8 @@ static void iax2_destroy(int callno)
 
 retry:
 	pvt = iaxs[callno];
+	iax2_destroy_helper(pvt);
+
 	lastused[callno] = ast_tvnow();
 	
 	owner = pvt ? pvt->owner : NULL;
diff --git a/include/asterisk/sched.h b/include/asterisk/sched.h
index 993ba6b7ebfd5acda54796ba45279f39f3da3a47..92a5d76a49f84cc688493cf508e5cefddf17b97f 100644
--- a/include/asterisk/sched.h
+++ b/include/asterisk/sched.h
@@ -72,6 +72,22 @@ extern "C" {
 		id = -1; \
 	} while (0);
 
+#define AST_SCHED_DEL_SPINLOCK(sched, id, lock) \
+	({ \
+		int _count = 0; \
+		int _sched_res = -1; \
+		while (id > -1 && (_sched_res = ast_sched_del(sched, id)) && ++_count < 10) { \
+			ast_mutex_unlock(lock); \
+			usleep(1); \
+			ast_mutex_lock(lock); \
+		} \
+		if (_count == 10 && option_debug > 2) { \
+			ast_log(LOG_DEBUG, "Unable to cancel schedule ID %d.\n", id); \
+		} \
+		id = -1; \
+		(_sched_res); \
+	})
+
 #define AST_SCHED_REPLACE_VARIABLE(id, sched, when, callback, data, variable) \
 	do { \
 		int _count = 0; \