Index: pjproject/trunk/pjlib/include/pj/timer.h
===================================================================
--- pjproject/trunk/pjlib/include/pj/timer.h	(revision 5970)
+++ pjproject/trunk/pjlib/include/pj/timer.h	(revision 5971)
@@ -253,7 +253,7 @@
  * @param ht        The timer heap.
  * @param entry     The entry to be registered.
+ * @param delay     The interval to expire.
  * @param id_val    The value to be set to the "id" field of the timer entry
  * 		    once the timer is scheduled.
- * @param delay     The interval to expire.
  * @param grp_lock  The group lock.
  *
Index: pjproject/trunk/pjlib/src/pj/timer.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/timer.c	(revision 5970)
+++ pjproject/trunk/pjlib/src/pj/timer.c	(revision 5971)
@@ -503,5 +503,5 @@
 
     /* Prevent same entry from being scheduled more than once */
-    PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
+    //PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
 
 #if PJ_TIMER_DEBUG
@@ -513,4 +513,13 @@
     
     lock_timer_heap(ht);
+
+    /* Prevent same entry from being scheduled more than once */
+    if (pj_timer_entry_running(entry)) {
+	unlock_timer_heap(ht);
+	PJ_LOG(3,(THIS_FILE, "Bug! Rescheduling outstanding entry (%p)",
+		  entry));
+	return PJ_EINVALIDOP;
+    }
+
     status = schedule_entry(ht, entry, &expires);
     if (status == PJ_SUCCESS) {
Index: pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h	(revision 5970)
+++ pjproject/trunk/pjsip/include/pjsip/sip_endpoint.h	(revision 5971)
@@ -139,4 +139,5 @@
 					        const pj_time_val *max_timeout,
 					        unsigned *count);
+
 /**
  * Schedule timer to endpoint's timer heap. Application must poll the endpoint
@@ -165,4 +166,42 @@
 						 pj_timer_entry *entry,
 						 const pj_time_val *delay );
+#endif
+
+/**
+ * Schedule timer to endpoint's timer heap with group lock. Application must
+ * poll the endpoint periodically (by calling #pjsip_endpt_handle_events) to
+ * ensure that the timer events are handled in timely manner. When the
+ * timeout for the timer has elapsed, the callback specified in the entry
+ * argument will be called. This function, like all other endpoint functions,
+ * is thread safe.
+ *
+ * @param endpt	    The endpoint.
+ * @param entry	    The timer entry.
+ * @param delay	    The relative delay of the timer.
+ * @param id_val    The value to be set to the "id" field of the timer entry
+ * 		    once the timer is scheduled.
+ * @param grp_lock  The group lock.
+ * @return	    PJ_OK (zero) if successfull.
+ */
+#if PJ_TIMER_DEBUG
+#define pjsip_endpt_schedule_timer_w_grp_lock(ept,ent,d,id,gl) \
+		pjsip_endpt_schedule_timer_w_grp_lock_dbg(ept,ent,d,id,gl,\
+							  __FILE__, __LINE__)
+
+PJ_DECL(pj_status_t) pjsip_endpt_schedule_timer_w_grp_lock_dbg(
+						    pjsip_endpoint *endpt,
+						    pj_timer_entry *entry,
+						    const pj_time_val *delay,
+						    int id_val,
+						    pj_grp_lock_t *grp_lock,
+						    const char *src_file,
+						    int src_line);
+#else
+PJ_DECL(pj_status_t) pjsip_endpt_schedule_timer_w_grp_lock(
+						 pjsip_endpoint *endpt,
+						 pj_timer_entry *entry,
+						 const pj_time_val *delay,
+						 int id_val,
+						 pj_grp_lock_t *grp_lock );
 #endif
 
Index: pjproject/trunk/pjsip/include/pjsip/sip_transport.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 5970)
+++ pjproject/trunk/pjsip/include/pjsip/sip_transport.h	(revision 5971)
@@ -811,4 +811,6 @@
     pj_atomic_t		   *ref_cnt;	    /**< Reference counter.	    */
     pj_lock_t		   *lock;	    /**< Lock object.		    */
+    pj_grp_lock_t	   *grp_lock;	    /**< Group lock for sync with
+					         ioqueue and timer.	    */
     pj_bool_t		    tracing;	    /**< Tracing enabled?	    */
     pj_bool_t		    is_shutdown;    /**< Being shutdown?	    */
Index: pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 5970)
+++ pjproject/trunk/pjsip/src/pjsip/sip_endpoint.c	(revision 5971)
@@ -804,4 +804,40 @@
 
 /*
+ * Schedule timer with group lock.
+ */
+#if PJ_TIMER_DEBUG
+PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer_w_grp_lock_dbg(
+						    pjsip_endpoint *endpt,
+						    pj_timer_entry *entry,
+						    const pj_time_val *delay,
+						    int id_val,
+						    pj_grp_lock_t *grp_lock,
+						    const char *src_file,
+						    int src_line)
+{
+    PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer_w_grp_lock"
+			  "(entry=%p, delay=%u.%u, grp_lock=%p)",
+			  entry, delay->sec, delay->msec, grp_lock));
+    return pj_timer_heap_schedule_w_grp_lock_dbg(endpt->timer_heap, entry,
+						 delay, id_val, grp_lock,
+						 src_file, src_line);
+}
+#else
+PJ_DEF(pj_status_t) pjsip_endpt_schedule_timer_w_grp_lock(
+						 pjsip_endpoint *endpt,
+						 pj_timer_entry *entry,
+						 const pj_time_val *delay,
+						 int id_val,
+						 pj_grp_lock_t *grp_lock )
+{
+    PJ_LOG(6, (THIS_FILE, "pjsip_endpt_schedule_timer_w_grp_lock"
+			  "(entry=%p, delay=%u.%u, grp_lock=%p)",
+			  entry, delay->sec, delay->msec, grp_lock));
+    return pj_timer_heap_schedule_w_grp_lock( endpt->timer_heap, entry,
+					      delay, id_val, grp_lock );
+}
+#endif
+
+/*
  * Cancel the previously registered timer.
  */
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 5970)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport.c	(revision 5971)
@@ -1013,4 +1013,7 @@
     PJ_UNUSED_ARG(timer_heap);
 
