From e2630fcd516b8f794bf342d9fd267b0c905e79ce Mon Sep 17 00:00:00 2001
From: Joshua Colp <jcolp@digium.com>
Date: Wed, 18 Dec 2013 19:28:05 +0000
Subject: [PATCH] channels: Return allocated channels locked.

This change makes ast_channel_alloc return allocated channels
locked. By doing so no other thread can acquire, lock, and manipulate
the channel before it is completely set up.

(closes issue AST-1256)

Review: https://reviewboard.asterisk.org/r/3067/
........

Merged revisions 404204 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404210 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 addons/chan_mobile.c               |  2 +
 addons/chan_ooh323.c               |  1 -
 apps/app_meetme.c                  |  2 +
 apps/app_voicemail.c               |  2 +
 apps/confbridge/conf_chan_record.c |  2 +
 channels/chan_alsa.c               |  2 +
 channels/chan_console.c            |  2 +
 channels/chan_dahdi.c              |  2 +
 channels/chan_gtalk.c              |  2 +
 channels/chan_h323.c               |  1 +
 channels/chan_iax2.c               |  3 ++
 channels/chan_jingle.c             |  2 +
 channels/chan_mgcp.c               |  2 +
 channels/chan_misdn.c              |  4 ++
 channels/chan_motif.c              |  2 +
 channels/chan_multicast_rtp.c      |  2 +
 channels/chan_nbs.c                |  1 +
 channels/chan_oss.c                |  1 +
 channels/chan_phone.c              |  1 +
 channels/chan_pjsip.c              | 29 +++++++-------
 channels/chan_sip.c                |  2 +-
 channels/chan_skinny.c             |  4 ++
 channels/chan_unistim.c            |  2 +
 channels/chan_vpb.cc               |  2 +
 include/asterisk/channel.h         |  5 ++-
 main/channel.c                     |  6 +++
 main/core_unreal.c                 | 55 ++++++++++++++++----------
 main/message.c                     |  4 +-
 main/pbx.c                         |  2 +
 res/parking/parking_tests.c        |  2 +
 res/res_calendar.c                 |  2 +
 res/res_stasis_snoop.c             | 62 ++++++++++++++++--------------
 tests/test_app.c                   | 12 ++++--
 tests/test_cdr.c                   | 18 +++++++++
 tests/test_cel.c                   |  5 +++
 tests/test_stasis_channels.c       |  6 +++
 tests/test_substitution.c          |  1 +
 tests/test_voicemail_api.c         |  2 +
 38 files changed, 187 insertions(+), 70 deletions(-)

diff --git a/addons/chan_mobile.c b/addons/chan_mobile.c
index 2cf7c7dbdd..a76d778c4c 100644
--- a/addons/chan_mobile.c
+++ b/addons/chan_mobile.c
@@ -879,6 +879,8 @@ static struct ast_channel *mbl_new(int state, struct mbl_pvt *pvt, char *cid_num
 		ast_channel_set_fd(chn, 0, pvt->sco_socket);
 	}
 
+	ast_channel_unlock(chn);
+
 	return chn;
 
 e_return:
