Ignore:
Timestamp:
Sep 19, 2006 1:37:53 PM (18 years ago)
Author:
bennylp
Message:

Fixed race-condition/deadlock problems in the dialog/user agent layer
all the way up to PJSUA-API:

  • standardized locking order: dialog then user agent, and dialog then PJSUA
  • any threads that attempt to acquire mutexes in different order than above MUST employ retry mechanism (for an example, see acquire_call() in pjsua_call.c). This retry mechanism has also been used in the UA layer (sip_ua_layer.c) since it needs to lock user agent layer first before the dialog.
  • introduced pjsip_dlg_try_inc_lock() and PJSUA_TRY_LOCK() to accomodate above.
  • pjsua tested on Quad Xeon with 4 threads and 200 cps, so far so good.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c

    r673 r729  
    210210 
    211211 
    212 /** 
    213  * Lock the dialog's hash table. This function is normally called by 
    214  * dialog code only. 
    215  * 
    216  * @return              PJ_SUCCESS on success or the appropriate error code. 
    217  */ 
    218 PJ_DEF(pj_status_t) pjsip_ua_lock_dlg_table(void) 
    219 { 
    220     return pj_mutex_lock(mod_ua.mutex); 
    221 } 
    222  
    223  
    224 /** 
    225  * Unlock the dialog's hash table. This function is normally called by 
    226  * dialog code only. 
    227  * 
    228  * @return              PJ_SUCCESS on success or the appropriate error code. 
    229  */ 
    230 PJ_DEF(pj_status_t) pjsip_ua_unlock_dlg_table(void) 
    231 { 
    232     return pj_mutex_unlock(mod_ua.mutex); 
    233 } 
    234  
    235  
    236212/* 
    237213 * Get the endpoint where this UA is currently registered. 
     
    500476    pj_str_t *from_tag; 
    501477    pjsip_dialog *dlg; 
     478    pj_status_t status; 
    502479 
    503480    /* Optimized path: bail out early if request is not CANCEL and it doesn't 
     
    509486        return PJ_FALSE; 
    510487    } 
     488 
     489retry_on_deadlock: 
    511490 
    512491    /* Lock user agent before looking up the dialog hash table. */ 
     
    586565    rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg; 
    587566 
    588     /* Lock the dialog */ 
     567    /* Try to lock the dialog */ 
    589568    PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for request")); 
    590     pjsip_dlg_inc_lock(dlg); 
     569    status = pjsip_dlg_try_inc_lock(dlg); 
     570    if (status != PJ_SUCCESS) { 
     571        /* Failed to acquire dialog mutex immediately, this could be  
     572         * because of deadlock. Release UA mutex, yield, and retry  
     573         * the whole thing once again. 
     574         */ 
     575        pj_mutex_unlock(mod_ua.mutex); 
     576        pj_thread_sleep(0); 
     577        goto retry_on_deadlock; 
     578    } 
     579 
     580    /* Done with processing in UA layer, release lock */ 
     581    pj_mutex_unlock(mod_ua.mutex); 
    591582 
    592583    /* Pass to dialog. */ 
     
    596587    pjsip_dlg_dec_lock(dlg); 
    597588 
    598     /* Done processing in the UA */ 
    599     pj_mutex_unlock(mod_ua.mutex); 
    600  
    601589    /* Report as handled. */ 
    602590    return PJ_TRUE; 
     
    610598    pjsip_transaction *tsx; 
    611599    struct dlg_set *dlg_set; 
    612     pjsip_dialog *dlg = NULL; 
     600    pjsip_dialog *dlg; 
     601    pj_status_t status; 
    613602 
    614603    /* 
     
    621610     * the response is a forked response. 
    622611     */ 
     612 
     613retry_on_deadlock: 
     614 
     615    dlg = NULL; 
    623616 
    624617    /* Lock user agent dlg table before we're doing anything. */ 
     
    783776    rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg; 
    784777 
    785     /* Acquire lock to the dialog. */ 
     778    /* Attempt to acquire lock to the dialog. */ 
    786779    PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for response")); 
    787     pjsip_dlg_inc_lock(dlg); 
     780    status = pjsip_dlg_try_inc_lock(dlg); 
     781    if (status != PJ_SUCCESS) { 
     782        /* Failed to acquire dialog mutex. This could indicate a deadlock 
     783         * situation, and for safety, try to avoid deadlock by releasing 
     784         * UA mutex, yield, and retry the whole processing once again. 
     785         */ 
     786        pj_mutex_unlock(mod_ua.mutex); 
     787        pj_thread_sleep(0); 
     788        goto retry_on_deadlock; 
     789    } 
     790 
     791    /* We're done with processing in the UA layer, we can release the mutex */ 
     792    pj_mutex_unlock(mod_ua.mutex); 
    788793 
    789794    /* Pass the response to the dialog. */ 
     
    792797    /* Unlock the dialog. This may destroy the dialog. */ 
    793798    pjsip_dlg_dec_lock(dlg); 
    794  
    795     /* Unlock dialog hash table. */ 
    796     pj_mutex_unlock(mod_ua.mutex); 
    797799 
    798800    /* Done. */ 
Note: See TracChangeset for help on using the changeset viewer.