+    if (entry->id == PJ_FALSE)
+	return;
+
     entry->id = PJ_FALSE;
     pjsip_transport_destroy(tp);
@@ -1049,4 +1052,8 @@
 
     PJ_ASSERT_RETURN(tp != NULL, PJ_EINVAL);
+
+    /* Add ref transport group lock, if any */
+    if (tp->grp_lock)
+	pj_grp_lock_add_ref(tp->grp_lock);
 
     /* Cache some vars for checking transport validity later */
@@ -1064,6 +1071,6 @@
 	{
 	    if (tp->idle_timer.id != PJ_FALSE) {
+		tp->idle_timer.id = PJ_FALSE;
 		pjsip_endpt_cancel_timer(tp->tpmgr->endpt, &tp->idle_timer);
-		tp->idle_timer.id = PJ_FALSE;
 	    }
 	}
@@ -1115,11 +1122,20 @@
 	    }
 
-	    pj_assert(tp->idle_timer.id == 0);
-	    tp->idle_timer.id = PJ_TRUE;
-	    pjsip_endpt_schedule_timer(tp->tpmgr->endpt, &tp->idle_timer, 
-				       &delay);
+	    /* Avoid double timer entry scheduling */
+	    if (pj_timer_entry_running(&tp->idle_timer))
+		pjsip_endpt_cancel_timer(tp->tpmgr->endpt, &tp->idle_timer);
+
+	    pjsip_endpt_schedule_timer_w_grp_lock(tp->tpmgr->endpt,
+						  &tp->idle_timer,
+						  &delay,
+						  PJ_TRUE,
+						  tp->grp_lock);
 	}
 	pj_lock_release(tpmgr->lock);
     }
+
+    /* Dec ref transport group lock, if any */
+    if (tp->grp_lock)
+	pj_grp_lock_dec_ref(tp->grp_lock);
 
     return PJ_SUCCESS;
@@ -1169,4 +1185,8 @@
     pj_hash_set(tp->pool, mgr->table, &tp->key, key_len, hval, tp);
 
+    /* Add ref transport group lock, if any */
+    if (tp->grp_lock)
+	pj_grp_lock_add_ref(tp->grp_lock);
+
     pj_lock_release(mgr->lock);
 
@@ -1200,6 +1220,6 @@
     //pj_assert(tp->idle_timer.id == PJ_FALSE);
     if (tp->idle_timer.id != PJ_FALSE) {
+	tp->idle_timer.id = PJ_FALSE;
 	pjsip_endpt_cancel_timer(mgr->endpt, &tp->idle_timer);
-	tp->idle_timer.id = PJ_FALSE;
     }
 
@@ -1226,4 +1246,8 @@
     pj_lock_release(mgr->lock);
     pj_lock_release(tp->lock);
+
+    /* Dec ref transport group lock, if any */
+    if (tp->grp_lock)
+	pj_grp_lock_dec_ref(tp->grp_lock);
 
     /* Destroy. */
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 5970)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 5971)
@@ -693,4 +693,6 @@
     pj_grp_lock_add_handler(tcp->grp_lock, pool, tcp, &tcp_on_destroy);
 
+    tcp->base.grp_lock = tcp->grp_lock;
+
     /* Create active socket */
     pj_activesock_cfg_default(&asock_cfg);
@@ -747,5 +749,9 @@
 
 on_error:
-    tcp_destroy(&tcp->base, status);
+    if (tcp->grp_lock && pj_grp_lock_get_ref(tcp->grp_lock))
+	tcp_destroy(&tcp->base, status);
+    else
+    	tcp_on_destroy(tcp);
+
     return status;
 }
@@ -868,6 +874,4 @@
 	pj_grp_lock_dec_ref(grp_lock);
 	/* Transport may have been deleted at this point */
-    } else {
-	tcp_on_destroy(tcp);
     }
 
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 5970)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_tls.c	(revision 5971)
@@ -164,4 +164,8 @@
 			      const pj_str_t *remote_name,
 			      struct tls_transport **p_tls);
+
+
+/* Clean up TLS resources */
+static void tls_on_destroy(void *arg);
 
 
@@ -894,5 +898,9 @@
 
 on_error:
-    tls_destroy(&tls->base, status);
+    if (tls->grp_lock && pj_grp_lock_get_ref(tls->grp_lock))
+	tls_destroy(&tls->base, status);
+    else
+    	tls_on_destroy(tls);
+
     return status;
 }
@@ -1049,6 +1057,4 @@
 	pj_grp_lock_dec_ref(grp_lock);
 	/* Transport may have been deleted at this point */
-    } else {
-	tls_on_destroy(tls);
     }
 
@@ -1236,5 +1242,5 @@
 
     /* Set up the group lock */
-    tls->grp_lock = glock;
+    tls->grp_lock = tls->base.grp_lock = glock;
     pj_grp_lock_add_ref(tls->grp_lock);
     pj_grp_lock_add_handler(tls->grp_lock, pool, tls, &tls_on_destroy);
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 5970)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_udp.c	(revision 5971)
@@ -692,4 +692,6 @@
 	pj_grp_lock_add_handler(tp->grp_lock, tp->base.pool, tp,
 				&udp_on_destroy);
+
+	tp->base.grp_lock = tp->grp_lock;
     }
     
