/* * test su_timer functionality: * * Create a timer, executing print_stamp() in every 20 ms */ int main(int argc, char *argv[]) { su_root_t *root; su_timer_t *t, *t1, *t_end; su_timer_t **timers; su_duration_t interval = 60; char *argv0 = argv[0]; char *s; int use_t1 = 0; su_time_t now, started; intptr_t i, N = 500; GSource *source; struct timing timing[1] = {{ 0 }}; struct tester tester[1] = {{ 0 }}; while (argv[1] && argv[1][0] == '-') { char *o = argv[1] + 1; while (*o) { if (*o == '1') o++, use_t1 = 1; else if (*o == 'r') o++, timing->t_run = 1; else if (*o == 'N') { if (o[1]) N = strtoul(o + 1, &o, 0); else if (argv[2]) N = strtoul(argv++[2], &o, 0); break; } else break; } if (*o) usage(argv0); argv++; } if (argv[1]) { interval = strtoul(argv[1], &s, 10); if (interval == 0 || s == argv[1]) usage(argv0); } su_init(); atexit(su_deinit); tester->root = root = su_glib_root_create(tester); source = su_root_gsource(tester->root); g_source_attach(source, NULL /*g_main_context_default ()*/); su_msg_create(intr_msg, su_root_task(root), su_root_task(root), test_break, 0); signal(SIGINT, intr_handler); #if HAVE_SIGPIPE signal(SIGPIPE, intr_handler); signal(SIGQUIT, intr_handler); signal(SIGHUP, intr_handler); #endif t = su_timer_create(su_root_task(root), interval); t1 = su_timer_create(su_root_task(root), 1); t_end = su_timer_create(su_root_task(root), 20 * interval); if (t == NULL || t1 == NULL || t_end == NULL) su_perror("su_timer_create"), exit(1); tester->t = t, tester->t1 = t1; timing->t_prev = su_now(); if (timing->t_run) su_timer_run(t, print_stamp, timing); else su_timer_set(t, print_stamp, timing); if (use_t1) su_timer_set(t1, print_X, NULL); su_timer_set(t_end, end_test, NULL); su_root_run(root); su_msg_destroy(intr_msg); su_timer_destroy(t); su_timer_destroy(t1); if (timing->t_times != 10) { fprintf(stderr, "%s: t expired %d times (expecting 10)\n", argv0, timing->t_times); return 1; } /* Insert timers in order */ timers = calloc(N, sizeof *timers); if (!timers) { perror("calloc"); exit(1); } now = started = su_now(); for (i = 0; i < N; i++) { t = su_timer_create(su_root_task(root), 1000); if (!t) { perror("su_timer_create"); exit(1); } if (++now.tv_usec == 0) ++now.tv_sec; su_timer_set_at(t, increment, (void *)i, now); timers[i] = t; } tester->sentinel = (void*)(i - 1); su_root_run(root); printf("Processing %u timers took %f millisec (%f expected)\n", (unsigned)i, su_time_diff(su_now(), started) * 1000, (double)i / 1000); for (i = 0; i < N; i++) { su_timer_destroy(timers[i]); } su_root_destroy(root); su_deinit(); return 0; }
void TimerQueue::doTimer(su_timer_t* timer) { //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; #ifndef TEST DR_LOG(log_debug) << m_name << ": running timer function" ; #endif //std::cout << "doTimer: running timer function with " << m_length << " timers queued " << std::endl; if( m_in_timer ) return ; m_in_timer = 1 ; queueEntry_t* expired = NULL ; queueEntry_t* tailExpired = NULL ; su_time_t now = su_now() ; assert( NULL != m_head ) ; queueEntry_t* ptr = m_head ; while( ptr && su_time_cmp( ptr->m_when, now ) < 0 ) { //std::cout << "expiring a timer" << std::endl ; m_length-- ; m_head = ptr->m_next ; if( m_head ) m_head->m_prev = NULL ; else m_tail = NULL ; //detach and assemble them into a new queue temporarily if( !expired ) { expired = tailExpired = ptr ; ptr->m_prev = ptr->m_next = NULL ; } else { tailExpired->m_next = ptr ; ptr->m_prev = tailExpired ; tailExpired = ptr ; } ptr = ptr->m_next ; } if( NULL == m_head ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": timer not set (queue is empty after processing expired timers), length: " << dec << m_length ; #endif //std::cout << "doTimer: timer not set (queue is empty after processing expired timers)" << std::endl; assert( 0 == m_length ) ; } else { //std::cout << "doTimer: Setting timer for " << su_duration( m_head->m_when, su_now() ) << "ms after processing expired timers" << std::endl; #ifndef TEST DR_LOG(log_debug) << m_name << ": Setting timer for " << su_duration( m_head->m_when, su_now() ) << "ms after processing expired timers, length: " << dec << m_length ; #endif int rc = su_timer_set_at(m_timer, timer_function, this, m_head->m_when); } m_in_timer = 0 ; while( NULL != expired ) { expired->m_function( expired->m_functionArgs ) ; queueEntry_t* p = expired ; expired = expired->m_next ; delete p ; } //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; }
TimerEventHandle TimerQueue::add( TimerFunc f, void* functionArgs, uint32_t milliseconds, su_time_t now ) { //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; su_time_t when = su_time_add(now, milliseconds) ; queueEntry_t* entry = new queueEntry_t(this, f, functionArgs, when) ; TimerEventHandle handle = entry ; assert(handle) ; int queueLength ; if( entry ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to go off in " << std::dec << milliseconds << "ms" ; #endif //std::cout << "Adding entry to go off in " << milliseconds << "ms" << std::endl; if( NULL == m_head ) { assert( NULL == m_tail ) ; m_head = m_tail = entry; #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to the head (queue was empty), length: " << dec << m_length+1 ; #endif //std::cout << "Adding entry to the head of the queue (it was empty)" << std::endl ; } else if( NULL != m_tail && su_time_cmp( when, m_tail->m_when ) > 0) { //one class of timer queues will always be appending entries, so check the tail //before starting to iterate through #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to the tail of the queue: length " << dec << m_length+1; #endif //std::cout << "Adding entry to the tail of the queue" << std::endl ; entry->m_prev = m_tail ; m_tail->m_next = entry ; m_tail = entry ; } else { //iterate queueEntry_t* ptr = m_head ; int idx = 0 ; do { if( su_time_cmp( when, ptr->m_when ) < 0) { #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry at position " << std::dec << idx << " of the queue, length: " << dec << m_length+1 ; #endif //std::cout << "Adding entry at position " << idx << " of the queue" << std::endl ; entry->m_next = ptr ; if( 0 == idx ) { m_head = entry ; } else { entry->m_prev = ptr->m_prev ; ptr->m_prev->m_next = entry ; } ptr->m_prev = entry ; break ; } idx++ ; } while( NULL != (ptr = ptr->m_next) ) ; assert( NULL != ptr ) ; /* if( NULL == ptr ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": Adding entry to the tail of the queue: length " << dec << m_length+1; #endif //std::cout << "Adding entry to the tail of the queue" << std::endl ; entry->m_prev = m_tail ; m_tail->m_next = entry ; m_tail = entry ; } */ } queueLength = ++m_length ; } else { //DR_LOG(log_error) << "Error allocating queue entry" ; //std::cerr << "Error allocating queue entry" << std::endl ; return NULL ; } //only need to set the timer if we added to the front if( m_head == entry ) { //DR_LOG(log_debug) << "timer add: Setting timer for " << milliseconds << "ms" ; //std::cout << "timer add: Setting timer for " << milliseconds << "ms" << std::endl; int rc = su_timer_set_at(m_timer, timer_function, this, when); assert( 0 == rc ) ; } //DR_LOG(log_debug) << "timer add: queue length is now " << queueLength ; //std::cout << "timer add: queue length is now " << queueLength << std::endl; //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; return handle ; }
void TimerQueue::remove( TimerEventHandle entry) { #ifndef TEST DR_LOG(log_debug) << m_name << ": removing entry, prior to removal length: " << dec << m_length; #endif //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; assert( m_head && m_length >= 1 ) ; int queueLength ; { if( m_head == entry ) { m_head = entry->m_next ; if( m_head ) m_head->m_prev = NULL ; else { assert( 1 == m_length ) ; m_tail = NULL ; } } else if( m_tail == entry ) { assert( m_head && entry->m_prev ) ; m_tail = entry->m_prev ; m_tail->m_next = NULL ; } else { assert( entry->m_prev ) ; assert( entry->m_next ) ; entry->m_prev->m_next = entry->m_next ; entry->m_next->m_prev = entry->m_prev ; } m_length-- ; assert( m_length >= 0 ) ; if( NULL == m_head ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": removed entry, timer not set (queue is empty after removal), length: " << dec << m_length; #endif //std::cout << "timer not set (queue is empty after removal)" << std::endl; su_timer_reset( m_timer ) ; } else if( m_head == entry->m_next ) { #ifndef TEST DR_LOG(log_debug) << m_name << ": removed entry, setting timer for " << std::dec << su_duration( m_head->m_when, su_now() ) << "ms after removal, length: " << dec << m_length; #endif //std::cout << "Setting timer for " << su_duration( m_head->m_when, su_now() ) << "ms after removal of head entry" << std::endl; int rc = su_timer_set_at(m_timer, timer_function, this, m_head->m_when); } } //DR_LOG(log_debug) << "timer remove: queue length is now " << queueLength ; //std::cout << "timer remove: queue length is now " << queueLength << std::endl; delete entry ; //self check assert( m_length == numberOfElements()) ; assert( 0 != m_length || (NULL == m_head && NULL == m_tail) ) ; assert( 1 != m_length || (m_head == m_tail)) ; assert( m_length < 2 || (m_head != m_tail)) ; assert( !(NULL == m_head && NULL != m_tail)) ; assert( !(NULL == m_tail && NULL != m_head)) ; }