PJ_DEF(unsigned) pj_timer_heap_poll( pj_timer_heap_t *ht, pj_time_val *next_delay ) { pj_time_val now; unsigned count; PJ_ASSERT_RETURN(ht, 0); lock_timer_heap(ht); if (!ht->cur_size && next_delay) { next_delay->sec = next_delay->msec = PJ_MAXINT32; unlock_timer_heap(ht); return 0; } count = 0; pj_gettickcount(&now); while ( ht->cur_size && PJ_TIME_VAL_LTE(ht->heap[0]->_timer_value, now) && count < ht->max_entries_per_poll ) { 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); } if (ht->cur_size && next_delay) { *next_delay = ht->heap[0]->_timer_value; PJ_TIME_VAL_SUB(*next_delay, now); if (next_delay->sec < 0 || next_delay->msec < 0) next_delay->sec = next_delay->msec = 0; } else if (next_delay) { next_delay->sec = next_delay->msec = PJ_MAXINT32; } unlock_timer_heap(ht); return count; }
PJ_DEF(pj_status_t) pj_timer_fire(int entry_code_id){ pj_thread_desc a_thread_desc; pj_thread_t *a_thread; unsigned i, j; int entry_id, heap_id; pj_timer_entry *entry; entry_id = entry_code_id % MAX_ENTRY_PER_HEAP; heap_id = entry_code_id / MAX_ENTRY_PER_HEAP; if(heap_id < 0 || heap_id >= MAX_HEAPS){ PJ_LOG(1, (THIS_FILE, "Invalid timer code %d", entry_code_id)); return PJ_EINVAL; } // First step is to register the thread if not already done if (!pj_thread_is_registered()) { char thread_name[160]; int len = pj_ansi_snprintf(thread_name, sizeof(thread_name), "timer_thread_%d", entry_code_id); thread_name[len] = '\0'; pj_thread_register(thread_name, a_thread_desc, &a_thread); PJ_LOG(5, (THIS_FILE, "Registered thread %s", thread_name)); } // Find corresponding ht pj_timer_heap_t *ht = sHeaps[heap_id]; if (ht != NULL) { PJ_LOG(5, (THIS_FILE, "FIRE timer %d of heap %d", entry_id, heap_id)); pj_timer_heap_callback* cb = NULL; lock_timer_heap(ht); // Get callback if entry valid entry = ht->entries[entry_id]; if (entry != NULL && entry->_timer_id >= 0) { cb = entry->cb; } //unlock_timer_heap(ht); //lock_timer_heap(ht); // Release slot ht->entries[entry_id] = NULL; entry->_timer_id = -1; unlock_timer_heap(ht); // Callback may modify current entry (re-enqueue), so do not fire cb before release the slot if (cb) { cb(ht, entry); } PJ_LOG(5, (THIS_FILE, "FIRE done and released")); } else { PJ_LOG(2, (THIS_FILE, "FIRE Ignore : No heap found at %d for this entry %d", heap_id, entry_code_id)); } return PJ_SUCCESS; }
PJ_DEF(pj_status_t) pj_timer_heap_schedule( pj_timer_heap_t *ht, pj_timer_entry *entry, const pj_time_val *delay) #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); unlock_timer_heap(ht); return status; }
PJ_DEF(int) pj_timer_heap_cancel( pj_timer_heap_t *ht, 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; }
PJ_DEF(pj_status_t) pj_timer_heap_earliest_time( pj_timer_heap_t * ht, pj_time_val *timeval) { pj_assert(ht->cur_size != 0); if (ht->cur_size == 0) return PJ_ENOTFOUND; lock_timer_heap(ht); *timeval = ht->heap[0]->_timer_value; unlock_timer_heap(ht); return PJ_SUCCESS; }
PJ_DEF(void) pj_timer_heap_destroy( pj_timer_heap_t *ht ) { int i; lock_timer_heap(ht); // Cancel all entries for (i = 0; i < MAX_ENTRY_PER_HEAP; i++) { if (ht->entries[i] != NULL) { pj_timer_entry *entry = ht->entries[i]; cancel(ht, entry, 1); } } unlock_timer_heap(ht); if (ht->lock && ht->auto_delete_lock) { pj_lock_destroy(ht->lock); ht->lock = NULL; } sCurrentHeap++; sCurrentHeap = sCurrentHeap % MAX_HEAPS; sHeaps[ht->heap_id] = NULL; }
PJ_DEF(void) pj_timer_heap_dump(pj_timer_heap_t *ht) { lock_timer_heap(ht); PJ_LOG(3,(THIS_FILE, "Dumping timer heap:")); PJ_LOG(3,(THIS_FILE, " Cur size: %d entries, max: %d", (int)ht->cur_size, (int)ht->max_size)); if (ht->cur_size) { unsigned i; pj_time_val now; PJ_LOG(3,(THIS_FILE, " Entries: ")); PJ_LOG(3,(THIS_FILE, " _id\tId\tElapsed\tSource")); PJ_LOG(3,(THIS_FILE, " ----------------------------------")); pj_gettickcount(&now); for (i=0; i<(unsigned)ht->cur_size; ++i) { pj_timer_entry *e = ht->heap[i]; pj_time_val delta; if (PJ_TIME_VAL_LTE(e->_timer_value, now)) delta.sec = delta.msec = 0; else { delta = e->_timer_value; PJ_TIME_VAL_SUB(delta, now); } PJ_LOG(3,(THIS_FILE, " %d\t%d\t%d.%03d\t%s:%d", e->_timer_id, e->id, (int)delta.sec, (int)delta.msec, e->src_file, e->src_line)); } } unlock_timer_heap(ht); }
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; }
static int cancel_timer(pj_timer_heap_t *ht, pj_timer_entry *entry, unsigned flags, int id_val) { int count; PJ_ASSERT_RETURN(ht && entry, PJ_EINVAL); lock_timer_heap(ht); count = cancel(ht, entry, flags | F_DONT_CALL); if (flags & F_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 count; }
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); 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 count; }