Index: /pjproject/trunk/pjsip/include/pjsip/sip_dialog.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_dialog.h	(revision 670)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_dialog.h	(revision 671)
@@ -109,5 +109,5 @@
     char		obj_name[PJ_MAX_OBJ_NAME];  /**< Standard id.	    */
     pj_pool_t	       *pool;	    /**< Dialog's pool.			    */
-    pj_mutex_t	       *mutex;	    /**< Dialog's mutex. Do not call!!
+    pj_mutex_t	       *mutex_;	    /**< Dialog's mutex. Do not call!!
 					 Use pjsip_dlg_inc_lock() instead!  */
     pjsip_user_agent   *ua;	    /**< User agent instance.		    */
Index: /pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h
===================================================================
--- /pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h	(revision 670)
+++ /pjproject/trunk/pjsip/include/pjsip/sip_ua_layer.h	(revision 671)
@@ -80,4 +80,23 @@
 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.
Index: /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 670)
+++ /pjproject/trunk/pjsip/src/pjsip-simple/evsub.c	(revision 671)
@@ -669,4 +669,7 @@
 
 
+    /* Must lock dialog before using pool etc. */
+    pjsip_dlg_inc_lock(dlg);
+
     /* Init attributes: */
 
@@ -715,6 +718,8 @@
 
     status = pjsip_dlg_add_usage(dlg, &mod_evsub.mod, dlgsub_head);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pjsip_dlg_dec_lock(dlg);
 	return status;
+    }
 
 
@@ -724,4 +729,5 @@
 
     *p_evsub = sub;
+    pjsip_dlg_dec_lock(dlg);
 
     return PJ_SUCCESS;
Index: /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 670)
+++ /pjproject/trunk/pjsip/src/pjsip-ua/sip_inv.c	(revision 671)
@@ -436,4 +436,7 @@
     PJ_ASSERT_RETURN(dlg && p_inv, PJ_EINVAL);
 
+    /* Must lock dialog first */
+    pjsip_dlg_inc_lock(dlg);
+
     /* Normalize options */
     if (options & PJSIP_INV_REQUIRE_100REL)
@@ -445,5 +448,5 @@
     /* Create the session */
     inv = pj_pool_zalloc(dlg->pool, sizeof(pjsip_inv_session));
-    PJ_ASSERT_RETURN(inv != NULL, PJ_ENOMEM);
+    pj_assert(inv != NULL);
 
     inv->pool = dlg->pool;
@@ -462,12 +465,16 @@
 	status = pjmedia_sdp_neg_create_w_local_offer(dlg->pool, local_sdp,
 						      &inv->neg);
-	if (status != PJ_SUCCESS)
+	if (status != PJ_SUCCESS) {
+	    pjsip_dlg_dec_lock(dlg);
 	    return status;
+	}
     }
 
     /* Register invite as dialog usage. */
     status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pjsip_dlg_dec_lock(dlg);
 	return status;
+    }
 
     /* Increment dialog session */
@@ -476,4 +483,6 @@
     /* Done */
     *p_inv = inv;
+
+    pjsip_dlg_dec_lock(dlg);
 
     PJ_LOG(5,(inv->obj_name, "UAC invite session created for dialog %s",
@@ -841,4 +850,7 @@
 		     PJ_EINVALIDOP);
 
+    /* Lock dialog */
+    pjsip_dlg_inc_lock(dlg);
+
     /* Normalize options */
     if (options & PJSIP_INV_REQUIRE_100REL)
@@ -850,5 +862,5 @@
     /* Create the session */
     inv = pj_pool_zalloc(dlg->pool, sizeof(pjsip_inv_session));
-    PJ_ASSERT_RETURN(inv != NULL, PJ_ENOMEM);
+    pj_assert(inv != NULL);
 
     inv->pool = dlg->pool;
@@ -873,6 +885,8 @@
 	    status = pjmedia_sdp_validate(rem_sdp);
 
-	if (status != PJ_SUCCESS)
+	if (status != PJ_SUCCESS) {
+	    pjsip_dlg_dec_lock(dlg);
 	    return status;
+	}
     }
 
@@ -889,11 +903,15 @@
     }
 
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pjsip_dlg_dec_lock(dlg);
 	return status;
+    }
 
     /* Register invite as dialog usage. */
     status = pjsip_dlg_add_usage(dlg, &mod_inv.mod, inv);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pjsip_dlg_dec_lock(dlg);
 	return status;
+    }
 
     /* Increment session in the dialog. */
@@ -910,4 +928,5 @@
 
     /* Done */
+    pjsip_dlg_dec_lock(dlg);
     *p_inv = inv;
 
Index: /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 670)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_dialog.c	(revision 671)
@@ -81,5 +81,5 @@
     pj_list_init(&dlg->inv_hdr);
 
