Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 1981)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 1992)
@@ -28,4 +28,5 @@
 #include <pj/assert.h>
 #include <pj/guid.h>
+#include <pj/lock.h>
 #include <pj/os.h>
 #include <pj/pool.h>
@@ -64,7 +65,8 @@
     pj_pool_t			*pool;
     pjsip_endpoint		*endpt;
+    pj_lock_t			*lock;
     pj_bool_t			 _delete_flag;
     pj_bool_t			 has_tsx;
-    pj_int32_t			 busy;
+    pj_atomic_t			*busy_ctr;
     enum regc_op		 current_op;
 
@@ -130,4 +132,18 @@
     regc->add_xuid_param = pjsip_cfg()->regc.add_xuid_param;
 
+    status = pj_lock_create_recursive_mutex(pool, pool->obj_name, 
+					    &regc->lock);
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
+	return status;
+    }
+
+    status = pj_atomic_create(pool, 0, &regc->busy_ctr);
+    if (status != PJ_SUCCESS) {
+	pj_lock_destroy(regc->lock);
+	pj_pool_release(pool);
+	return status;
+    }
+
     status = pjsip_auth_clt_init(&regc->auth_sess, endpt, regc->pool, 0);
     if (status != PJ_SUCCESS)
@@ -149,7 +165,9 @@
     PJ_ASSERT_RETURN(regc, PJ_EINVAL);
 
-    if (regc->has_tsx || regc->busy) {
+    pj_lock_acquire(regc->lock);
+    if (regc->has_tsx || pj_atomic_get(regc->busy_ctr) != 0) {
 	regc->_delete_flag = 1;
 	regc->cb = NULL;
+	pj_lock_release(regc->lock);
     } else {
 	pjsip_tpselector_dec_ref(&regc->tp_sel);
@@ -162,4 +180,8 @@
 	    regc->timer.id = 0;
 	}
+	pj_atomic_destroy(regc->busy_ctr);
+	pj_lock_release(regc->lock);
+	pj_lock_destroy(regc->lock);
+	regc->lock = NULL;
 	pjsip_endpt_release_pool(regc->endpt, regc->pool);
     }
@@ -174,7 +196,9 @@
     PJ_ASSERT_RETURN(regc && info, PJ_EINVAL);
 
+    pj_lock_acquire(regc->lock);
+
     info->server_uri = regc->str_srv_url;
     info->client_uri = regc->from_uri;
-    info->is_busy = (regc->busy || regc->has_tsx);
+    info->is_busy = (pj_atomic_get(regc->busy_ctr) || regc->has_tsx);
     info->auto_reg = regc->auto_reg;
     info->interval = regc->expires;
@@ -194,4 +218,6 @@
 	info->next_reg = next_reg.sec;
     }
+
+    pj_lock_release(regc->lock);
 
     return PJ_SUCCESS;
@@ -505,7 +531,11 @@
     PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
 
+    pj_lock_acquire(regc->lock);
+
     status = create_request(regc, &tdata);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pj_lock_release(regc->lock);
 	return status;
+    }
 
     msg = tdata->msg;
@@ -540,4 +570,6 @@
     regc->auto_reg = autoreg;
 
+    pj_lock_release(regc->lock);
+
     /* Done */
     *p_tdata = tdata;
@@ -556,4 +588,6 @@
     PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
 
+    pj_lock_acquire(regc->lock);
+
     if (regc->timer.id != 0) {
 	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
@@ -562,6 +596,8 @@
 
     status = create_request(regc, &tdata);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pj_lock_release(regc->lock);
 	return status;
+    }
 
     msg = tdata->msg;
@@ -587,4 +623,6 @@
     pjsip_msg_add_hdr(msg, hdr);
 
+    pj_lock_release(regc->lock);
+
     *p_tdata = tdata;
     return PJ_SUCCESS;
@@ -602,4 +640,6 @@
     PJ_ASSERT_RETURN(regc && p_tdata, PJ_EINVAL);
 
+    pj_lock_acquire(regc->lock);
+
     if (regc->timer.id != 0) {
 	pjsip_endpt_cancel_timer(regc->endpt, &regc->timer);
@@ -608,6 +648,8 @@
 
     status = create_request(regc, &tdata);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pj_lock_release(regc->lock);
 	return status;
+    }
 
     msg = tdata->msg;
@@ -625,4 +667,6 @@
     pjsip_msg_add_hdr(msg, hdr);
 
+    pj_lock_release(regc->lock);
+
     *p_tdata = tdata;
     return PJ_SUCCESS;
@@ -634,6 +678,13 @@
 						const pj_str_t contact[] )
 {
+    pj_status_t status;
+
     PJ_ASSERT_RETURN(regc, PJ_EINVAL);
-    return set_contact( regc, contact_cnt, contact );
+
+    pj_lock_acquire(regc->lock);
+    status = set_contact( regc, contact_cnt, contact );
+    pj_lock_release(regc->lock);
+
+    return status;
 }
 