diff --git a/addons/chan_ooh323.c b/addons/chan_ooh323.c
index ff0a030adf..d89e00c2e9 100644
--- a/addons/chan_ooh323.c
+++ b/addons/chan_ooh323.c
@@ -395,7 +395,6 @@ static struct ast_channel *ooh323_new(struct ooh323_pvt *i, int state,
 	ast_mutex_lock(&i->lock);
 
 	if (ch) {
-		ast_channel_lock(ch);
 		ast_channel_tech_set(ch, &ooh323_tech);
 
 		if (cap)
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index ffd55e70df..feea3b6c59 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -8140,6 +8140,8 @@ AST_TEST_DEFINE(test_meetme_data_provider)
 		return AST_TEST_FAIL;
 	}
 
+	ast_channel_unlock(chan);
+
 	cnf = build_conf("9898", "", "1234", 1, 1, 1, chan, test);
 	if (!cnf) {
 		ast_test_status_update(test, "Build of test conference 9898 failed\n");
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index dbcd283559..4dffbbef07 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -13744,6 +13744,8 @@ AST_TEST_DEFINE(test_voicemail_vmsayname)
 	ast_format_set(ast_channel_rawreadformat(test_channel1), AST_FORMAT_GSM, 0);
 	ast_channel_tech_set(test_channel1, &fake_tech);
 
+	ast_channel_unlock(test_channel1);
+
 	ast_test_status_update(test, "Test playing of extension when greeting is not available...\n");
 	snprintf(dir, sizeof(dir), "%s@%s", TEST_EXTENSION, TEST_CONTEXT); /* not a dir, don't get confused */
 	if (!(res = vmsayname_exec(test_channel1, dir))) {
diff --git a/apps/confbridge/conf_chan_record.c b/apps/confbridge/conf_chan_record.c
index 7080d118c9..78d1f272c3 100644
--- a/apps/confbridge/conf_chan_record.c
+++ b/apps/confbridge/conf_chan_record.c
@@ -66,6 +66,7 @@ static struct ast_channel *rec_request(const char *type, struct ast_format_cap *
 		return NULL;
 	}
 	if (ast_channel_add_bridge_role(chan, "recorder")) {
+		ast_channel_unlock(chan);
 		ast_channel_release(chan);
 		return NULL;
 	}
@@ -76,6 +77,7 @@ static struct ast_channel *rec_request(const char *type, struct ast_format_cap *
 	ast_format_copy(ast_channel_rawwriteformat(chan), &format);
 	ast_format_copy(ast_channel_readformat(chan), &format);
 	ast_format_copy(ast_channel_rawreadformat(chan), &format);
+	ast_channel_unlock(chan);
 	return chan;
 }
 
diff --git a/channels/chan_alsa.c b/channels/chan_alsa.c
index 60bbacbb86..1d2d5f9f28 100644
--- a/channels/chan_alsa.c
+++ b/channels/chan_alsa.c
@@ -602,6 +602,8 @@ static struct ast_channel *alsa_new(struct chan_alsa_pvt *p, int state, const ch
 
 	ast_channel_stage_snapshot_done(tmp);
 
+	ast_channel_unlock(tmp);
+
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(tmp)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
diff --git a/channels/chan_console.c b/channels/chan_console.c
index 922c53b426..e37b565c50 100644
--- a/channels/chan_console.c
+++ b/channels/chan_console.c
@@ -445,6 +445,8 @@ static struct ast_channel *console_new(struct console_pvt *pvt, const char *ext,
 
 	ast_channel_stage_snapshot_done(chan);
 
+	ast_channel_unlock(chan);
+
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(chan)) {
 			ast_channel_hangupcause_set(chan, AST_CAUSE_SWITCH_CONGESTION);
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index 2eba958a8b..636d8863f0 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -9097,6 +9097,8 @@ static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpb
 
 	ast_channel_stage_snapshot_done(tmp);
 
+	ast_channel_unlock(tmp);
+
 	ast_module_ref(ast_module_info->self);
 
 	dahdi_ami_channel_event(i, tmp);
diff --git a/channels/chan_gtalk.c b/channels/chan_gtalk.c
index d6a0949419..bec4401034 100644
--- a/channels/chan_gtalk.c
+++ b/channels/chan_gtalk.c
@@ -1227,6 +1227,8 @@ static struct ast_channel *gtalk_new(struct gtalk *client, struct gtalk_pvt *i,
 
 	ast_channel_stage_snapshot_done(tmp);
 
+	ast_channel_unlock(tmp);
+
 	if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
 		ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
 		ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
diff --git a/channels/chan_h323.c b/channels/chan_h323.c
index 22dba3c183..1c9bb2ad07 100644
--- a/channels/chan_h323.c
+++ b/channels/chan_h323.c
@@ -1139,6 +1139,7 @@ static struct ast_channel *__oh323_new(struct oh323_pvt *pvt, int state, const c
 		}
 		if (pvt->cd.transfer_capability >= 0)
 			ast_channel_transfercapability_set(ch, pvt->cd.transfer_capability);
+		ast_channel_unlock(ch);
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(ch)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(ch));
diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c
index 84a72c850c..b89ae824be 100644
--- a/channels/chan_iax2.c
+++ b/channels/chan_iax2.c
@@ -5694,6 +5694,7 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
 		if (tmp) {
 			/* unlock and relock iaxsl[callno] to preserve locking order */
 			ast_mutex_unlock(&iaxsl[callno]);
+			ast_channel_unlock(tmp);
 			tmp = ast_channel_release(tmp);
 			ast_mutex_lock(&iaxsl[callno]);
 		}
@@ -5804,6 +5805,8 @@ static struct ast_channel *ast_iax2_new(int callno, int state, iax2_format capab
 
 	ast_channel_stage_snapshot_done(tmp);
 
+	ast_channel_unlock(tmp);
+
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(tmp)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
diff --git a/channels/chan_jingle.c b/channels/chan_jingle.c
index 56c15b193f..c1c5026871 100644
--- a/channels/chan_jingle.c
+++ b/channels/chan_jingle.c
@@ -942,6 +942,8 @@ static struct ast_channel *jingle_new(struct jingle *client, struct jingle_pvt *
 
 	ast_channel_stage_snapshot_done(tmp);
 
+	ast_channel_unlock(tmp);
+
 	if (state != AST_STATE_DOWN && ast_pbx_start(tmp)) {
 		ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
 		ast_channel_hangupcause_set(tmp, AST_CAUSE_SWITCH_CONGESTION);
diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c
index 84fb3b2256..a6f75e6c32 100644
--- a/channels/chan_mgcp.c
+++ b/channels/chan_mgcp.c
@@ -1571,6 +1571,8 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state, cons
 
 		ast_channel_stage_snapshot_done(tmp);
 
+		ast_channel_unlock(tmp);
+
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
diff --git a/channels/chan_misdn.c b/channels/chan_misdn.c
index 38197c6381..6dd9adf6ac 100644
--- a/channels/chan_misdn.c
+++ b/channels/chan_misdn.c
@@ -8226,6 +8226,8 @@ static struct ast_channel *misdn_new(struct chan_list *chlist, int state,  char
 		ast_channel_rings_set(tmp, (state == AST_STATE_RING) ? 1 : 0);
 
 		ast_jb_configure(tmp, misdn_get_global_jbconf());
+
+		ast_channel_unlock(tmp);
 	} else {
 		chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
 	}
@@ -8949,6 +8951,8 @@ static void misdn_cc_pbx_notify(long record_id, const struct misdn_cc_notify *no
 	ast_free(ast_channel_dialed(chan)->number.str);
 	ast_channel_dialed(chan)->number.str = ast_strdup(notify->exten);
 
+	ast_channel_unlock(chan);
+
 	if (ast_pbx_start(chan)) {
 		ast_log(LOG_WARNING, "Unable to start pbx channel %s!\n", ast_channel_name(chan));
 		ast_channel_release(chan);
diff --git a/channels/chan_motif.c b/channels/chan_motif.c
index 1e7ee3cce6..2c2b270077 100644
--- a/channels/chan_motif.c
+++ b/channels/chan_motif.c
@@ -853,6 +853,8 @@ static struct ast_channel *jingle_new(struct jingle_endpoint *endpoint, struct j
 
 	ast_channel_stage_snapshot_done(chan);
 
+	ast_channel_unlock(chan);
+
 	return chan;
 }
 
diff --git a/channels/chan_multicast_rtp.c b/channels/chan_multicast_rtp.c
index 1b9e4d31f2..e3d8f9b130 100644
--- a/channels/chan_multicast_rtp.c
+++ b/channels/chan_multicast_rtp.c
@@ -166,6 +166,8 @@ static struct ast_channel *multicast_rtp_request(const char *type, struct ast_fo
 
 	ast_channel_tech_pvt_set(chan, instance);
 
+	ast_channel_unlock(chan);
+
 	return chan;
 
 failure:
diff --git a/channels/chan_nbs.c b/channels/chan_nbs.c
index 1d8c59d4e1..7cce241135 100644
--- a/channels/chan_nbs.c
+++ b/channels/chan_nbs.c
@@ -239,6 +239,7 @@ static struct ast_channel *nbs_new(struct nbs_pvt *i, int state, const char *lin
 		ast_channel_language_set(tmp, "");
 		i->owner = tmp;
 		i->u = ast_module_user_add(tmp);
+		ast_channel_unlock(tmp);
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
diff --git a/channels/chan_oss.c b/channels/chan_oss.c
index 5ae18f362e..3a52ac9db4 100644
--- a/channels/chan_oss.c
+++ b/channels/chan_oss.c
@@ -829,6 +829,7 @@ static struct ast_channel *oss_new(struct chan_oss_pvt *o, char *ext, char *ctx,
 	o->owner = c;
 	ast_module_ref(ast_module_info->self);
 	ast_jb_configure(c, &global_jbconf);
+	ast_channel_unlock(c);
 	if (state != AST_STATE_DOWN) {
 		if (ast_pbx_start(c)) {
 			ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(c));
diff --git a/channels/chan_phone.c b/channels/chan_phone.c
index c1a24b8b1b..ba14a435e2 100644
--- a/channels/chan_phone.c
+++ b/channels/chan_phone.c
@@ -901,6 +901,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *cntx,
 
 		i->owner = tmp;
 		ast_module_ref(ast_module_info->self);
+		ast_channel_unlock(tmp);
 		if (state != AST_STATE_DOWN) {
 			if (state == AST_STATE_RING) {
 				ioctl(ast_channel_fd(tmp, 0), PHONE_RINGBACK);
diff --git a/channels/chan_pjsip.c b/channels/chan_pjsip.c
index 21a79f0edb..cd209d243a 100644
--- a/channels/chan_pjsip.c
+++ b/channels/chan_pjsip.c
@@ -359,24 +359,14 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s
 	ast_channel_tech_set(chan, &chan_pjsip_tech);
 
 	if (!(channel = ast_sip_channel_pvt_alloc(pvt, session))) {
+		ast_channel_unlock(chan);
 		ast_hangup(chan);
 		return NULL;
 	}
 
 	ast_channel_stage_snapshot(chan);
 
-	/* If res_pjsip_session is ever updated to create/destroy ast_sip_session_media
-	 * during a call such as if multiple same-type stream support is introduced,
-	 * these will need to be recaptured as well */
-	pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
-	pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
 	ast_channel_tech_pvt_set(chan, channel);
-	if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) {
-		ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(chan));
-	}
-	if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) {
-		ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ast_channel_uniqueid(chan));
-	}
 
 	if (ast_format_cap_is_empty(session->req_caps) || !ast_format_cap_has_joint(session->req_caps, session->endpoint->media.codecs)) {
 		ast_format_cap_copy(ast_channel_nativeformats(chan), session->endpoint->media.codecs);
@@ -418,9 +408,22 @@ static struct ast_channel *chan_pjsip_new(struct ast_sip_session *session, int s
 		ast_channel_zone_set(chan, zone);
 	}
 
-	ast_endpoint_add_channel(session->endpoint->persistent, chan);
-
 	ast_channel_stage_snapshot_done(chan);
+	ast_channel_unlock(chan);
+
+	/* If res_pjsip_session is ever updated to create/destroy ast_sip_session_media
+	 * during a call such as if multiple same-type stream support is introduced,
+	 * these will need to be recaptured as well */
+	pvt->media[SIP_MEDIA_AUDIO] = ao2_find(session->media, "audio", OBJ_KEY);
+	pvt->media[SIP_MEDIA_VIDEO] = ao2_find(session->media, "video", OBJ_KEY);
+	if (pvt->media[SIP_MEDIA_AUDIO] && pvt->media[SIP_MEDIA_AUDIO]->rtp) {
+		ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_AUDIO]->rtp, ast_channel_uniqueid(chan));
+	}
+	if (pvt->media[SIP_MEDIA_VIDEO] && pvt->media[SIP_MEDIA_VIDEO]->rtp) {
+		ast_rtp_instance_set_channel_id(pvt->media[SIP_MEDIA_VIDEO]->rtp, ast_channel_uniqueid(chan));
+	}
+
+	ast_endpoint_add_channel(session->endpoint->persistent, chan);
 
 	return chan;
 }
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index a7649127e7..0fde84e2df 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -8100,6 +8100,7 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 
 	if (i->relatedpeer && i->relatedpeer->endpoint) {
 		if (ast_endpoint_add_channel(i->relatedpeer->endpoint, tmp)) {
+			ast_channel_unlock(tmp);
 			ast_channel_unref(tmp);
 			sip_pvt_lock(i);
 			return NULL;
@@ -8113,7 +8114,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
 		ast_channel_callid_set(tmp, callid);
 	}
 
-	ast_channel_lock(tmp);
 	sip_pvt_lock(i);
 	ast_channel_cc_params_init(tmp, i->cc_params);
 	ast_channel_caller(tmp)->id.tag = ast_strdup(i->cid_tag);
diff --git a/channels/chan_skinny.c b/channels/chan_skinny.c
index a65862ff3c..bb270d6a9d 100644
--- a/channels/chan_skinny.c
+++ b/channels/chan_skinny.c
@@ -5393,6 +5393,8 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
 		sub = ast_calloc(1, sizeof(*sub));
 		if (!sub) {
 			ast_log(LOG_WARNING, "Unable to allocate Skinny subchannel\n");
+			ast_channel_unlock(tmp);
+			ast_channel_unref(tmp);
 			return NULL;
 		} else {
 			ast_mutex_init(&sub->lock);
@@ -5500,6 +5502,8 @@ static struct ast_channel *skinny_new(struct skinny_line *l, struct skinny_subli
 
 		ast_channel_stage_snapshot_done(tmp);
 
+		ast_channel_unlock(tmp);
+
 		if (state != AST_STATE_DOWN) {
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", ast_channel_name(tmp));
diff --git a/channels/chan_unistim.c b/channels/chan_unistim.c
index 547cd7c2f6..21bbbc1e82 100644
--- a/channels/chan_unistim.c
+++ b/channels/chan_unistim.c
@@ -5628,6 +5628,8 @@ static struct ast_channel *unistim_new(struct unistim_subchannel *sub, int state
 
 	ast_channel_stage_snapshot_done(tmp);
 
+	ast_channel_unlock(tmp);
+
 	if (state != AST_STATE_DOWN) {
 		if (unistimdebug) {
 			ast_verb(0, "Starting pbx in unistim_new\n");
diff --git a/channels/chan_vpb.cc b/channels/chan_vpb.cc
index 12f27249b1..39d78cc332 100644
--- a/channels/chan_vpb.cc
+++ b/channels/chan_vpb.cc
@@ -2472,6 +2472,8 @@ static struct ast_channel *vpb_new(struct vpb_pvt *me, enum ast_channel_state st
 		if (!ast_strlen_zero(me->language))
 			ast_channel_language_set(tmp, me->language);
 
+		ast_channel_unlock(tmp);
+
 		me->owner = tmp;
 
 		me->bridge = NULL;
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 03d9aef68a..51530a82bf 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -791,7 +791,8 @@ typedef int(*ast_timing_func_t)(const void *data);
  * active channels in the system.  The hash key is based on the channel name.  Because
  * of this, if you want to change the name, you _must_ use ast_change_name(), not change
  * the name field directly.  When ast_channel_alloc() returns a channel pointer, you now
- * hold a reference to that channel.  In most cases this reference is given to ast_pbx_run().
+ * hold both a reference to that channel and a lock on the channel. Once the channel has
+ * been set up the lock can be released. In most cases the reference is given to ast_pbx_run().
  *
  * \par Channel Locking
  * There is a lock associated with every ast_channel.  It is allocated internally via astobj2.
@@ -1122,6 +1123,7 @@ struct ast_datastore *ast_channel_datastore_find(struct ast_channel *chan, const
  * \note Absolutely _NO_ channel locks should be held before calling this function.
  * \note By default, new channels are set to the "s" extension
  *       and "default" context.
+ * \note Since 12.0.0 this function returns with the newly created channel locked.
  */
 struct ast_channel * attribute_malloc __attribute__((format(printf, 13, 14)))
 	__ast_channel_alloc(int needqueue, int state, const char *cid_num,
@@ -1140,6 +1142,7 @@ struct ast_channel * attribute_malloc __attribute__((format(printf, 13, 14)))
  * \note Absolutely _NO_ channel locks should be held before calling this function.
  * \note By default, new channels are set to the "s" extension
  *       and "default" context.
+ * \note Since 12.0.0 this function returns with the newly created channel locked.
  */
 #define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, linkedid, amaflag, ...) \
 	__ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, linkedid, amaflag, \
diff --git a/main/channel.c b/main/channel.c
index d669baf85e..418e6a7727 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1017,6 +1017,12 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
 	ast_channel_internal_finalize(tmp);
 
 	ast_atomic_fetchadd_int(&chancount, +1);
+
+	/* You might scream "locking inversion" at seeing this but it is actually perfectly fine.
+	 * Since the channel was just created nothing can know about it yet or even acquire it.
+	 */
+	ast_channel_lock(tmp);
+
 	ao2_link(channels, tmp);
 
 	/*
diff --git a/main/core_unreal.c b/main/core_unreal.c
index 7e457f4849..7ab7da7650 100644
--- a/main/core_unreal.c
+++ b/main/core_unreal.c
@@ -906,57 +906,72 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
 	 */
 	if (!(owner = ast_channel_alloc(1, semi1_state, NULL, NULL, NULL,
 			exten, context, linkedid, 0,
-			"%s/%s-%08x;1", tech->type, p->name, generated_seqno))
-		|| !(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
-			exten, context, ast_channel_linkedid(owner), 0,
-			"%s/%s-%08x;2", tech->type, p->name, generated_seqno))) {
-		if (owner) {
-			owner = ast_channel_release(owner);
-		}
-		ast_log(LOG_WARNING, "Unable to allocate channel structure(s)\n");
+			"%s/%s-%08x;1", tech->type, p->name, generated_seqno))) {
+		ast_log(LOG_WARNING, "Unable to allocate owner channel structure\n");
 		return NULL;
 	}
 
 	if (callid) {
 		ast_channel_callid_set(owner, callid);
-		ast_channel_callid_set(chan, callid);
 	}
 
 	ast_channel_tech_set(owner, tech);
-	ast_channel_tech_set(chan, tech);
+	ao2_ref(p, +1);
 	ast_channel_tech_pvt_set(owner, p);
-	ast_channel_tech_pvt_set(chan, p);
 
 	ast_format_cap_copy(ast_channel_nativeformats(owner), p->reqcap);
-	ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);
 
 	/* Determine our read/write format and set it on each channel */
 	ast_best_codec(p->reqcap, &fmt);
 	ast_format_copy(ast_channel_writeformat(owner), &fmt);
-	ast_format_copy(ast_channel_writeformat(chan), &fmt);
 	ast_format_copy(ast_channel_rawwriteformat(owner), &fmt);
-	ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
 	ast_format_copy(ast_channel_readformat(owner), &fmt);
-	ast_format_copy(ast_channel_readformat(chan), &fmt);
 	ast_format_copy(ast_channel_rawreadformat(owner), &fmt);
-	ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
 
 	ast_set_flag(ast_channel_flags(owner), AST_FLAG_DISABLE_DEVSTATE_CACHE);
-	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
 
 	ast_jb_configure(owner, &p->jb_conf);
 
 	if (ast_channel_cc_params_init(owner, requestor
 		? ast_channel_get_cc_config_params((struct ast_channel *) requestor) : NULL)) {
+		ao2_ref(p, -1);
+		ast_channel_unlock(owner);
 		ast_channel_release(owner);
-		ast_channel_release(chan);
 		return NULL;
 	}
 
-	/* Give the private a ref for each channel. */
-	ao2_ref(p, +2);
 	p->owner = owner;
+	ast_channel_unlock(owner);
+
+	if (!(chan = ast_channel_alloc(1, semi2_state, NULL, NULL, NULL,
+			exten, context, ast_channel_linkedid(owner), 0,
+			"%s/%s-%08x;2", tech->type, p->name, generated_seqno))) {
+		ast_log(LOG_WARNING, "Unable to allocate chan channel structure\n");
+		ao2_ref(p, -1);
+		ast_channel_release(owner);
+		return NULL;
+	}
+
+	if (callid) {
+		ast_channel_callid_set(chan, callid);
+	}
+
+	ast_channel_tech_set(chan, tech);
+	ao2_ref(p, +1);
+	ast_channel_tech_pvt_set(chan, p);
+
+	ast_format_cap_copy(ast_channel_nativeformats(chan), p->reqcap);
+
+	/* Format was already determined when setting up owner */
+	ast_format_copy(ast_channel_writeformat(chan), &fmt);
+	ast_format_copy(ast_channel_rawwriteformat(chan), &fmt);
+	ast_format_copy(ast_channel_readformat(chan), &fmt);
+	ast_format_copy(ast_channel_rawreadformat(chan), &fmt);
+
+	ast_set_flag(ast_channel_flags(chan), AST_FLAG_DISABLE_DEVSTATE_CACHE);
+
 	p->chan = chan;
+	ast_channel_unlock(chan);
 
 	return owner;
 }
diff --git a/main/message.c b/main/message.c
index ef2c97f1fa..7690e4a886 100644
--- a/main/message.c
+++ b/main/message.c
@@ -678,9 +678,9 @@ static struct ast_channel *create_msg_q_chan(void)
 		return NULL;
 	}
 
-	ast_channel_unlink(chan);
-
 	ast_channel_tech_set(chan, &msg_chan_tech_hack);
+	ast_channel_unlock(chan);
+	ast_channel_unlink(chan);
 
 	if (!(ds = ast_datastore_alloc(&msg_datastore, NULL))) {
 		ast_hangup(chan);
diff --git a/main/pbx.c b/main/pbx.c
index 6b9bd5ebfd..726677f4aa 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -10365,6 +10365,8 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co
 			snprintf(failed_reason, sizeof(failed_reason), "%d", ast_dial_reason(outgoing->dial, 0));
 			pbx_builtin_setvar_helper(failed, "REASON", failed_reason);
 
+			ast_channel_unlock(failed);
+
 			if (ast_pbx_run(failed)) {
 				ast_log(LOG_ERROR, "Unable to run PBX on '%s'\n", ast_channel_name(failed));
 				ast_hangup(failed);
diff --git a/res/parking/parking_tests.c b/res/parking/parking_tests.c
index e046ca8cf8..f6767769ae 100644
--- a/res/parking/parking_tests.c
+++ b/res/parking/parking_tests.c
@@ -63,6 +63,8 @@ static struct ast_channel *create_alice_channel(void)
 
 	ast_channel_set_caller(alice, &alice_callerid, NULL);
 
+	ast_channel_unlock(alice);
+
 	return alice;
 }
 
diff --git a/res/res_calendar.c b/res/res_calendar.c
index eebd7b480e..c36e5cf0a7 100644
--- a/res/res_calendar.c
+++ b/res/res_calendar.c
@@ -766,6 +766,8 @@ static void *do_notify(void *data)
 	/* clear native formats and set to slinear. write format is signlear so just use that to set it */
 	ast_format_cap_set(ast_channel_nativeformats(chan), ast_channel_writeformat(chan));
 
+	ast_channel_unlock(chan);
+
 	if (!(datastore = ast_datastore_alloc(&event_notification_datastore, NULL))) {
 		ast_log(LOG_ERROR, "Could not allocate datastore, notification not being sent!\n");
 		goto notify_cleanup;
diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c
index 1a40112d1f..65186d14e6 100644
--- a/res/res_stasis_snoop.c
+++ b/res/res_stasis_snoop.c
@@ -274,12 +274,21 @@ static int snoop_setup_audiohook(struct ast_channel *chan, enum ast_audiohook_ty
 	return ast_audiohook_attach(chan, audiohook);
 }
 
+/*! \brief Helper function which gets the format for a Snoop channel based on the channel being snooped on */
+static void snoop_determine_format(struct ast_channel *chan, struct stasis_app_snoop *snoop)
+{
+	SCOPED_CHANNELLOCK(lock, chan);
+	unsigned int rate = MAX(ast_format_rate(ast_channel_rawwriteformat(chan)),
+		ast_format_rate(ast_channel_rawreadformat(chan)));
+
+	ast_format_set(&snoop->spy_format, ast_format_slin_by_rate(rate), 0);
+}
+
 struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
 	enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper,
 	const char *app, const char *app_args)
 {
 	RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup);
-	unsigned int rate;
 	pthread_t thread;
 
 	if (spy == STASIS_SNOOP_DIRECTION_NONE &&
@@ -310,6 +319,9 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
 	}
 	ast_timer_set_rate(snoop->timer, 1000 / SNOOP_INTERVAL);
 
+	/* Determine which signed linear format should be used */
+	snoop_determine_format(chan, snoop);
+
 	/* Allocate a Snoop channel and set up various parameters */
 	snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", "", 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
 		ast_atomic_fetchadd_int((int *)&chan_idx, +1));
@@ -327,39 +339,33 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
 	ast_channel_tech_pvt_set(snoop->chan, snoop);
 	ast_channel_set_fd(snoop->chan, 0, ast_timer_fd(snoop->timer));
 
-	{
-		SCOPED_CHANNELLOCK(lock, chan);
+	/* The format on the Snoop channel will be this signed linear format, and it will never change */
+	ast_format_cap_set(ast_channel_nativeformats(snoop->chan), &snoop->spy_format);
+	ast_format_copy(ast_channel_writeformat(snoop->chan), &snoop->spy_format);
+	ast_format_copy(ast_channel_rawwriteformat(snoop->chan), &snoop->spy_format);
+	ast_format_copy(ast_channel_readformat(snoop->chan), &snoop->spy_format);
+	ast_format_copy(ast_channel_rawreadformat(snoop->chan), &snoop->spy_format);
 
-		/* Determine the "best" signed linear format capable by the channel we are snooping on */
-		rate = MAX(ast_format_rate(ast_channel_rawwriteformat(chan)), ast_format_rate(ast_channel_rawreadformat(chan)));
-		ast_format_set(&snoop->spy_format, ast_format_slin_by_rate(rate), 0);
+	ast_channel_unlock(snoop->chan);
 
-		/* The format on the Snoop channel will be this signed linear format, and it will never change */
-		ast_format_cap_set(ast_channel_nativeformats(snoop->chan), &snoop->spy_format);
-		ast_format_copy(ast_channel_writeformat(snoop->chan), &snoop->spy_format);
-		ast_format_copy(ast_channel_rawwriteformat(snoop->chan), &snoop->spy_format);
-		ast_format_copy(ast_channel_readformat(snoop->chan), &snoop->spy_format);
-		ast_format_copy(ast_channel_rawreadformat(snoop->chan), &snoop->spy_format);
-
-		if (spy != STASIS_SNOOP_DIRECTION_NONE) {
-			if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) {
-				ast_hangup(snoop->chan);
-				return NULL;
-			}
-
-			snoop->spy_samples = rate / (1000 / SNOOP_INTERVAL);
-			snoop->spy_active = 1;
+	if (spy != STASIS_SNOOP_DIRECTION_NONE) {
+		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_SPY, spy, &snoop->spy_direction, &snoop->spy)) {
+			ast_hangup(snoop->chan);
+			return NULL;
 		}
 
-		/* If whispering is enabled set up the audiohook */
-		if (whisper != STASIS_SNOOP_DIRECTION_NONE) {
-			if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) {
-				ast_hangup(snoop->chan);
-				return NULL;
-			}
+		snoop->spy_samples = ast_format_rate(&snoop->spy_format) / (1000 / SNOOP_INTERVAL);
+		snoop->spy_active = 1;
+	}
 
-			snoop->whisper_active = 1;
+	/* If whispering is enabled set up the audiohook */
+	if (whisper != STASIS_SNOOP_DIRECTION_NONE) {
+		if (snoop_setup_audiohook(chan, AST_AUDIOHOOK_TYPE_WHISPER, whisper, &snoop->whisper_direction, &snoop->whisper)) {
+			ast_hangup(snoop->chan);
+			return NULL;
 		}
+
+		snoop->whisper_active = 1;
 	}
 
 	/* Create the thread which services the Snoop channel */
diff --git a/tests/test_app.c b/tests/test_app.c
index f47b052e52..92da42022d 100644
--- a/tests/test_app.c
+++ b/tests/test_app.c
@@ -175,21 +175,25 @@ AST_TEST_DEFINE(app_group)
 		"'%s', '%s', '%s', '%s'\n", group1_full, group2_full, category1_full, category2_full);
 
 	if (!(test_channel1 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-        NULL, NULL, 0, 0, "TestChannel1"))) {
+		NULL, NULL, 0, 0, "TestChannel1"))) {
 		goto exit_group_test;
 	}
+	ast_channel_unlock(test_channel1);
 	if (!(test_channel2 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-        NULL, NULL, 0, 0, "TestChannel2"))) {
+		NULL, NULL, 0, 0, "TestChannel2"))) {
 		goto exit_group_test;
 	}
+	ast_channel_unlock(test_channel2);
 	if (!(test_channel3 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-        NULL, NULL, 0, 0, "TestChannel3"))) {
+		NULL, NULL, 0, 0, "TestChannel3"))) {
 		goto exit_group_test;
 	}
+	ast_channel_unlock(test_channel3);
 	if (!(test_channel4 = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL,
-        NULL, NULL, 0, 0, "TestChannel4"))) {
+		NULL, NULL, 0, 0, "TestChannel4"))) {
 		goto exit_group_test;
 	}
