Index: pjproject/trunk/pjsip/include/pjsip/sip_transaction.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 3310)
+++ pjproject/trunk/pjsip/include/pjsip/sip_transaction.h	(revision 3311)
@@ -87,4 +87,7 @@
     pjsip_endpoint	       *endpt;          /**< Endpoint instance.     */
     pj_mutex_t		       *mutex;          /**< Mutex for this tsx.    */
+    pj_mutex_t		       *mutex_b;	/**< Second mutex to avoid
+						     deadlock. It is used to
+						     protect timer.	    */
 
     /*
Index: pjproject/trunk/pjsip/src/pjsip/sip_transaction.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 3310)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transaction.c	(revision 3311)
@@ -951,4 +951,16 @@
 
 
+/* Lock transaction for accessing the timeout timer only. */
+static void lock_timer(pjsip_transaction *tsx)
+{
+    pj_mutex_lock(tsx->mutex_b);
+}
+
+/* Unlock timer */
+static void unlock_timer(pjsip_transaction *tsx)
+{
+    pj_mutex_unlock(tsx->mutex_b);
+}
+
 /* Create and initialize basic transaction structure.
  * This function is called by both UAC and UAS creation.
@@ -989,4 +1001,11 @@
     }
 
+    status = pj_mutex_create_simple(pool, tsx->obj_name, &tsx->mutex_b);
+    if (status != PJ_SUCCESS) {
+	pj_mutex_destroy(tsx->mutex);
+	pjsip_endpt_release_pool(mod_tsx_layer.endpt, pool);
+	return status;
+    }
+
     *p_tsx = tsx;
     return PJ_SUCCESS;
@@ -1042,4 +1061,5 @@
     }
 
+    pj_mutex_destroy(tsx->mutex_b);
     pj_mutex_destroy(tsx->mutex);
 
@@ -1150,4 +1170,6 @@
 	}
 
+	lock_timer(tsx);
+
 	/* Cancel timeout timer. */
 	if (tsx->timeout_timer.id != 0) {
@@ -1160,4 +1182,5 @@
 				    &timeout);
 
+	unlock_timer(tsx);
 
     } else if (state == PJSIP_TSX_STATE_DESTROYED) {
@@ -1558,5 +1581,4 @@
 					   unsigned millisec)
 {
-    struct tsx_lock_data lck;
     pj_time_val timeout;
 
@@ -1566,9 +1588,12 @@
 		     PJ_EINVALIDOP);
 
-    lock_tsx(tsx, &lck);
+    /* Note: must not call lock_tsx() as that would introduce deadlock.
+     * See #1121.
+     */
+    lock_timer(tsx);
 
     /* Transaction must not have got final response */
     PJ_ASSERT_ON_FAIL(tsx->status_code < 200,
-		    { unlock_tsx(tsx, &lck); return PJ_EINVALIDOP; });
+		    { unlock_timer(tsx); return PJ_EINVALIDOP; });
 
     if (tsx->timeout_timer.id != 0) {
@@ -1586,5 +1611,5 @@
 
 
-    unlock_tsx(tsx, &lck);
+    unlock_timer(tsx);
 
     return PJ_SUCCESS;
@@ -1805,4 +1830,6 @@
 	    /* And reset timeout timer */
 	    if (tsx->timeout_timer.id) {
+		lock_timer(tsx);
+
 		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
 		tsx->timeout_timer.id = TIMER_INACTIVE;
@@ -1811,4 +1838,6 @@
 		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
 					    &timeout_timer_val);
+
+		unlock_timer(tsx);
 	    }
 
@@ -2208,7 +2237,9 @@
 	 * timeout.
 	 */
+	lock_timer(tsx);
 	tsx->timeout_timer.id = TIMER_ACTIVE;
 	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
 				    &timeout_timer_val);
+	unlock_timer(tsx);
 
 	/* Start Timer A (or timer E) for retransmission only if unreliable 
@@ -2300,6 +2331,8 @@
 
 	    if (tsx->timeout_timer.id != 0) {
+		lock_timer(tsx);
 		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
 		tsx->timeout_timer.id = 0;
+		unlock_timer(tsx);
 	    }
 
@@ -2322,5 +2355,7 @@
 
 		/* Cancel timeout timer */
+		lock_timer(tsx);
 		pjsip_endpt_cancel_timer(tsx->endpt, &tsx->timeout_timer);
+		unlock_timer(tsx);
 
 	    } else {
@@ -2573,7 +2608,9 @@
 		}
 
+		lock_timer(tsx);
 		tsx->timeout_timer.id = TIMER_ACTIVE;
 		pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
                                             &timeout);
+		unlock_timer(tsx);
 
 		/* Set state to "Completed" */
@@ -2603,4 +2640,5 @@
 	     * non-reliable transports, and zero for reliable transports.
 	     */
+	    lock_timer(tsx);
 	    if (tsx->method.id == PJSIP_INVITE_METHOD) {
 		/* Start timer H for INVITE */
@@ -2620,4 +2658,5 @@
 					   &zero_time);
 	    }
+	    unlock_timer(tsx);
 
 	    /* For INVITE, if unreliable transport is used, retransmission 
@@ -2747,5 +2786,7 @@
 
 	/* Stop timeout timer B/F. */
+	lock_timer(tsx);
 	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
+	unlock_timer(tsx);
 
 	/* For INVITE, the state moves to Terminated state (because ACK is
@@ -2771,7 +2812,9 @@
 		timeout.sec = timeout.msec = 0;
 	    }
+	    lock_timer(tsx);
 	    tsx->timeout_timer.id = TIMER_ACTIVE;
 	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
 					&timeout);
+	    unlock_timer(tsx);
 
 	    /* Cancel retransmission timer */
@@ -2865,6 +2908,8 @@
 
 	/* Stop timer B. */
+	lock_timer(tsx);
 	tsx->timeout_timer.id = 0;
 	pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
+	unlock_timer(tsx);
 
 	/* Generate and send ACK (for INVITE) */
@@ -2913,6 +2958,8 @@
 	    timeout.sec = timeout.msec = 0;
 	}
+	lock_timer(tsx);
 	tsx->timeout_timer.id = TIMER_ACTIVE;
 	pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, &timeout);
+	unlock_timer(tsx);
 
     } else {
@@ -2972,4 +3019,5 @@
 
 	    /* Reschedule timeout timer. */
+	    lock_timer(tsx);
 	    pjsip_endpt_cancel_timer( tsx->endpt, &tsx->timeout_timer );
 	    tsx->timeout_timer.id = TIMER_ACTIVE;
@@ -2987,4 +3035,5 @@
 	    pjsip_endpt_schedule_timer( tsx->endpt, &tsx->timeout_timer, 
 					&timeout);
+	    unlock_timer(tsx);
 
 	    /* Move state to "Confirmed" */
