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(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); }
bool operator <= (const Pj_Time_Val &rhs) const { return PJ_TIME_VAL_LTE((*this), rhs); }
static int test_timer_heap(void) { int i, j; pj_timer_entry *entry; pj_pool_t *pool; pj_timer_heap_t *timer; pj_time_val delay; pj_status_t rc; int err=0; unsigned size, count; size = pj_timer_heap_mem_size(MAX_COUNT)+MAX_COUNT*sizeof(pj_timer_entry); pool = pj_pool_create( mem, NULL, size, 4000, NULL); if (!pool) { PJ_LOG(3,("test", "...error: unable to create pool of %u bytes", size)); return -10; } entry = (pj_timer_entry*)pj_pool_calloc(pool, MAX_COUNT, sizeof(*entry)); if (!entry) return -20; for (i=0; i<MAX_COUNT; ++i) { entry[i].cb = &timer_callback; } rc = pj_timer_heap_create(pool, MAX_COUNT, &timer); if (rc != PJ_SUCCESS) { app_perror("...error: unable to create timer heap", rc); return -30; } count = MIN_COUNT; for (i=0; i<LOOP; ++i) { int early = 0; int done=0; int cancelled=0; int rc; pj_timestamp t1, t2, t_sched, t_cancel, t_poll; pj_time_val now, expire; pj_gettimeofday(&now); pj_srand(now.sec); t_sched.u32.lo = t_cancel.u32.lo = t_poll.u32.lo = 0; // Register timers for (j=0; j<(int)count; ++j) { delay.sec = pj_rand() % DELAY; delay.msec = pj_rand() % 1000; // Schedule timer pj_get_timestamp(&t1); rc = pj_timer_heap_schedule(timer, &entry[j], &delay); if (rc != 0) return -40; pj_get_timestamp(&t2); t_sched.u32.lo += (t2.u32.lo - t1.u32.lo); // Poll timers. pj_get_timestamp(&t1); rc = pj_timer_heap_poll(timer, NULL); pj_get_timestamp(&t2); if (rc > 0) { t_poll.u32.lo += (t2.u32.lo - t1.u32.lo); early += rc; } } // Set the time where all timers should finish pj_gettimeofday(&expire); delay.sec = DELAY; delay.msec = 0; PJ_TIME_VAL_ADD(expire, delay); // Wait unfil all timers finish, cancel some of them. do { int index = pj_rand() % count; pj_get_timestamp(&t1); rc = pj_timer_heap_cancel(timer, &entry[index]); pj_get_timestamp(&t2); if (rc > 0) { cancelled += rc; t_cancel.u32.lo += (t2.u32.lo - t1.u32.lo); } pj_gettimeofday(&now); pj_get_timestamp(&t1); #if defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0 /* On Symbian, we must use OS poll (Active Scheduler poll) since * timer is implemented using Active Object. */ rc = 0; while (pj_symbianos_poll(-1, 0)) ++rc; #else rc = pj_timer_heap_poll(timer, NULL); #endif pj_get_timestamp(&t2); if (rc > 0) { done += rc; t_poll.u32.lo += (t2.u32.lo - t1.u32.lo); } } while (PJ_TIME_VAL_LTE(now, expire)&&pj_timer_heap_count(timer) > 0); if (pj_timer_heap_count(timer)) { PJ_LOG(3, (THIS_FILE, "ERROR: %d timers left", pj_timer_heap_count(timer))); ++err; } t_sched.u32.lo /= count; t_cancel.u32.lo /= count; t_poll.u32.lo /= count; PJ_LOG(4, (THIS_FILE, "...ok (count:%d, early:%d, cancelled:%d, " "sched:%d, cancel:%d poll:%d)", count, early, cancelled, t_sched.u32.lo, t_cancel.u32.lo, t_poll.u32.lo)); count = count * 2; if (count > MAX_COUNT) break; } pj_pool_release(pool); return err; }