+	ast_channel_unlock(test_channel4);
 
 	ast_app_group_set_channel(test_channel1, group1_full);
 	ast_app_group_set_channel(test_channel2, group2_full);
diff --git a/tests/test_cdr.c b/tests/test_cdr.c
index 6d1626b368..e70a0641b0 100644
--- a/tests/test_cdr.c
+++ b/tests/test_cdr.c
@@ -238,6 +238,7 @@ static void clear_mock_cdr_backend(void)
 	ast_channel_set_caller((channel_var), (caller_id), NULL); \
 	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
 	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Create a \ref test_cdr_chan_tech for Bob, and set the expected
@@ -247,6 +248,7 @@ static void clear_mock_cdr_backend(void)
 	ast_channel_set_caller((channel_var), (caller_id), NULL); \
 	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
 	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Create a \ref test_cdr_chan_tech for Charlie, and set the expected
@@ -256,6 +258,7 @@ static void clear_mock_cdr_backend(void)
 	ast_channel_set_caller((channel_var), (caller_id), NULL); \
 	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
 	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Create a \ref test_cdr_chan_tech for Charlie, and set the expected
@@ -265,6 +268,7 @@ static void clear_mock_cdr_backend(void)
 	ast_channel_set_caller((channel_var), (caller_id), NULL); \
 	ast_copy_string((expected_record)->uniqueid, ast_channel_uniqueid((channel_var)), sizeof((expected_record)->uniqueid)); \
 	ast_copy_string((expected_record)->linkedid, ast_channel_linkedid((channel_var)), sizeof((expected_record)->linkedid)); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Emulate a channel entering into an application */
