/** @internal Block until wait object is signaled or timeout. * * This function waits for wait objects and the timers associated with * the root object. When any wait object is signaled or timer is * expired, it invokes the callbacks. * * This function returns when a callback has been invoked or @c tout * milliseconds is elapsed. * * @param self pointer to port * @param tout timeout in milliseconds * * @return * Milliseconds to the next invocation of timer, or @c SU_WAIT_FOREVER if * there are no active timers. */ su_duration_t su_base_port_step(su_port_t *self, su_duration_t tout) { su_time_t now = su_now(); assert(su_port_own_thread(self)); if (self->sup_prepoll) self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root); if (self->sup_head) self->sup_vtable->su_port_getmsgs(self); if (self->sup_timers) su_timer_expire(&self->sup_timers, &tout, now); /* XXX: why isn't the timeout ignored here? */ if (self->sup_deferrable) su_timer_expire(&self->sup_deferrable, &tout, now); /* if there are messages do a quick wait */ if (self->sup_head) tout = 0; if (self->sup_vtable->su_port_wait_events(self, tout)) tout = 0; else tout = SU_WAIT_FOREVER; if (self->sup_head) { if (self->sup_vtable->su_port_getmsgs(self)) { /* Check for wait events that may have been generated by messages */ if (self->sup_vtable->su_port_wait_events(self, 0)) tout = 0; } } if (self->sup_timers || self->sup_deferrable) { su_duration_t tout2 = SU_WAIT_FOREVER; now = su_now(); su_timer_expire(&self->sup_timers, &tout, now); su_timer_expire(&self->sup_deferrable, &tout2, now); if (tout == SU_WAIT_FOREVER && tout2 != SU_WAIT_FOREVER) { if (tout2 < self->sup_max_defer) tout2 = self->sup_max_defer; tout = tout2; } } if (self->sup_head) tout = 0; return tout; }
/* This version can help tuning... */ void su_base_port_run_tune(su_port_t *self) { int i; int timers = 0, messages = 0, events = 0; su_duration_t tout = 0, tout2 = 0; su_time_t started = su_now(), woken = started, bedtime = woken; assert(su_port_own_thread(self)); for (self->sup_running = 1; self->sup_running;) { tout = self->sup_max_defer; timers = 0, messages = 0; if (self->sup_prepoll) self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root); if (self->sup_head) messages = self->sup_vtable->su_port_getmsgs(self); if (self->sup_timers || self->sup_deferrable) { su_time_t now = su_now(); timers = su_timer_expire(&self->sup_timers, &tout, now) + su_timer_expire(&self->sup_deferrable, &tout2, now); } if (!self->sup_running) break; if (self->sup_head) /* if there are messages do a quick wait */ tout = 0; bedtime = su_now(); events = self->sup_vtable->su_port_wait_events(self, tout); woken = su_now(); if (messages || timers || events) SU_DEBUG_1(("su_port_run(%p): %.6f: %u messages %u timers %u " "events slept %.6f/%.3f\n", self, su_time_diff(woken, started), messages, timers, events, su_time_diff(woken, bedtime), tout * 1e-3)); if (!self->sup_running) break; } }
/** Dump the data from the iovec */ void tport_dump_iovec(tport_t const *self, msg_t *msg, size_t n, su_iovec_t const iov[], size_t iovused, char const *what, char const *how) { tport_master_t *mr; char stamp[128]; size_t i; assert(self); assert(msg); mr = self->tp_master; if (!mr->mr_dump_file) return; tport_stamp(self, msg, stamp, what, n, how, su_now()); fputs(stamp, mr->mr_dump_file); for (i = 0; i < iovused && n > 0; i++) { size_t len = iov[i].mv_len; if (len > n) len = n; if (fwrite(iov[i].mv_base, len, 1, mr->mr_dump_file) != len) break; n -= len; } fputs("\v\n", mr->mr_dump_file); fflush(mr->mr_dump_file); }
/** @internal Main loop. * * The function @c su_port_run() waits for wait objects and the timers * associated with the port object. When any wait object is signaled or * timer is expired, it invokes the callbacks, and returns waiting. * * The function @c su_port_run() runs until @c su_port_break() is called * from a callback. * * @param self pointer to port object * */ void su_base_port_run(su_port_t *self) { su_duration_t tout = 0, tout2 = 0; assert(su_port_own_thread(self)); for (self->sup_running = 1; self->sup_running;) { tout = self->sup_max_defer; if (self->sup_prepoll) self->sup_prepoll(self->sup_pp_magic, self->sup_pp_root); if (self->sup_head) self->sup_vtable->su_port_getmsgs(self); if (self->sup_timers || self->sup_deferrable) { su_time_t now = su_now(); su_timer_expire(&self->sup_timers, &tout, now); su_timer_expire(&self->sup_deferrable, &tout2, now); } if (!self->sup_running) break; if (self->sup_head) /* if there are messages do a quick wait */ tout = 0; self->sup_vtable->su_port_wait_events(self, tout); } }
/** Get current timestamp in milliseconds */ su_inline uint32_t server_now(server_t const *srv) { if (srv->srv_now) return srv->srv_now; else return su_time_ms(su_now()); }
/** Get current timestamp in milliseconds */ static uint32_t he_now(nth_engine_t const *he) { if (he->he_now) return he->he_now; else return su_time_ms(su_now()); }
/**Run event and message loop for given duration. * * The function su_root_sleep() runs event loop for @a duration milliseconds. * The event loop waits for wait objects and the timers associated with the * @a root object. When any wait object is signaled, timer is expired, or * message is received, it invokes the callbacks and returns waiting. * * @param self pointer to root object * @param duration milliseconds to run event loop * * @retval milliseconds until next timer expiration */ su_duration_t su_root_sleep(su_root_t *self, su_duration_t duration) { su_duration_t retval, accrued = 0; su_time_t started; if (self == NULL) return (void)(errno = EFAULT), SU_WAIT_FOREVER; assert(self->sur_port); started = su_now(); do { retval = su_port_step(self->sur_port, duration - accrued); accrued = su_duration(su_now(), started); } while (accrued < duration); return retval; }
/** * Server timer routine. */ static void server_timer(su_root_magic_t *rm, su_timer_t *timer, server_t *srv) { uint32_t now; su_timer_set(timer, server_timer, srv); now = su_time_ms(su_now()); now += now == 0; srv->srv_now = now; /* Xyzzy */ srv->srv_now = 0; }
void print_stamp(struct tester *x, su_timer_t *t, struct timing *ti) { su_time_t now = su_now(), prev = ti->t_prev; ti->t_prev = now; printf("timer interval %f\n", 1000 * su_time_diff(now, prev)); if (!ti->t_run) su_timer_set(t, print_stamp, ti); if (++ti->t_times >= 10) su_timer_reset(t); }
/** * Engine timer routine. */ static void he_timer(su_root_magic_t *rm, su_timer_t *timer, nth_engine_t * he) { unsigned i; uint32_t now; hc_htable_t *hct = he->he_clients; now = su_time_ms(su_now()); now += now == 0; he->he_now = now; if (hct) for (i = hct->hct_size; i > 0;) if (hct->hct_table[--i]) hc_timer(he, hct->hct_table[i], now); su_timer_set(timer, he_timer, he); he->he_now = 0; }
/* * 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; }
TimerEventHandle TimerQueue::add( TimerFunc f, void* functionArgs, uint32_t milliseconds ) { return add( f, functionArgs, milliseconds, su_now() ) ; }
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)) ; }
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)) ; }