-    status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex);
+    status = pj_mutex_create_recursive(pool, "dlg%p", &dlg->mutex_);
     if (status != PJ_SUCCESS)
 	goto on_error;
@@ -90,6 +90,6 @@
 
 on_error:
-    if (dlg->mutex)
-	pj_mutex_destroy(dlg->mutex);
+    if (dlg->mutex_)
+	pj_mutex_destroy(dlg->mutex_);
     pjsip_endpt_release_pool(endpt, pool);
     return status;
@@ -98,6 +98,8 @@
 static void destroy_dialog( pjsip_dialog *dlg )
 {
-    if (dlg->mutex)
-	pj_mutex_destroy(dlg->mutex);
+    if (dlg->mutex_) {
+	pj_mutex_destroy(dlg->mutex_);
+	dlg->mutex_ = NULL;
+    }
     pjsip_endpt_release_pool(dlg->endpt, dlg->pool);
 }
@@ -607,6 +609,5 @@
 
     /* Destroy this dialog. */
-    pj_mutex_destroy(dlg->mutex);
-    pjsip_endpt_release_pool(dlg->endpt, dlg->pool);
+    destroy_dialog(dlg);
 
     return PJ_SUCCESS;
@@ -639,5 +640,5 @@
     PJ_ASSERT_RETURN(dlg, PJ_EINVAL);
 
-    pj_mutex_lock(dlg->mutex);
+    pjsip_dlg_inc_lock(dlg);
 
     /* Clear route set. */
@@ -645,5 +646,5 @@
 
     if (!route_set) {
-	pj_mutex_unlock(dlg->mutex);
+	pjsip_dlg_dec_lock(dlg);
 	return PJ_SUCCESS;
     }
@@ -659,6 +660,5 @@
     }
 
-    pj_mutex_unlock(dlg->mutex);
-
+    pjsip_dlg_dec_lock(dlg);
     return PJ_SUCCESS;
 }
@@ -673,7 +673,7 @@
     PJ_ASSERT_RETURN(dlg && mod, PJ_EINVAL);
 
-    pj_mutex_lock(dlg->mutex);
+    pjsip_dlg_inc_lock(dlg);
     ++dlg->sess_count;
-    pj_mutex_unlock(dlg->mutex);
+    pjsip_dlg_dec_lock(dlg);
 
     PJ_LOG(5,(dlg->obj_name, "Session count inc to %d by %.*s",
@@ -685,10 +685,15 @@
 /*
  * Lock dialog and increment session counter temporarily
- * to prevent it from being deleted.
+ * to prevent it from being deleted. In addition, it must lock
+ * the user agent's dialog table first, to prevent deadlock.
  */
 PJ_DEF(void) pjsip_dlg_inc_lock(pjsip_dialog *dlg)
 {
-    pj_mutex_lock(dlg->mutex);
+    pjsip_ua_lock_dlg_table();
+
+    pj_mutex_lock(dlg->mutex_);
     dlg->sess_count++;
+
+    pjsip_ua_unlock_dlg_table();
 }
 
@@ -700,14 +705,18 @@
 PJ_DEF(void) pjsip_dlg_dec_lock(pjsip_dialog *dlg)
 {
+    pjsip_ua_lock_dlg_table();
+
     pj_assert(dlg->sess_count > 0);
     --dlg->sess_count;
 
     if (dlg->sess_count==0 && dlg->tsx_count==0) {
-	pj_mutex_unlock(dlg->mutex);
-	pj_mutex_lock(dlg->mutex);
+	pj_mutex_unlock(dlg->mutex_);
+	pj_mutex_lock(dlg->mutex_);
 	unregister_and_destroy_dialog(dlg);
     } else {
-	pj_mutex_unlock(dlg->mutex);
-    }
+	pj_mutex_unlock(dlg->mutex_);
+    }
+
+    pjsip_ua_unlock_dlg_table();
 }
 
@@ -725,5 +734,6 @@
 	      dlg->sess_count-1, (int)mod->name.slen, mod->name.ptr));
 
-    pj_mutex_lock(dlg->mutex);
+    pjsip_dlg_inc_lock(dlg);
+    --dlg->sess_count;
     pjsip_dlg_dec_lock(dlg);
 
@@ -749,5 +759,5 @@
 	      (int)mod->name.slen, mod->name.ptr, mod_data));
 