@@ -563,6 +567,7 @@ AST_TEST_DEFINE(test_cdr_outbound_bridged_call)
 	ast_test_validate(test, !ast_bridge_impart(bridge, chan_alice, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE));
 
 	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_alice), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_bob);
 	ast_copy_string(bob_expected.linkedid, ast_channel_linkedid(chan_bob), sizeof(bob_expected.linkedid));
 	ast_copy_string(bob_expected.uniqueid, ast_channel_uniqueid(chan_bob), sizeof(bob_expected.uniqueid));
 	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
@@ -1133,6 +1138,7 @@ AST_TEST_DEFINE(test_cdr_dial_unanswered)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", "CDRTestChannel/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1194,6 +1200,7 @@ AST_TEST_DEFINE(test_cdr_dial_busy)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1254,6 +1261,7 @@ AST_TEST_DEFINE(test_cdr_dial_congestion)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1314,6 +1322,7 @@ AST_TEST_DEFINE(test_cdr_dial_unavailable)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1375,6 +1384,7 @@ AST_TEST_DEFINE(test_cdr_dial_caller_cancel)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1476,14 +1486,17 @@ AST_TEST_DEFINE(test_cdr_dial_parallel_failed)
 
 	/* Outbound channels are created */
 	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_bob);
 	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_bob, 0, "AppDial", "(Outgoing Line)");
 
 	chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "300", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Charlie");
