diff options
author | Benny Prijono <bennylp@teluu.com> | 2006-09-19 13:37:53 +0000 |
---|---|---|
committer | Benny Prijono <bennylp@teluu.com> | 2006-09-19 13:37:53 +0000 |
commit | 4b188d682a36a7fa454884ca55b5cf5a7bad069c (patch) | |
tree | c7f94ec4bd11263869fc2ed8804a7864a93a0591 | |
parent | cf81bc0a2ab2947f4a2c5c5fd20bc77ea5611947 (diff) |
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.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@729 74dad513-b988-da41-8d7b-12977e46ad98
-rw-r--r-- | pjsip-apps/src/pjsua/pjsua_app.c | 5 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_dialog.h | 10 | ||||
-rw-r--r-- | pjsip/include/pjsip/sip_ua_layer.h | 18 | ||||
-rw-r--r-- | pjsip/include/pjsua-lib/pjsua_internal.h | 8 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_dialog.c | 32 | ||||
-rw-r--r-- | pjsip/src/pjsip/sip_ua_layer.c | 72 | ||||
-rw-r--r-- | pjsip/src/pjsua-lib/pjsua_call.c | 263 |
7 files changed, 227 insertions, 181 deletions
diff --git a/pjsip-apps/src/pjsua/pjsua_app.c b/pjsip-apps/src/pjsua/pjsua_app.c index 57b6ad2e..0a495b03 100644 --- a/pjsip-apps/src/pjsua/pjsua_app.c +++ b/pjsip-apps/src/pjsua/pjsua_app.c @@ -1196,6 +1196,11 @@ static void call_timeout_callback(pj_timer_heap_t *timer_heap, PJ_UNUSED_ARG(timer_heap); + if (call_id == PJSUA_INVALID_ID) { + PJ_LOG(1,(THIS_FILE, "Invalid call ID in timer callback")); + return; + } + /* Add warning header */ pjsua_msg_data_init(&msg_data); pjsip_generic_string_hdr_init2(&warn, &hname, &hvalue); diff --git a/pjsip/include/pjsip/sip_dialog.h b/pjsip/include/pjsip/sip_dialog.h index 191196a5..b4d2a1ac 100644 --- a/pjsip/include/pjsip/sip_dialog.h +++ b/pjsip/include/pjsip/sip_dialog.h @@ -356,6 +356,16 @@ PJ_DECL(void*) pjsip_dlg_get_mod_data( pjsip_dialog *dlg, PJ_DECL(void) pjsip_dlg_inc_lock( pjsip_dialog *dlg ); /** + * Try to acquire dialog's lock, but return immediately if lock can not + * be acquired. + * + * @param dlg The dialog. + * + * @return PJ_SUCCESS if lock has been acquired. + */ +PJ_DECL(pj_status_t) pjsip_dlg_try_inc_lock( pjsip_dialog *dlg ); + +/** * Unlock dialog and decrement temporary session counter. After this function * is called, dialog may be destroyed. * diff --git a/pjsip/include/pjsip/sip_ua_layer.h b/pjsip/include/pjsip/sip_ua_layer.h index 08e692ca..c4e2d7c7 100644 --- a/pjsip/include/pjsip/sip_ua_layer.h +++ b/pjsip/include/pjsip/sip_ua_layer.h @@ -81,24 +81,6 @@ PJ_DECL(pjsip_user_agent*) pjsip_ua_instance(void); /** - * Lock the dialog's hash table. This function is normally called by - * dialog code only. - * - * @return PJ_SUCCESS on success or the appropriate error code. - */ -PJ_DECL(pj_status_t) pjsip_ua_lock_dlg_table(void); - - -/** - * Unlock the dialog's hash table. This function is normally called by - * dialog code only. - * - * @return PJ_SUCCESS on success or the appropriate error code. - */ -PJ_DECL(pj_status_t) pjsip_ua_unlock_dlg_table(void); - - -/** * Destroy the user agent layer. * * @return PJ_SUCCESS on success. diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index 8b1002b4..10e76635 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -257,11 +257,13 @@ PJ_INLINE(pjsua_im_data*) pjsua_im_data_dup(pj_pool_t *pool, } -#if 0 -#define PJSUA_LOCK() pj_mutex_lock(pjsua_var.mutex); -#define PJSUA_UNLOCK() pj_mutex_unlock(pjsua_var.mutex); +#if 1 +#define PJSUA_LOCK() pj_mutex_lock(pjsua_var.mutex) +#define PJSUA_TRY_LOCK() pj_mutex_trylock(pjsua_var.mutex) +#define PJSUA_UNLOCK() pj_mutex_unlock(pjsua_var.mutex) #else #define PJSUA_LOCK() +#define PJSUA_TRY_LOCK() PJ_SUCCESS #define PJSUA_UNLOCK() #endif diff --git a/pjsip/src/pjsip/sip_dialog.c b/pjsip/src/pjsip/sip_dialog.c index 6cc76141..aab06704 100644 --- a/pjsip/src/pjsip/sip_dialog.c +++ b/pjsip/src/pjsip/sip_dialog.c @@ -692,17 +692,37 @@ PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg) PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_inc_lock(), sess_count=%d", dlg->sess_count)); - pjsip_ua_lock_dlg_table(); - pj_mutex_lock(dlg->mutex_); dlg->sess_count++; - //pjsip_ua_unlock_dlg_table(); - PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_inc_lock(), sess_count=%d", dlg->sess_count)); } +/* Try to acquire dialog's mutex, but bail out if mutex can not be + * acquired immediately. + */ +PJ_DEF(pj_status_t) pjsip_dlg_try_inc_lock(pjsip_dialog *dlg) +{ + pj_status_t status; + + PJ_LOG(6,(dlg->obj_name,"Entering pjsip_dlg_try_inc_lock(), sess_count=%d", + dlg->sess_count)); + + status = pj_mutex_trylock(dlg->mutex_); + if (status != PJ_SUCCESS) { + PJ_LOG(6,(dlg->obj_name, "pjsip_dlg_try_inc_lock() failed")); + return status; + } + + dlg->sess_count++; + + PJ_LOG(6,(dlg->obj_name, "Leaving pjsip_dlg_try_inc_lock(), sess_count=%d", + dlg->sess_count)); + + return PJ_SUCCESS; +} + /* * Unlock dialog and decrement session counter. @@ -713,8 +733,6 @@ PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg) PJ_LOG(6,(dlg->obj_name, "Entering pjsip_dlg_dec_lock(), sess_count=%d", dlg->sess_count)); - //pjsip_ua_lock_dlg_table(); - pj_assert(dlg->sess_count > 0); --dlg->sess_count; @@ -726,8 +744,6 @@ PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg) pj_mutex_unlock(dlg->mutex_); } - pjsip_ua_unlock_dlg_table(); - PJ_LOG(6,(THIS_FILE, "Leaving pjsip_dlg_dec_lock() (dlg=%p)", dlg)); } diff --git a/pjsip/src/pjsip/sip_ua_layer.c b/pjsip/src/pjsip/sip_ua_layer.c index d8552ce0..48764081 100644 --- a/pjsip/src/pjsip/sip_ua_layer.c +++ b/pjsip/src/pjsip/sip_ua_layer.c @@ -209,30 +209,6 @@ PJ_DEF(pjsip_user_agent*) pjsip_ua_instance(void) } -/** - * Lock the dialog's hash table. This function is normally called by - * dialog code only. - * - * @return PJ_SUCCESS on success or the appropriate error code. - */ -PJ_DEF(pj_status_t) pjsip_ua_lock_dlg_table(void) -{ - return pj_mutex_lock(mod_ua.mutex); -} - - -/** - * Unlock the dialog's hash table. This function is normally called by - * dialog code only. - * - * @return PJ_SUCCESS on success or the appropriate error code. - */ -PJ_DEF(pj_status_t) pjsip_ua_unlock_dlg_table(void) -{ - return pj_mutex_unlock(mod_ua.mutex); -} - - /* * Get the endpoint where this UA is currently registered. */ @@ -499,6 +475,7 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata) struct dlg_set *dlg_set; pj_str_t *from_tag; pjsip_dialog *dlg; + pj_status_t status; /* Optimized path: bail out early if request is not CANCEL and it doesn't * have To tag @@ -509,6 +486,8 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata) return PJ_FALSE; } +retry_on_deadlock: + /* Lock user agent before looking up the dialog hash table. */ pj_mutex_lock(mod_ua.mutex); @@ -585,9 +564,21 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata) /* Mark the dialog id of the request. */ rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg; - /* Lock the dialog */ + /* Try to lock the dialog */ PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for request")); - pjsip_dlg_inc_lock(dlg); + status = pjsip_dlg_try_inc_lock(dlg); + if (status != PJ_SUCCESS) { + /* Failed to acquire dialog mutex immediately, this could be + * because of deadlock. Release UA mutex, yield, and retry + * the whole thing once again. + */ + pj_mutex_unlock(mod_ua.mutex); + pj_thread_sleep(0); + goto retry_on_deadlock; + } + + /* Done with processing in UA layer, release lock */ + pj_mutex_unlock(mod_ua.mutex); /* Pass to dialog. */ pjsip_dlg_on_rx_request(dlg, rdata); @@ -595,9 +586,6 @@ static pj_bool_t mod_ua_on_rx_request(pjsip_rx_data *rdata) /* Unlock the dialog. This may destroy the dialog */ pjsip_dlg_dec_lock(dlg); - /* Done processing in the UA */ - pj_mutex_unlock(mod_ua.mutex); - /* Report as handled. */ return PJ_TRUE; } @@ -609,7 +597,8 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata) { pjsip_transaction *tsx; struct dlg_set *dlg_set; - pjsip_dialog *dlg = NULL; + pjsip_dialog *dlg; + pj_status_t status; /* * Find the dialog instance for the response. @@ -621,6 +610,10 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata) * the response is a forked response. */ +retry_on_deadlock: + + dlg = NULL; + /* Lock user agent dlg table before we're doing anything. */ pj_mutex_lock(mod_ua.mutex); @@ -782,9 +775,21 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata) /* Put the dialog instance in the rdata. */ rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg; - /* Acquire lock to the dialog. */ + /* Attempt to acquire lock to the dialog. */ PJ_LOG(6,(dlg->obj_name, "UA layer acquiring dialog lock for response")); - pjsip_dlg_inc_lock(dlg); + status = pjsip_dlg_try_inc_lock(dlg); + if (status != PJ_SUCCESS) { + /* Failed to acquire dialog mutex. This could indicate a deadlock + * situation, and for safety, try to avoid deadlock by releasing + * UA mutex, yield, and retry the whole processing once again. + */ + pj_mutex_unlock(mod_ua.mutex); + pj_thread_sleep(0); + goto retry_on_deadlock; + } + + /* We're done with processing in the UA layer, we can release the mutex */ + pj_mutex_unlock(mod_ua.mutex); /* Pass the response to the dialog. */ pjsip_dlg_on_rx_response(dlg, rdata); @@ -792,9 +797,6 @@ static pj_bool_t mod_ua_on_rx_response(pjsip_rx_data *rdata) /* Unlock the dialog. This may destroy the dialog. */ pjsip_dlg_dec_lock(dlg); - /* Unlock dialog hash table. */ - pj_mutex_unlock(mod_ua.mutex); - /* Done. */ return PJ_TRUE; } diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index a7e0dd47..d9faeb0c 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -383,6 +383,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) if (dlg || tsx) return PJ_FALSE; + PJSUA_LOCK(); /* Verify that we can handle the request. */ status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, @@ -407,6 +408,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) NULL, NULL); } + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -427,6 +429,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) NULL, NULL); PJ_LOG(2,(THIS_FILE, "Unable to accept incoming call (too many calls)")); + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -445,6 +448,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, NULL, NULL); + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -462,6 +466,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, NULL, NULL); + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -471,7 +476,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 500, NULL, NULL, NULL); - + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -499,6 +504,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) /* Can't terminate dialog because transaction is in progress. pjsip_dlg_terminate(dlg); */ + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -520,6 +526,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) pjsip_dlg_respond(dlg, rdata, 500, NULL, NULL, NULL); pjsip_inv_terminate(inv, 500, PJ_FALSE); + PJSUA_UNLOCK(); return PJ_TRUE; } else { @@ -536,6 +543,7 @@ pj_bool_t pjsua_call_on_incoming(pjsip_rx_data *rdata) pjsua_var.ua_cfg.cb.on_incoming_call(acc_id, call_id, rdata); /* This INVITE request has been handled. */ + PJSUA_UNLOCK(); return PJ_TRUE; } @@ -565,17 +573,91 @@ PJ_DEF(pj_bool_t) pjsua_call_has_media(pjsua_call_id call_id) } +/* Acquire lock to the specified call_id */ +static pj_status_t acquire_call(const char *title, + pjsua_call_id call_id, + pjsua_call **p_call) +{ + enum { MAX_RETRY=50 }; + unsigned retry; + pjsua_call *call; + pj_bool_t has_pjsua_lock; + pj_status_t status; + + for (retry=0; retry<MAX_RETRY; ++retry) { + + has_pjsua_lock = PJ_FALSE; + + status = PJSUA_TRY_LOCK(); + if (status != PJ_SUCCESS) { + pj_thread_sleep(retry/10); + continue; + } + + has_pjsua_lock = PJ_TRUE; + call = &pjsua_var.calls[call_id]; + + if (call->inv == NULL) { + PJSUA_UNLOCK(); + PJ_LOG(3,(THIS_FILE, "Invalid call_id %d in %s", call_id, title)); + return PJSIP_ESESSIONTERMINATED; + } + + status = pjsip_dlg_try_inc_lock(call->inv->dlg); + if (status != PJ_SUCCESS) { + PJSUA_UNLOCK(); + pj_thread_sleep(retry/10); + continue; + } + + PJSUA_UNLOCK(); + + break; + } + + if (status != PJ_SUCCESS) { + if (has_pjsua_lock == PJ_FALSE) + PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire PJSUA mutex " + "(possibly system has deadlocked) in %s", + title)); + else + PJ_LOG(1,(THIS_FILE, "Timed-out trying to acquire dialog mutex " + "(possibly system has deadlocked) in %s", + title)); + return PJ_ETIMEDOUT; + } + + *p_call = call; + + return PJ_SUCCESS; +} + + /* * Get the conference port identification associated with the call. */ PJ_DEF(pjsua_conf_port_id) pjsua_call_get_conf_port(pjsua_call_id call_id) { + pjsua_call *call; + pjsua_conf_port_id port_id; + pj_status_t status; + PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - return pjsua_var.calls[call_id].conf_slot; + + status = acquire_call("pjsua_call_get_conf_port()", call_id, &call); + if (status != PJ_SUCCESS) + return -1; + + port_id = call->conf_slot; + + pjsip_dlg_dec_lock(call->inv->dlg); + + return port_id; } + /* * Obtain detail information about the specified call. */ @@ -583,24 +665,18 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id, pjsua_call_info *info) { pjsua_call *call; + pj_status_t status; PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); pj_bzero(info, sizeof(*info)); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; - - if (call->inv == NULL) { - PJSUA_UNLOCK(); - return PJ_SUCCESS; + status = acquire_call("pjsua_call_get_info()", call_id, &call); + if (status != PJ_SUCCESS) { + return status; } - pjsip_dlg_inc_lock(call->inv->dlg); - - /* id and role */ info->id = call_id; info->role = call->inv->role; @@ -696,7 +772,6 @@ PJ_DEF(pj_status_t) pjsua_call_get_info( pjsua_call_id call_id, } pjsip_dlg_dec_lock(call->inv->dlg); - PJSUA_UNLOCK(); return PJ_SUCCESS; } @@ -742,15 +817,9 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id, PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; - - if (call->inv == NULL) { - PJ_LOG(3,(THIS_FILE, "Call %d already disconnected", call_id)); - PJSUA_UNLOCK(); - return PJSIP_ESESSIONTERMINATED; - } + status = acquire_call("pjsua_call_answer()", call_id, &call); + if (status != PJ_SUCCESS) + return status; if (call->res_time.sec == 0) pj_gettimeofday(&call->res_time); @@ -760,7 +829,7 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id, if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error creating response", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -773,7 +842,7 @@ PJ_DEF(pj_status_t) pjsua_call_answer( pjsua_call_id call_id, pjsua_perror(THIS_FILE, "Error sending response", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -793,18 +862,17 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, pjsip_tx_data *tdata; + if (call_id<0 || call_id>=(int)pjsua_var.ua_cfg.max_calls) { + PJ_LOG(1,(THIS_FILE, "pjsua_call_hangup(): invalid call id %d", + call_id)); + } + PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; - - if (!call->inv) { - PJ_LOG(3,(THIS_FILE,"Invalid call or call has been disconnected")); - PJSUA_UNLOCK(); - return PJ_EINVAL; - } + status = acquire_call("pjsua_call_hangup()", call_id, &call); + if (status != PJ_SUCCESS) + return status; if (code==0) { if (call->inv->state == PJSIP_INV_STATE_CONFIRMED) @@ -820,7 +888,7 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, pjsua_perror(THIS_FILE, "Failed to create end session message", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -829,7 +897,7 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, * with any provisional responses. */ if (tdata == NULL) { - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_SUCCESS; } @@ -842,11 +910,11 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, pjsua_perror(THIS_FILE, "Failed to send end session message", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_SUCCESS; } @@ -866,25 +934,20 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id, PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); + status = acquire_call("pjsua_call_set_hold()", call_id, &call); + if (status != PJ_SUCCESS) + return status; - call = &pjsua_var.calls[call_id]; - - if (!call->inv) { - PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); - PJSUA_UNLOCK(); - return PJSIP_ESESSIONTERMINATED; - } if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { PJ_LOG(3,(THIS_FILE, "Can not hold call that is not confirmed")); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJSIP_ESESSIONSTATE; } status = create_inactive_sdp(call, &sdp); if (status != PJ_SUCCESS) { - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -892,7 +955,7 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id, status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -903,11 +966,11 @@ PJ_DEF(pj_status_t) pjsua_call_set_hold(pjsua_call_id call_id, status = pjsip_inv_send_msg( call->inv, tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_SUCCESS; } @@ -929,20 +992,13 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; - - if (!call->inv) { - PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); - PJSUA_UNLOCK(); - return PJSIP_ESESSIONTERMINATED; - } - + status = acquire_call("pjsua_call_reinvite()", call_id, &call); + if (status != PJ_SUCCESS) + return status; if (call->inv->state != PJSIP_INV_STATE_CONFIRMED) { PJ_LOG(3,(THIS_FILE, "Can not re-INVITE call that is not confirmed")); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJSIP_ESESSIONSTATE; } @@ -954,7 +1010,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to get SDP from media endpoint", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -962,7 +1018,7 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, status = pjsip_inv_reinvite( call->inv, NULL, sdp, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create re-INVITE", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -973,11 +1029,11 @@ PJ_DEF(pj_status_t) pjsua_call_reinvite( pjsua_call_id call_id, status = pjsip_inv_send_msg( call->inv, tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send re-INVITE", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_SUCCESS; } @@ -999,15 +1055,11 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id, PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; + pjsip_dlg_dec_lock(call->inv->dlg); + status = acquire_call("pjsua_call_xfer()", call_id, &call); + if (status != PJ_SUCCESS) + return status; - if (!call->inv) { - PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); - PJSUA_UNLOCK(); - return PJSIP_ESESSIONTERMINATED; - } /* Create xfer client subscription. * We're not interested in knowing the transfer result, so we @@ -1016,7 +1068,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id, status = pjsip_xfer_create_uac(call->inv->dlg, NULL, &sub); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create xfer", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -1026,7 +1078,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id, status = pjsip_xfer_initiate(sub, dest, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create REFER request", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -1037,7 +1089,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id, status = pjsip_xfer_send_request(sub, tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to send REFER request", status); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -1046,7 +1098,7 @@ PJ_DEF(pj_status_t) pjsua_call_xfer( pjsua_call_id call_id, * may want to hold the INVITE, or terminate the invite, or whatever. */ - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_SUCCESS; @@ -1065,19 +1117,21 @@ PJ_DEF(pj_status_t) pjsua_call_dial_dtmf( pjsua_call_id call_id, PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); + status = acquire_call("pjsua_call_dial_dtmf()", call_id, &call); + if (status != PJ_SUCCESS) + return status; call = &pjsua_var.calls[call_id]; if (!call->session) { PJ_LOG(3,(THIS_FILE, "Media is not established yet!")); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_EINVALIDOP; } status = pjmedia_session_dial_dtmf( call->session, 0, digits); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return status; } @@ -1103,19 +1157,10 @@ PJ_DEF(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id, PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; - - if (!call->inv) { - PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); - PJSUA_UNLOCK(); - return PJSIP_ESESSIONTERMINATED; - } - - /* Lock dialog. */ - pjsip_dlg_inc_lock(call->inv->dlg); - + status = acquire_call("pjsua_call_send_im", call_id, &call); + if (status != PJ_SUCCESS) + return status; + /* Set default media type if none is specified */ if (mime_type == NULL) { mime_type = &mime_text_plain; @@ -1167,7 +1212,6 @@ PJ_DEF(pj_status_t) pjsua_call_send_im( pjsua_call_id call_id, on_return: pjsip_dlg_dec_lock(call->inv->dlg); - PJSUA_UNLOCK(); return status; } @@ -1183,23 +1227,13 @@ PJ_DEF(pj_status_t) pjsua_call_send_typing_ind( pjsua_call_id call_id, pjsip_tx_data *tdata; pj_status_t status; - PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; - - if (!call->inv) { - PJ_LOG(3,(THIS_FILE,"Call has been disconnected")); - PJSUA_UNLOCK(); - return PJSIP_ESESSIONTERMINATED; - } + status = acquire_call("pjsua_call_send_typing_ind", call_id, &call); + if (status != PJ_SUCCESS) + return status; - /* Lock dialog. */ - pjsip_dlg_inc_lock(call->inv->dlg); - /* Create request message. */ status = pjsip_dlg_create_request( call->inv->dlg, &pjsip_message_method, -1, &tdata); @@ -1224,7 +1258,6 @@ PJ_DEF(pj_status_t) pjsua_call_send_typing_ind( pjsua_call_id call_id, on_return: pjsip_dlg_dec_lock(call->inv->dlg); - PJSUA_UNLOCK(); return status; } @@ -1501,25 +1534,21 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id, pj_time_val duration, res_delay, con_delay; char tmp[128]; char *p, *end; + pj_status_t status; int len; PJ_ASSERT_RETURN(call_id>=0 && call_id<(int)pjsua_var.ua_cfg.max_calls, PJ_EINVAL); - PJSUA_LOCK(); - - call = &pjsua_var.calls[call_id]; + status = acquire_call("pjsua_call_dump()", call_id, &call); + if (status != PJ_SUCCESS) + return status; *buffer = '\0'; p = buffer; end = buffer + maxlen; len = 0; - if (call->inv == NULL) { - PJSUA_UNLOCK(); - return PJ_EINVALIDOP; - } - print_call(indent, call_id, tmp, sizeof(tmp)); len = pj_ansi_strlen(tmp); @@ -1569,7 +1598,7 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id, if (with_media && call->session) dump_media_session(indent, p, end-p, call->session); - PJSUA_UNLOCK(); + pjsip_dlg_dec_lock(call->inv->dlg); return PJ_SUCCESS; } |