-    pj_mutex_lock(dlg->mutex);
+    pjsip_dlg_inc_lock(dlg);
 
     /* Usages are sorted on priority, lowest number first.
@@ -758,5 +768,5 @@
 	if (dlg->usage[index] == mod) {
 	    pj_assert(!"This module is already registered");
-	    pj_mutex_unlock(dlg->mutex);
+	    pjsip_dlg_dec_lock(dlg);
 	    return PJSIP_ETYPEEXISTS;
 	}
@@ -778,5 +788,5 @@
     ++dlg->usage_cnt;
 
-    pj_mutex_unlock(dlg->mutex);
+    pjsip_dlg_dec_lock(dlg);
 
     return PJ_SUCCESS;
@@ -897,5 +907,5 @@
 
     /* Lock dialog. */
-    pj_mutex_lock(dlg->mutex);
+    pjsip_dlg_inc_lock(dlg);
 
     /* Use outgoing CSeq and increment it by one. */
@@ -922,5 +932,5 @@
 
     /* Unlock dialog. */
-    pj_mutex_unlock(dlg->mutex);
+    pjsip_dlg_dec_lock(dlg);
 
     *p_tdata = tdata;
@@ -1114,10 +1124,10 @@
 
     /* Lock the dialog. */
-    pj_mutex_lock(dlg->mutex);
+    pjsip_dlg_inc_lock(dlg);
 
     dlg_beautify_response(dlg, st_code, tdata);
 
     /* Unlock the dialog. */
-    pj_mutex_unlock(dlg->mutex);
+    pjsip_dlg_dec_lock(dlg);
 
     /* Done. */
Index: /pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c	(revision 670)
+++ /pjproject/trunk/pjsip/src/pjsip/sip_ua_layer.c	(revision 671)
@@ -210,4 +210,28 @@
 
 
+/**
+ * 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.
@@ -562,4 +586,7 @@
     rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
 
+    /* Lock the dialog */
+    pjsip_dlg_inc_lock(dlg);
+
     /* Done processing in the UA */
     pj_mutex_unlock(mod_ua.mutex);
@@ -567,4 +594,7 @@
     /* Pass to dialog. */
     pjsip_dlg_on_rx_request(dlg, rdata);
+
+    /* Unlock the dialog. This may destroy the dialog */
+    pjsip_dlg_dec_lock(dlg);
 
     /* Report as handled. */
@@ -591,4 +621,7 @@
      */
 
+    /* Lock user agent dlg table before we're doing anything. */
+    pj_mutex_lock(mod_ua.mutex);
+
     /* Check if transaction is present. */
     tsx = pjsip_rdata_get_tsx(rdata);
@@ -596,6 +629,9 @@
 	/* Check if dialog is present in the transaction. */
 	dlg = pjsip_tsx_get_dlg(tsx);
-	if (!dlg)
+	if (!dlg) {
+	    /* Unlock dialog hash table. */
+	    pj_mutex_unlock(mod_ua.mutex);
 	    return PJ_FALSE;
+	}
 
 	/* Get the dialog set. */
@@ -621,9 +657,9 @@
 	     * or a very late response.
 	     */
+	    /* Unlock dialog hash table. */
+	    pj_mutex_unlock(mod_ua.mutex);
 	    return PJ_FALSE;
 	}
 
-	/* Lock user agent before accessing the hash table. */
-	pj_mutex_lock(mod_ua.mutex);
 
 	/* Get the dialog set. */
@@ -633,8 +669,8 @@
 			      NULL);
 
-	/* Done with accessing the hash table. */
-	pj_mutex_unlock(mod_ua.mutex);
-
 	if (!dlg_set) {
+	    /* Unlock dialog hash table. */
+	    pj_mutex_unlock(mod_ua.mutex);
+
 	    /* Strayed 2xx response!! */
 	    PJ_LOG(4,(THIS_FILE, 
@@ -666,7 +702,4 @@
 	int st_code = rdata->msg_info.msg->line.status.code;
 	pj_str_t *to_tag = &rdata->msg_info.to->tag;
-
-	/* Must hold UA mutex before accessing dialog set. */
-	pj_mutex_lock(mod_ua.mutex);
 
 	dlg = dlg_set->dlg_list.next;
@@ -734,7 +767,4 @@
 	}
 
-	/* Done with the dialog set. */
-	pj_mutex_unlock(mod_ua.mutex);
-
     } else {
 	/* Either this is a non-INVITE response, or subsequent INVITE
@@ -752,6 +782,15 @@
     rdata->endpt_info.mod_data[mod_ua.mod.id] = dlg;
 
+    /* Acquire lock to the dialog. */
+    pjsip_dlg_inc_lock(dlg);
+
+    /* Unlock dialog hash table. */
+    pj_mutex_unlock(mod_ua.mutex);
+
     /* Pass the response to the dialog. */
     pjsip_dlg_on_rx_response(dlg, rdata);
+
+    /* Unlock the dialog. This may destroy the dialog. */
+    pjsip_dlg_dec_lock(dlg);
 
     /* Done. */