+	ast_channel_unlock(chan_charlie);
 	ast_set_flag(ast_channel_flags(chan_charlie), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_charlie, 0, "AppDial", "(Outgoing Line)");
 
 	chan_david = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "400", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/David");
+	ast_channel_unlock(chan_david);
 	ast_set_flag(ast_channel_flags(chan_david), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_david, 0, "AppDial", "(Outgoing Line)");
 
@@ -1589,6 +1602,7 @@ AST_TEST_DEFINE(test_cdr_dial_answer_no_bridge)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	COPY_IDS(chan_callee, &bob_expected_one);
 
@@ -1656,6 +1670,7 @@ AST_TEST_DEFINE(test_cdr_dial_answer_twoparty_bridge_a)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1731,6 +1746,7 @@ AST_TEST_DEFINE(test_cdr_dial_answer_twoparty_bridge_b)
 	EMULATE_APP_DATA(chan_caller, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, "200", NULL, NULL, ast_channel_linkedid(chan_caller), 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_callee);
 	ast_set_flag(ast_channel_flags(chan_callee), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_callee, 0, "AppDial", "(Outgoing Line)");
 
@@ -1889,6 +1905,7 @@ AST_TEST_DEFINE(test_cdr_dial_answer_multiparty)
 	EMULATE_APP_DATA(chan_alice, 1, "Dial", CHANNEL_TECH_NAME "/Bob");
 
 	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob");
