diff --git a/res/res_pjsip_registrar.c b/res/res_pjsip_registrar.c index efd2bd9397c9296b371832f22b5767fdf862effd..83fbdf81685896c837d5caf787f0eae4328da011 100644 --- a/res/res_pjsip_registrar.c +++ b/res/res_pjsip_registrar.c @@ -318,6 +318,8 @@ struct contact_transport_monitor { * \note Stored after aor_name in space reserved when struct allocated. */ char *contact_name; + /*! Indicates that the monitor is in the process of removing a contact */ + int removing; /*! AOR name the contact is associated */ char aor_name[0]; }; @@ -344,6 +346,20 @@ static int register_contact_transport_remove_cb(void *data) } ao2_lock(aor); + + /* + * We're now locked so check again to make sure some other thread is not + * currently removing the contact, or already has. + */ + if (monitor->removing) { + ao2_unlock(aor); + ao2_ref(aor, -1); + ao2_ref(monitor, -1); + return 0; + } + + monitor->removing = 1; + contact = ast_sip_location_retrieve_contact(monitor->contact_name); if (contact) { ast_sip_location_delete_contact(contact); @@ -379,6 +395,19 @@ static void register_contact_transport_shutdown_cb(void *data) { struct contact_transport_monitor *monitor = data; + /* + * It's possible for this shutdown handler to get called multiple times for the + * same monitor from different threads. Only one of the calls needs to do the + * actual removing of the contact, so if one is currently removing then any + * subsequent calls can skip. + * + * We'll call it non locked here, but check again once locked just in case the + * flag was updated (see register_contact_transport_remove_cb). + */ + if (monitor->removing) { + return; + } + /* * Push off to a default serializer. This is in case sorcery * does database accesses for contacts. Database accesses may