summaryrefslogtreecommitdiff
path: root/main
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2013-12-03 17:07:29 +0000
committerMark Michelson <mmichelson@digium.com>2013-12-03 17:07:29 +0000
commit8e8b329e14ad2e4d747c4c4eb33c118305401aee (patch)
tree200a9b111d9cf75ab980aedf53ee714b7cc398f2 /main
parent8b24b0d20647697c9ee899dea85871465c3032cb (diff)
Add channel locking for channel snapshot creation.
This adds channel locks around calls to create channel snapshots as well as other functions which operate on a channel and then end up creating a channel snapshot. Functions that expect the channel to be locked prior to being called have had their documentation updated to indicate such. ........ Merged revisions 403311 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main')
-rw-r--r--main/bridge.c9
-rw-r--r--main/bridge_channel.c11
-rw-r--r--main/cel.c2
-rw-r--r--main/channel.c18
-rw-r--r--main/core_local.c26
-rw-r--r--main/core_unreal.c4
-rw-r--r--main/dial.c2
-rw-r--r--main/endpoints.c2
-rw-r--r--main/pbx.c12
-rw-r--r--main/pickup.c10
-rw-r--r--main/stasis_bridges.c6
-rw-r--r--main/stasis_channels.c4
12 files changed, 94 insertions, 12 deletions
diff --git a/main/bridge.c b/main/bridge.c
index 1c3bf16e3..5d6d0632a 100644
--- a/main/bridge.c
+++ b/main/bridge.c
@@ -2497,7 +2497,13 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
other = ast_bridge_channel_peer(src_bridge_channel);
if (other && other->state == BRIDGE_CHANNEL_STATE_WAIT) {
- unsigned int id = ast_atomic_fetchadd_int((int *) &optimization_id, +1);
+ unsigned int id;
+
+ if (ast_channel_trylock(other->chan)) {
+ return 1;
+ }
+
+ id = ast_atomic_fetchadd_int((int *) &optimization_id, +1);
ast_verb(3, "Move-swap optimizing %s <-- %s.\n",
ast_channel_name(dst_bridge_channel->chan),
@@ -2519,6 +2525,7 @@ static int try_swap_optimize_out(struct ast_bridge *chan_bridge,
if (pvt && pvt->callbacks && pvt->callbacks->optimization_finished) {
pvt->callbacks->optimization_finished(pvt, res == 1, id);
}
+ ast_channel_unlock(other);
}
return res;
}
diff --git a/main/bridge_channel.c b/main/bridge_channel.c
index 96bfb209a..ae33cd056 100644
--- a/main/bridge_channel.c
+++ b/main/bridge_channel.c
@@ -235,12 +235,16 @@ void ast_bridge_channel_update_linkedids(struct ast_bridge_channel *bridge_chann
return;
}
+ ast_channel_lock(bridge_channel->chan);
ast_channel_linkedid_set(bridge_channel->chan, oldest_linkedid);
+ ast_channel_unlock(bridge_channel->chan);
AST_LIST_TRAVERSE(&bridge->channels, other, entry) {
if (other == swap) {
continue;
}
+ ast_channel_lock(other->chan);
ast_channel_linkedid_set(other->chan, oldest_linkedid);
+ ast_channel_unlock(other->chan);
}
}
@@ -253,6 +257,7 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch
if (other == swap) {
continue;
}
+ ast_channel_lock_both(bridge_channel->chan, other->chan);
if (!ast_strlen_zero(ast_channel_accountcode(bridge_channel->chan)) && ast_strlen_zero(ast_channel_peeraccount(other->chan))) {
ast_debug(1, "Setting peeraccount to %s for %s from data on channel %s\n",
@@ -286,6 +291,8 @@ void ast_bridge_channel_update_accountcodes(struct ast_bridge_channel *bridge_ch
ast_channel_peeraccount_set(bridge_channel->chan, ast_channel_accountcode(other->chan));
}
}
+ ast_channel_unlock(bridge_channel->chan);
+ ast_channel_unlock(other->chan);
}
}
@@ -624,14 +631,18 @@ int ast_bridge_channel_write_hold(struct ast_bridge_channel *bridge_channel, con
datalen = 0;
}
+ ast_channel_lock(bridge_channel->chan);
ast_channel_publish_blob(bridge_channel->chan, ast_channel_hold_type(), blob);
+ ast_channel_unlock(bridge_channel->chan);
return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_HOLD,
moh_class, datalen);
}
int ast_bridge_channel_write_unhold(struct ast_bridge_channel *bridge_channel)
{
+ ast_channel_lock(bridge_channel->chan);
ast_channel_publish_blob(bridge_channel->chan, ast_channel_unhold_type(), NULL);
+ ast_channel_unlock(bridge_channel->chan);
return ast_bridge_channel_write_control_data(bridge_channel, AST_CONTROL_UNHOLD, NULL, 0);
}
diff --git a/main/cel.c b/main/cel.c
index db51361e9..b9f992f6f 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -1614,7 +1614,9 @@ void ast_cel_publish_event(struct ast_channel *chan,
"event_type", event_type,
"event_details", blob);
+ ast_channel_lock(chan);
message = ast_channel_blob_create(chan, cel_generic_type(), cel_blob);
+ ast_channel_unlock(chan);
if (message) {
stasis_publish(ast_cel_topic(), message);
}
diff --git a/main/channel.c b/main/channel.c
index 58b50c820..f1bbbda27 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -678,7 +678,9 @@ int ast_str2cause(const char *name)
static struct stasis_message *create_channel_snapshot_message(struct ast_channel *channel)
{
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ ast_channel_lock(channel);
snapshot = ast_channel_snapshot_create(channel);
+ ast_channel_unlock(channel);
if (!snapshot) {
return NULL;
}
@@ -1261,6 +1263,7 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_HOLD };
int res;
+ ast_channel_lock(chan);
if (!ast_strlen_zero(musicclass)) {
f.data.ptr = (void *) musicclass;
f.datalen = strlen(musicclass) + 1;
@@ -1272,6 +1275,7 @@ int ast_queue_hold(struct ast_channel *chan, const char *musicclass)
ast_channel_publish_blob(chan, ast_channel_hold_type(), blob);
res = ast_queue_frame(chan, &f);
+ ast_channel_unlock(chan);
return res;
}
@@ -1280,9 +1284,11 @@ int ast_queue_unhold(struct ast_channel *chan)
struct ast_frame f = { AST_FRAME_CONTROL, .subclass.integer = AST_CONTROL_UNHOLD };
int res;
+ ast_channel_lock(chan);
ast_channel_publish_blob(chan, ast_channel_unhold_type(), NULL);
res = ast_queue_frame(chan, &f);
+ ast_channel_unlock(chan);
return res;
}
@@ -2248,7 +2254,9 @@ static void ast_channel_destructor(void *obj)
/* Things that may possibly raise Stasis messages shouldn't occur after this point */
ast_set_flag(ast_channel_flags(chan), AST_FLAG_DEAD);
+ ast_channel_lock(chan);
ast_channel_publish_snapshot(chan);
+ ast_channel_unlock(chan);
publish_cache_clear(chan);
ast_channel_lock(chan);
@@ -5318,7 +5326,9 @@ static int set_format(struct ast_channel *chan,
generator_write_format_change(chan);
}
+ ast_channel_lock(chan);
ast_channel_publish_snapshot(chan);
+ ast_channel_unlock(chan);
return 0;
}
@@ -5399,7 +5409,9 @@ static int set_format(struct ast_channel *chan,
generator_write_format_change(chan);
}
+ ast_channel_lock(chan);
ast_channel_publish_snapshot(chan);
+ ast_channel_unlock(chan);
return res;
}
@@ -5616,7 +5628,9 @@ struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_chan
/* Copy/inherit important information into new channel */
if (oh) {
if (oh->vars) {
+ ast_channel_lock(new_chan);
ast_set_variables(new_chan, oh->vars);
+ ast_channel_unlock(new_chan);
}
if (oh->parent_channel) {
call_forward_inherit(new_chan, oh->parent_channel, orig);
@@ -5677,7 +5691,9 @@ struct ast_channel *__ast_request_and_dial(const char *type, struct ast_format_c
if (oh) {
if (oh->vars) {
+ ast_channel_lock(chan);
ast_set_variables(chan, oh->vars);
+ ast_channel_unlock(chan);
}
if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) {
/*
@@ -5949,7 +5965,9 @@ struct ast_channel *ast_request(const char *type, struct ast_format_cap *request
if (requestor) {
struct ast_callid *callid = ast_channel_callid(requestor);
if (callid) {
+ ast_channel_lock(c);
ast_channel_callid_set(c, callid);
+ ast_channel_unlock(c);
callid = ast_callid_unref(callid);
}
}
diff --git a/main/core_local.c b/main/core_local.c
index 4a047032c..4b1253219 100644
--- a/main/core_local.c
+++ b/main/core_local.c
@@ -498,29 +498,32 @@ static void publish_local_bridge_message(struct local_pvt *p)
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel_snapshot *, one_snapshot, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel_snapshot *, two_snapshot, NULL, ao2_cleanup);
- SCOPED_AO2LOCK(lock, p);
+ struct ast_channel *owner;
+ struct ast_channel *chan;
+
+ ast_unreal_lock_all(&p->base, &chan, &owner);
blob = ast_json_pack("{s: s, s: s, s: b}",
"context", p->context,
"exten", p->exten,
"can_optimize", !ast_test_flag(&p->base, AST_UNREAL_NO_OPTIMIZATION));
if (!blob) {
- return;
+ goto end;
}
multi_blob = ast_multi_channel_blob_create(blob);
if (!multi_blob) {
- return;
+ goto end;
}
- one_snapshot = ast_channel_snapshot_create(p->base.owner);
+ one_snapshot = ast_channel_snapshot_create(owner);
if (!one_snapshot) {
- return;
+ goto end;
}
- two_snapshot = ast_channel_snapshot_create(p->base.chan);
+ two_snapshot = ast_channel_snapshot_create(chan);
if (!two_snapshot) {
- return;
+ goto end;
}
ast_multi_channel_blob_add_channel(multi_blob, "1", one_snapshot);
@@ -528,10 +531,15 @@ static void publish_local_bridge_message(struct local_pvt *p)
msg = stasis_message_create(ast_local_bridge_type(), multi_blob);
if (!msg) {
- return;
+ goto end;
}
- stasis_publish(ast_channel_topic(p->base.owner), msg);
+ stasis_publish(ast_channel_topic(owner), msg);
+
+end:
+ ast_channel_unlock(owner);
+ ast_channel_unlock(chan);
+ ao2_unlock(p);
}
int ast_local_setup_bridge(struct ast_channel *ast, struct ast_bridge *bridge, struct ast_channel *swap, struct ast_bridge_features *features)
diff --git a/main/core_unreal.c b/main/core_unreal.c
index 7e457f484..0a4859703 100644
--- a/main/core_unreal.c
+++ b/main/core_unreal.c
@@ -918,8 +918,12 @@ struct ast_channel *ast_unreal_new_channels(struct ast_unreal_pvt *p,
}
if (callid) {
+ ast_channel_lock(owner);
ast_channel_callid_set(owner, callid);
+ ast_channel_unlock(owner);
+ ast_channel_lock(chan);
ast_channel_callid_set(chan, callid);
+ ast_channel_unlock(chan);
}
ast_channel_tech_set(owner, tech);
diff --git a/main/dial.c b/main/dial.c
index 8cc6f9c89..1729af41a 100644
--- a/main/dial.c
+++ b/main/dial.c
@@ -286,6 +286,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
cap_request = NULL;
cap_all_audio = ast_format_cap_destroy(cap_all_audio);
+ ast_channel_lock(channel->owner);
ast_channel_stage_snapshot(channel->owner);
ast_channel_appl_set(channel->owner, "AppDial2");
@@ -315,6 +316,7 @@ static int begin_dial_prerun(struct ast_dial_channel *channel, struct ast_channe
}
ast_channel_stage_snapshot_done(channel->owner);
+ ast_channel_unlock(channel->owner);
return 0;
}
diff --git a/main/endpoints.c b/main/endpoints.c
index 9eeadfeef..3480a3055 100644
--- a/main/endpoints.c
+++ b/main/endpoints.c
@@ -203,7 +203,9 @@ int ast_endpoint_add_channel(struct ast_endpoint *endpoint,
ast_str_container_add(endpoint->channel_ids, ast_channel_uniqueid(chan));
ao2_unlock(endpoint);
+ ast_channel_lock(chan);
ast_publish_channel_state(chan);
+ ast_channel_unlock(chan);
endpoint_publish_snapshot(endpoint);
return 0;
diff --git a/main/pbx.c b/main/pbx.c
index 99c686371..03b1c4a8e 100644
--- a/main/pbx.c
+++ b/main/pbx.c
@@ -1601,9 +1601,11 @@ int pbx_exec(struct ast_channel *c, /*!< Channel */
saved_c_appl= ast_channel_appl(c);
saved_c_data= ast_channel_data(c);
+ ast_channel_lock(c);
ast_channel_appl_set(c, app->name);
ast_channel_data_set(c, data);
ast_channel_publish_snapshot(c);
+ ast_channel_unlock(c);
if (app->module)
u = __ast_module_user_add(app->module, c);
@@ -6101,7 +6103,9 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
if (!callid) {
callid = ast_create_callid();
if (callid) {
+ ast_channel_lock(c);
ast_channel_callid_set(c, callid);
+ ast_channel_unlock(c);
}
}
ast_callid_threadassoc_add(callid);
@@ -10069,6 +10073,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co
return -1;
}
+ ast_channel_lock(dialed);
if (vars) {
ast_set_variables(dialed, vars);
}
@@ -10077,6 +10082,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co
ast_channel_accountcode_set(dialed, account);
}
ast_set_flag(ast_channel_flags(dialed), AST_FLAG_ORIGINATED);
+ ast_channel_unlock(dialed);
if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
struct ast_party_connected_line connected;
@@ -10172,6 +10178,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co
if (failed) {
char failed_reason[4] = "";
+ ast_channel_lock(failed);
if (!ast_strlen_zero(context)) {
ast_channel_context_set(failed, context);
}
@@ -10184,6 +10191,7 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap, co
ast_set_variables(failed, vars);
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));
@@ -10484,10 +10492,12 @@ static int pbx_builtin_busy(struct ast_channel *chan, const char *data)
ast_indicate(chan, AST_CONTROL_BUSY);
/* Don't change state of an UP channel, just indicate
busy in audio */
+ ast_channel_lock(chan);
if (ast_channel_state(chan) != AST_STATE_UP) {
ast_channel_hangupcause_set(chan, AST_CAUSE_BUSY);
ast_setstate(chan, AST_STATE_BUSY);
}
+ ast_channel_unlock(chan);
wait_for_hangup(chan, data);
return -1;
}
@@ -10500,10 +10510,12 @@ static int pbx_builtin_congestion(struct ast_channel *chan, const char *data)
ast_indicate(chan, AST_CONTROL_CONGESTION);
/* Don't change state of an UP channel, just indicate
congestion in audio */
+ ast_channel_lock(chan);
if (ast_channel_state(chan) != AST_STATE_UP) {
ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
ast_setstate(chan, AST_STATE_BUSY);
}
+ ast_channel_unlock(chan);
wait_for_hangup(chan, data);
return -1;
}
diff --git a/main/pickup.c b/main/pickup.c
index 7ae6927fa..a415f1672 100644
--- a/main/pickup.c
+++ b/main/pickup.c
@@ -354,11 +354,17 @@ int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
/* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
- if (!(chan_snapshot = ast_channel_snapshot_create(chan))) {
+ ast_channel_lock(chan);
+ chan_snapshot = ast_channel_snapshot_create(chan);
+ ast_channel_unlock(chan);
+ if (!chan_snapshot) {
goto pickup_failed;
}
- if (!(target_snapshot = ast_channel_snapshot_create(target))) {
+ ast_channel_lock(target);
+ target_snapshot = ast_channel_snapshot_create(target);
+ ast_channel_unlock(target);
+ if (!target_snapshot) {
goto pickup_failed;
}
diff --git a/main/stasis_bridges.c b/main/stasis_bridges.c
index b92d048bc..dd22710b1 100644
--- a/main/stasis_bridges.c
+++ b/main/stasis_bridges.c
@@ -397,7 +397,9 @@ struct stasis_message *ast_bridge_blob_create(
}
if (chan) {
+ ast_channel_lock(chan);
obj->channel = ast_channel_snapshot_create(chan);
+ ast_channel_unlock(chan);
if (obj->channel == NULL) {
return NULL;
}
@@ -579,7 +581,9 @@ static int bridge_channel_snapshot_pair_init(struct ast_bridge_channel_pair *pai
}
}
+ ast_channel_lock(pair->channel);
snapshot_pair->channel_snapshot = ast_channel_snapshot_create(pair->channel);
+ ast_channel_unlock(pair->channel);
if (!snapshot_pair->channel_snapshot) {
return -1;
}
@@ -915,7 +919,9 @@ void ast_bridge_publish_attended_transfer_link(int is_external, enum ast_transfe
transfer_msg->dest_type = AST_ATTENDED_TRANSFER_DEST_LINK;
for (i = 0; i < 2; ++i) {
+ ast_channel_lock(locals[i]);
transfer_msg->dest.links[i] = ast_channel_snapshot_create(locals[i]);
+ ast_channel_unlock(locals[i]);
if (!transfer_msg->dest.links[i]) {
return;
}
diff --git a/main/stasis_channels.c b/main/stasis_channels.c
index 38aac982e..127106ad9 100644
--- a/main/stasis_channels.c
+++ b/main/stasis_channels.c
@@ -310,14 +310,18 @@ void ast_channel_publish_dial_forward(struct ast_channel *caller, struct ast_cha
}
if (caller) {
+ ast_channel_lock(caller);
caller_snapshot = ast_channel_snapshot_create(caller);
+ ast_channel_unlock(caller);
if (!caller_snapshot) {
return;
}
ast_multi_channel_blob_add_channel(payload, "caller", caller_snapshot);
}
+ ast_channel_lock(peer);
peer_snapshot = ast_channel_snapshot_create(peer);
+ ast_channel_unlock(peer);
if (!peer_snapshot) {
return;
}