+	ast_channel_unlock(chan_bob);
 	ast_set_flag(ast_channel_flags(chan_bob), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_bob, 0, "AppDial", "(Outgoing Line)");
 	ast_copy_string(bob_expected_one.uniqueid, ast_channel_uniqueid(chan_bob), sizeof(bob_expected_one.uniqueid));
@@ -1902,6 +1919,7 @@ AST_TEST_DEFINE(test_cdr_dial_answer_multiparty)
 	ast_copy_string(charlie_expected_two.linkedid, ast_channel_linkedid(chan_alice), sizeof(charlie_expected_two.linkedid));
 
 	chan_david = ast_channel_alloc(0, AST_STATE_DOWN, "400", "David", "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David");
+	ast_channel_unlock(chan_david);
 	ast_set_flag(ast_channel_flags(chan_david), AST_FLAG_OUTGOING);
 	EMULATE_APP_DATA(chan_david, 0, "AppDial", "(Outgoing Line)");
 
diff --git a/tests/test_cel.c b/tests/test_cel.c
index 7732f3e9dd..7da4f9ee83 100644
--- a/tests/test_cel.c
+++ b/tests/test_cel.c
@@ -201,24 +201,28 @@ static void do_sleep(void)
 #define CREATE_ALICE_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "100", "100", "default", NULL, 0, CHANNEL_TECH_NAME "/Alice"); \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Create a \ref test_cel_chan_tech for Bob. */
 #define CREATE_BOB_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "200", "200", "default", NULL, 0, CHANNEL_TECH_NAME "/Bob"); \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Create a \ref test_cel_chan_tech for Charlie. */
 #define CREATE_CHARLIE_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "300", "300", "default", NULL, 0, CHANNEL_TECH_NAME "/Charlie"); \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Create a \ref test_cel_chan_tech for David. */
 #define CREATE_DAVID_CHANNEL(channel_var, caller_id) do { \
 	(channel_var) = ast_channel_alloc(0, AST_STATE_DOWN, (caller_id)->id.number.str, (caller_id)->id.name.str, "400", "400", "default", NULL, 0, CHANNEL_TECH_NAME "/David"); \
 	APPEND_EVENT(channel_var, AST_CEL_CHANNEL_START, NULL, NULL); \
