Properly lock slave and master in zt_unlink (bug #1008)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2208 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Mark Spencer 22 years ago
parent de6910a6b6
commit 90594b5fc8

@ -2196,13 +2196,23 @@ int x;
return 0; return 0;
} }
static void zt_unlink(struct zt_pvt *slave, struct zt_pvt *master) static void zt_unlink(struct zt_pvt *slave, struct zt_pvt *master, int needlock)
{ {
/* Unlink a specific slave or all slaves/masters from a given master */ /* Unlink a specific slave or all slaves/masters from a given master */
int x; int x;
int hasslaves; int hasslaves;
if (!master) if (!master)
return; return;
if (needlock) {
ast_mutex_lock(&master->lock);
if (slave) {
while(ast_mutex_trylock(&slave->lock)) {
ast_mutex_unlock(&master->lock);
usleep(1);
ast_mutex_lock(&master->lock);
}
}
}
hasslaves = 0; hasslaves = 0;
for (x=0;x<MAX_SLAVES;x++) { for (x=0;x<MAX_SLAVES;x++) {
if (master->slaves[x]) { if (master->slaves[x]) {
@ -2237,6 +2247,11 @@ static void zt_unlink(struct zt_pvt *slave, struct zt_pvt *master)
master->master = NULL; master->master = NULL;
} }
update_conf(master); update_conf(master);
if (needlock) {
if (slave)
ast_mutex_unlock(&slave->lock);
ast_mutex_unlock(&master->lock);
}
} }
static void zt_link(struct zt_pvt *slave, struct zt_pvt *master) { static void zt_link(struct zt_pvt *slave, struct zt_pvt *master) {
@ -2456,7 +2471,7 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
(oi1 != i1) || (oi1 != i1) ||
(oi2 != i2)) { (oi2 != i2)) {
if (slave && master) if (slave && master)
zt_unlink(slave, master); zt_unlink(slave, master, 1);
ast_log(LOG_DEBUG, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n", ast_log(LOG_DEBUG, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
op0->channel, oi1, op1->channel, oi2); op0->channel, oi1, op1->channel, oi2);
if (op0 == p0) if (op0 == p0)
@ -2484,7 +2499,7 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
*fo = NULL; *fo = NULL;
*rc = who; *rc = who;
if (slave && master) if (slave && master)
zt_unlink(slave, master); zt_unlink(slave, master, 1);
if (op0 == p0) if (op0 == p0)
zt_enable_ec(p0); zt_enable_ec(p0);
if (op1 == p1) if (op1 == p1)
@ -2497,7 +2512,7 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
*fo = f; *fo = f;
*rc = who; *rc = who;
if (slave && master) if (slave && master)
zt_unlink(slave, master); zt_unlink(slave, master, 1);
return 0; return 0;
} else if ((who == c0) && p0->pulsedial) { } else if ((who == c0) && p0->pulsedial) {
ast_write(c1, f); ast_write(c1, f);
@ -2520,18 +2535,20 @@ static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
{ {
struct zt_pvt *p = newchan->pvt->pvt; struct zt_pvt *p = newchan->pvt->pvt;
int x; int x;
ast_mutex_lock(&p->lock);
ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name); ast_log(LOG_DEBUG, "New owner for channel %d is %s\n", p->channel, newchan->name);
if (p->owner == oldchan) if (p->owner == oldchan)
p->owner = newchan; p->owner = newchan;
for (x=0;x<3;x++) for (x=0;x<3;x++)
if (p->subs[x].owner == oldchan) { if (p->subs[x].owner == oldchan) {
if (!x) if (!x)
zt_unlink(NULL, p); zt_unlink(NULL, p, 0);
p->subs[x].owner = newchan; p->subs[x].owner = newchan;
} }
if (newchan->_state == AST_STATE_RINGING) if (newchan->_state == AST_STATE_RINGING)
zt_indicate(newchan, AST_CONTROL_RINGING); zt_indicate(newchan, AST_CONTROL_RINGING);
update_conf(p); update_conf(p);
ast_mutex_unlock(&p->lock);
return 0; return 0;
} }

Loading…
Cancel
Save