diff options
Diffstat (limited to 'channels/chan_dahdi.c')
-rw-r--r-- | channels/chan_dahdi.c | 62 |
1 files changed, 49 insertions, 13 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c index 4d6a3fae4..de3c0c237 100644 --- a/channels/chan_dahdi.c +++ b/channels/chan_dahdi.c @@ -2058,6 +2058,13 @@ static void my_unlock_private(void *pvt) ast_mutex_unlock(&p->lock); } +static void my_deadlock_avoidance_private(void *pvt) +{ + struct dahdi_pvt *p = pvt; + + DEADLOCK_AVOIDANCE(&p->lock); +} + /* linear_mode = 0 - turn linear mode off, >0 - turn linear mode on * returns the last value of the linear setting */ @@ -3479,6 +3486,7 @@ static struct analog_callback dahdi_analog_callbacks = .all_subchannels_hungup = my_all_subchannels_hungup, .lock_private = my_lock_private, .unlock_private = my_unlock_private, + .deadlock_avoidance_private = my_deadlock_avoidance_private, .handle_dtmfup = my_handle_dtmfup, .wink = my_wink, .new_ast_channel = my_new_analog_ast_channel, @@ -3537,19 +3545,43 @@ static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nul return res; } -static void wakeup_sub(struct dahdi_pvt *p, int a) +/*! + * \internal + * \brief Obtain the specified subchannel owner lock if the owner exists. + * + * \param pvt Channel private struct. + * \param sub_idx Subchannel owner to lock. + * + * \note Assumes the pvt->lock is already obtained. + * + * \note + * Because deadlock avoidance may have been necessary, you need to confirm + * the state of things before continuing. + * + * \return Nothing + */ +static void dahdi_lock_sub_owner(struct dahdi_pvt *pvt, int sub_idx) { for (;;) { - if (p->subs[a].owner) { - if (ast_channel_trylock(p->subs[a].owner)) { - DEADLOCK_AVOIDANCE(&p->lock); - } else { - ast_queue_frame(p->subs[a].owner, &ast_null_frame); - ast_channel_unlock(p->subs[a].owner); - break; - } - } else + if (!pvt->subs[sub_idx].owner) { + /* No subchannel owner pointer */ + break; + } + if (!ast_channel_trylock(pvt->subs[sub_idx].owner)) { + /* Got subchannel owner lock */ break; + } + /* We must unlock the private to avoid the possibility of a deadlock */ + DEADLOCK_AVOIDANCE(&pvt->lock); + } +} + +static void wakeup_sub(struct dahdi_pvt *p, int a) +{ + dahdi_lock_sub_owner(p, a); + if (p->subs[a].owner) { + ast_queue_frame(p->subs[a].owner, &ast_null_frame); + ast_channel_unlock(p->subs[a].owner); } } @@ -11241,9 +11273,13 @@ static void *do_monitor(void *data) if (last) { struct analog_pvt *analog_p = last->sig_pvt; /* Only allow MWI to be initiated on a quiescent fxs port */ - if (!last->mwisendactive && last->sig & __DAHDI_SIG_FXO && - !analog_p->fxsoffhookstate && !last->owner && - !ast_strlen_zero(last->mailbox) && (thispass - analog_p->onhooktime > 3)) { + if (analog_p + && !last->mwisendactive + && (last->sig & __DAHDI_SIG_FXO) + && !analog_p->fxsoffhookstate + && !last->owner + && !ast_strlen_zero(last->mailbox) + && (thispass - analog_p->onhooktime > 3)) { res = has_voicemail(last); if (analog_p->msgstate != res) { /* Set driver resources for signalling VMWI */ |