+	ast_channel_unlock((channel_var)); \
 	} while (0)
 
 /*! \brief Emulate a channel entering into an application */
@@ -717,6 +721,7 @@ AST_TEST_DEFINE(test_cel_single_multiparty_bridge)
 
 #define START_DIALED_FULL(caller, callee, number, name) do { \
 	callee = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, number, NULL, NULL, ast_channel_linkedid(caller), 0, CHANNEL_TECH_NAME "/" name); \
+	ast_channel_unlock(callee); \
 	if (append_expected_event(callee, AST_CEL_CHANNEL_START, NULL, NULL, NULL)) { \
 		return AST_TEST_FAIL; \
 	} \
diff --git a/tests/test_stasis_channels.c b/tests/test_stasis_channels.c
index 45f1e2ba35..de445458c9 100644
--- a/tests/test_stasis_channels.c
+++ b/tests/test_stasis_channels.c
@@ -73,6 +73,7 @@ AST_TEST_DEFINE(channel_blob_create)
 
 	type = stasis_message_type_create("test-type", NULL);
 	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice");
+	ast_channel_unlock(chan);
 	json = ast_json_pack("{s: s}",
 		     "foo", "bar");
 
@@ -125,6 +126,7 @@ AST_TEST_DEFINE(null_blob)
 
 	type = stasis_message_type_create("test-type", NULL);
 	chan = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice");
