Index: pjproject/trunk/pjlib/src/pj/timer.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/timer.c	(revision 4281)
+++ pjproject/trunk/pjlib/src/pj/timer.c	(revision 4359)
@@ -36,4 +36,5 @@
 #include <pj/lock.h>
 #include <pj/log.h>
+#include <pj/rand.h>
 
 #define THIS_FILE	"timer.c"
@@ -452,7 +453,58 @@
     entry->user_data = user_data;
     entry->cb = cb;
+    entry->_grp_lock = NULL;
 
     return entry;
 }
+
+#if PJ_TIMER_DEBUG
+static pj_status_t schedule_w_grp_lock_dbg(pj_timer_heap_t *ht,
+                                           pj_timer_entry *entry,
+                                           const pj_time_val *delay,
+                                           pj_bool_t set_id,
+                                           int id_val,
+					   pj_grp_lock_t *grp_lock,
+					   const char *src_file,
+					   int src_line)
+#else
+static pj_status_t schedule_w_grp_lock(pj_timer_heap_t *ht,
+                                       pj_timer_entry *entry,
+                                       const pj_time_val *delay,
+                                       pj_bool_t set_id,
+                                       int id_val,
+                                       pj_grp_lock_t *grp_lock)
+#endif
+{
+    pj_status_t status;
+    pj_time_val expires;
+
+    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
+    PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL);
+
+    /* Prevent same entry from being scheduled more than once */
+    PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
+
+#if PJ_TIMER_DEBUG
+    entry->src_file = src_file;
+    entry->src_line = src_line;
+#endif
+    pj_gettickcount(&expires);
+    PJ_TIME_VAL_ADD(expires, *delay);
+    
+    lock_timer_heap(ht);
+    status = schedule_entry(ht, entry, &expires);
+    if (status == PJ_SUCCESS) {
+	if (set_id)
+	    entry->id = id_val;
+	entry->_grp_lock = grp_lock;
+	if (entry->_grp_lock) {
+	    pj_grp_lock_add_ref(entry->_grp_lock);
+	}
+    }
+    unlock_timer_heap(ht);
+
+    return status;
+}
+
 
 #if PJ_TIMER_DEBUG
@@ -462,31 +514,62 @@
 						const char *src_file,
 						int src_line)
+{
+    return schedule_w_grp_lock_dbg(ht, entry, delay, PJ_FALSE, 1, NULL,
+                                   src_file, src_line);
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_schedule_w_grp_lock_dbg(
+						pj_timer_heap_t *ht,
+						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)
+{
+    return schedule_w_grp_lock_dbg(ht, entry, delay, PJ_TRUE, id_val,
+                                   grp_lock, src_file, src_line);
+}
+
 #else
 PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht,
-					    pj_timer_entry *entry, 
-					    const pj_time_val *delay)
+                                            pj_timer_entry *entry,
+                                            const pj_time_val *delay)
+{
+    return schedule_w_grp_lock(ht, entry, delay, PJ_FALSE, 1, NULL);
+}
+
+PJ_DEF(pj_status_t) pj_timer_heap_schedule_w_grp_lock(pj_timer_heap_t *ht,
+                                                      pj_timer_entry *entry,
+                                                      const pj_time_val *delay,
+                                                      int id_val,
+                                                      pj_grp_lock_t *grp_lock)
+{
+    return schedule_w_grp_lock(ht, entry, delay, PJ_TRUE, id_val, grp_lock);
+}
 #endif
-{
-    pj_status_t status;
-    pj_time_val expires;
-
-    PJ_ASSERT_RETURN(ht && entry && delay, PJ_EINVAL);
-    PJ_ASSERT_RETURN(entry->cb != NULL, PJ_EINVAL);
-
-    /* Prevent same entry from being scheduled more than once */
-    PJ_ASSERT_RETURN(entry->_timer_id < 1, PJ_EINVALIDOP);
-
-#if PJ_TIMER_DEBUG
-    entry->src_file = src_file;
-    entry->src_line = src_line;
-#endif
-    pj_gettickcount(&expires);
-    PJ_TIME_VAL_ADD(expires, *delay);
-    
+
+static int cancel_timer(pj_timer_heap_t *ht,
+			pj_timer_entry *entry,
+			pj_bool_t set_id,
+			int id_val)
+{
+    int count;
+
+    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
+
     lock_timer_heap(ht);
-    status = schedule_entry(ht, entry, &expires);
+    count = cancel(ht, entry, 1);
+    if (set_id) {
+	entry->id = id_val;
+    }
+    if (entry->_grp_lock) {
+	pj_grp_lock_t *grp_lock = entry->_grp_lock;
+	entry->_grp_lock = NULL;
+	pj_grp_lock_dec_ref(grp_lock);
+    }
     unlock_timer_heap(ht);
 
-    return status;
+    return count;
 }
 
@@ -494,13 +577,12 @@
 				  pj_timer_entry *entry)
 {
-    int count;
-
-    PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL);
-
-    lock_timer_heap(ht);
-    count = cancel(ht, entry, 1);
-    unlock_timer_heap(ht);
-
-    return count;
+    return cancel_timer(ht, entry, PJ_FALSE, 0);
+}
+
+PJ_DEF(int) pj_timer_heap_cancel_if_active(pj_timer_heap_t *ht,
+                                           pj_timer_entry *entry,
+                                           int id_val)
+{
+    return cancel_timer(ht, entry, PJ_TRUE, id_val);
 }
 
@@ -528,9 +610,21 @@
     {
 	pj_timer_entry *node = remove_node(ht, 0);
+	pj_grp_lock_t *grp_lock;
+
 	++count;
 
+	grp_lock = node->_grp_lock;
+	node->_grp_lock = NULL;
+
 	unlock_timer_heap(ht);
+
+	PJ_RACE_ME(5);
+
 	if (node->cb)
 	    (*node->cb)(ht, node);
+
+	if (grp_lock)
+	    pj_grp_lock_dec_ref(grp_lock);
+
 	lock_timer_heap(ht);
     }