@@ -643,5 +694,9 @@
 {
     PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+
+    pj_lock_acquire(regc->lock);
     set_expires( regc, expires );
+    pj_lock_release(regc->lock);
+
     return PJ_SUCCESS;
 }
@@ -685,7 +740,7 @@
 
     /* Temporarily increase busy flag to prevent regc from being deleted
-     * in pjsip_regc_send()
+     * in pjsip_regc_send() or in the callback
      */
-    regc->busy++;
+    pj_atomic_inc(regc->busy_ctr);
 
     entry->id = 0;
@@ -701,8 +756,6 @@
     }
 
-    regc->busy--;
-
     /* Delete the record if user destroy regc during the callback. */
-    if (regc->_delete_flag && regc->busy==0) {
+    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
 	pjsip_regc_destroy(regc);
     }
@@ -881,5 +934,8 @@
     pjsip_regc *regc = (pjsip_regc*) token;
     pjsip_transaction *tsx = event->body.tsx_state.tsx;
-    
+
+    pj_atomic_inc(regc->busy_ctr);
+    pj_lock_acquire(regc->lock);
+
     /* Decrement pending transaction counter. */
     pj_assert(regc->has_tsx);
@@ -915,7 +971,5 @@
 
 	if (status == PJ_SUCCESS) {
-	    ++regc->busy;
 	    status = pjsip_regc_send(regc, tdata);
-	    --regc->busy;
 	}
 	
@@ -926,15 +980,12 @@
 	     */
 	    if (regc->_delete_flag == 0) {
-		/* Increment busy flag temporarily to prevent regc from
-		 * being destroyed.
+		/* Should be safe to release the lock temporarily.
+		 * We do this to avoid deadlock. 
 		 */
-		++regc->busy;
-
+		pj_lock_release(regc->lock);
 		call_callback(regc, status, tsx->status_code, 
 			      &rdata->msg_info.msg->line.status.reason,
 			      rdata, -1, 0, NULL);
-
-		/* Decrement busy flag */
-		--regc->busy;
+		pj_lock_acquire(regc->lock);
 	    }
 	}
@@ -994,9 +1045,4 @@
 	}
 
-	/* Increment busy flag temporarily to prevent regc from
-	 * being destroyed.
-	 */
-	++regc->busy;
-
 	/* Update registration */
 	if (expiration==NOEXP) expiration=-1;
@@ -1004,4 +1050,8 @@
 
 	/* Call callback. */
+	/* Should be safe to release the lock temporarily.
+	 * We do this to avoid deadlock. 
+	 */
+	pj_lock_release(regc->lock);
 	call_callback(regc, PJ_SUCCESS, tsx->status_code, 
 		      (rdata ? &rdata->msg_info.msg->line.status.reason 
@@ -1009,11 +1059,11 @@
 		      rdata, expiration, 
 		      contact_cnt, contact);
-
-	/* Decrement busy flag */
-	--regc->busy;
-    }
+	pj_lock_acquire(regc->lock);
+    }
+
+    pj_lock_release(regc->lock);
 
     /* Delete the record if user destroy regc during the callback. */
-    if (regc->_delete_flag && regc->busy==0) {
+    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
 	pjsip_regc_destroy(regc);
     }
@@ -1026,4 +1076,7 @@
     pjsip_expires_hdr *expires_hdr;
     pj_uint32_t cseq;
+
+    pj_atomic_inc(regc->busy_ctr);
+    pj_lock_acquire(regc->lock);
 
     /* Make sure we don't have pending transaction. */
@@ -1032,4 +1085,6 @@
 			     "transaction pending"));
 	pjsip_tx_data_dec_ref( tdata );
+	pj_lock_release(regc->lock);
+	pj_atomic_dec(regc->busy_ctr);
 	return PJSIP_EBUSY;
     }
@@ -1053,9 +1108,5 @@
     pjsip_tx_data_set_transport(tdata, &regc->tp_sel);
 
-    /* Increment pending transaction first, since transaction callback
-     * may be called even before send_request() returns!
-     */
     regc->has_tsx = PJ_TRUE;
-    ++regc->busy;
 
     /* Set current operation based on the value of Expires header */
@@ -1070,8 +1121,9 @@
 	PJ_LOG(4,(THIS_FILE, "Error sending request, status=%d", status));
     }
-    --regc->busy;
+
+    pj_lock_release(regc->lock);
 
     /* Delete the record if user destroy regc during the callback. */
-    if (regc->_delete_flag && regc->busy==0) {
+    if (pj_atomic_dec_and_get(regc->busy_ctr)==0 && regc->_delete_flag) {
 	pjsip_regc_destroy(regc);
     }