+	ast_channel_unlock(chan);
 	json = ast_json_pack("{s: s}",
 		     "foo", "bar");
 
@@ -192,8 +194,11 @@ AST_TEST_DEFINE(multi_channel_blob_snapshots)
 	json = ast_json_pack("{s: s}",
 		     "type", "test");
 	chan_alice = ast_channel_alloc(0, AST_STATE_DOWN, "100", "Alice", "100", "100", "default", NULL, 0, "TEST/Alice");
+	ast_channel_unlock(chan_alice);
 	chan_bob = ast_channel_alloc(0, AST_STATE_DOWN, "200", "Bob", "200", "200", "default", NULL, 0, "TEST/Bob");
+	ast_channel_unlock(chan_bob);
 	chan_charlie = ast_channel_alloc(0, AST_STATE_DOWN, "300", "Bob", "300", "300", "default", NULL, 0, "TEST/Charlie");
+	ast_channel_unlock(chan_charlie);
 
 	blob = ast_multi_channel_blob_create(json);
 	ast_multi_channel_blob_add_channel(blob, "Caller", ast_channel_snapshot_create(chan_alice));
@@ -251,6 +256,7 @@ AST_TEST_DEFINE(channel_snapshot_json)
 	ast_test_validate(test, NULL == ast_channel_snapshot_to_json(NULL, NULL));
 
 	chan = ast_channel_alloc(0, AST_STATE_DOWN, "cid_num", "cid_name", "acctcode", "exten", "context", NULL, 0, "TEST/name");
+	ast_channel_unlock(chan);
 	ast_test_validate(test, NULL != chan);
 	snapshot = ast_channel_snapshot_create(chan);
 	ast_test_validate(test, NULL != snapshot);
diff --git a/tests/test_substitution.c b/tests/test_substitution.c
index 0fa0a584ea..4f87aebd97 100644
--- a/tests/test_substitution.c
+++ b/tests/test_substitution.c
@@ -244,6 +244,7 @@ AST_TEST_DEFINE(test_substitution)
 	ast_test_status_update(test, "Testing variable substitution ...\n");
 
 	c = ast_channel_alloc(0, 0, "", "", "", "", "", "", 0, "Test/substitution");
+	ast_channel_unlock(c);
 
 #define TEST(t) if (t == AST_TEST_FAIL) { res = AST_TEST_FAIL; }
 #if 0
diff --git a/tests/test_voicemail_api.c b/tests/test_voicemail_api.c
index 01efeeec2d..b21ab1f87b 100644
--- a/tests/test_voicemail_api.c
+++ b/tests/test_voicemail_api.c
@@ -833,6 +833,8 @@ static struct ast_channel *test_vm_api_create_mock_channel(void)
 	ast_format_set(ast_channel_rawreadformat(mock_channel), AST_FORMAT_GSM, 0);
 	ast_channel_tech_set(mock_channel, &mock_channel_tech);
 
+	ast_channel_unlock(mock_channel);
+
 	return mock_channel;
 }
 
-- 
GitLab