src/dpdk/lib/librte_timer/rte_timer.c
static void
__rte_timer_manage(struct rte_timer_data *timer_data)
{
	union rte_timer_status status;
	struct rte_timer *tim, *next_tim;
	struct rte_timer *run_first_tim, **pprev;
	unsigned lcore_id = rte_lcore_id();
	struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1];
	uint64_t cur_time;
	int i, ret;
	struct priv_timer *priv_timer = timer_data->priv_timer;

	/* timer manager only runs on EAL thread with valid lcore_id */
	assert(lcore_id < RTE_MAX_LCORE);

	__TIMER_STAT_ADD(priv_timer, manage, 1);
	/* optimize for the case where per-cpu list is empty */
	if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL)
		return;
	cur_time = rte_get_timer_cycles();

#ifdef RTE_ARCH_64
	/* on 64-bit the value cached in the pending_head.expired will be
	 * updated atomically, so we can consult that for a quick check here
	 * outside the lock */
	if (likely(priv_timer[lcore_id].pending_head.expire > cur_time))
		return;
#endif

	/* browse ordered list, add expired timers in 'expired' list */
	rte_spinlock_lock(&priv_timer[lcore_id].list_lock);

	/* if nothing to do just unlock and return */
	if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL ||
	    priv_timer[lcore_id].pending_head.sl_next[0]->expire > cur_time) {
		rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
		return;
	}

	/* save start of list of expired timers */
	tim = priv_timer[lcore_id].pending_head.sl_next[0];

	/* break the existing list at current time point */
	timer_get_prev_entries(cur_time, lcore_id, prev, priv_timer);
	for (i = priv_timer[lcore_id].curr_skiplist_depth -1; i >= 0; i--) {
		if (prev[i] == &priv_timer[lcore_id].pending_head)
			continue;
		priv_timer[lcore_id].pending_head.sl_next[i] =
		    prev[i]->sl_next[i];
		if (prev[i]->sl_next[i] == NULL)
			priv_timer[lcore_id].curr_skiplist_depth--;
		prev[i] ->sl_next[i] = NULL;
	}

	/* transition run-list from PENDING to RUNNING */
	run_first_tim = tim;
	pprev = &run_first_tim;

	for ( ; tim != NULL; tim = next_tim) {
		next_tim = tim->sl_next[0];

		ret = timer_set_running_state(tim);
		if (likely(ret == 0)) {
			pprev = &tim->sl_next[0];
		} else {
			/* another core is trying to re-config this one,
			 * remove it from local expired list
			 */
			*pprev = next_tim;
		}
	}

	/* update the next to expire timer value */
	priv_timer[lcore_id].pending_head.expire =
	    (priv_timer[lcore_id].pending_head.sl_next[0] == NULL) ? 0 :
		priv_timer[lcore_id].pending_head.sl_next[0]->expire;

	rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);

	/* now scan expired list and call callbacks */
	for (tim = run_first_tim; tim != NULL; tim = next_tim) {
		next_tim = tim->sl_next[0];
		priv_timer[lcore_id].updated = 0;
		priv_timer[lcore_id].running_tim = tim;

		/* execute callback function with list unlocked */
		tim->f(tim, tim->arg);

		__TIMER_STAT_ADD(priv_timer, pending, -1);
		/* the timer was stopped or reloaded by the callback
		 * function, we have nothing to do here */
		if (priv_timer[lcore_id].updated == 1)
			continue;

		if (tim->period == 0) {
			/* remove from done list and mark timer as stopped */
			status.state = RTE_TIMER_STOP;
			status.owner = RTE_TIMER_NO_OWNER;
			/* The "RELEASE" ordering guarantees the memory
			 * operations above the status update are observed
			 * before the update by all threads
			 */
			__atomic_store_n(&tim->status.u32, status.u32,
				__ATOMIC_RELEASE);
		}
		else {
			/* keep it in list and mark timer as pending */
			rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
			status.state = RTE_TIMER_PENDING;
			__TIMER_STAT_ADD(priv_timer, pending, 1);
			status.owner = (int16_t)lcore_id;
			/* The "RELEASE" ordering guarantees the memory
			 * operations above the status update are observed
			 * before the update by all threads
			 */
			__atomic_store_n(&tim->status.u32, status.u32,
				__ATOMIC_RELEASE);
			__rte_timer_reset(tim, tim->expire + tim->period,
				tim->period, lcore_id, tim->f, tim->arg, 1,
				timer_data);
			rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
		}
	}
	priv_timer[lcore_id].running_tim = NULL;
}
/* must be called periodically, run all timer that expired */
must be called periodically, run all timer that expired
must be called periodically run all timer that expired
static void
__rte_timer_manage(struct rte_timer_data *timer_data)
{
	union rte_timer_status status;
	struct rte_timer *tim, *next_tim;
	struct rte_timer *run_first_tim, **pprev;
	unsigned lcore_id = rte_lcore_id();
	struct rte_timer *prev[MAX_SKIPLIST_DEPTH + 1];
	uint64_t cur_time;
	int i, ret;
	struct priv_timer *priv_timer = timer_data->priv_timer;
	assert(lcore_id < RTE_MAX_LCORE);
	__TIMER_STAT_ADD(priv_timer, manage, 1);
	if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL)
		return;
	cur_time = rte_get_timer_cycles();
#ifdef RTE_ARCH_64
	if (likely(priv_timer[lcore_id].pending_head.expire > cur_time))
		return;
#endif
	rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
	if (priv_timer[lcore_id].pending_head.sl_next[0] == NULL ||
	    priv_timer[lcore_id].pending_head.sl_next[0]->expire > cur_time) {
		rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
		return;
	}
	tim = priv_timer[lcore_id].pending_head.sl_next[0];
	timer_get_prev_entries(cur_time, lcore_id, prev, priv_timer);
	for (i = priv_timer[lcore_id].curr_skiplist_depth -1; i >= 0; i--) {
		if (prev[i] == &priv_timer[lcore_id].pending_head)
			continue;
		priv_timer[lcore_id].pending_head.sl_next[i] =
		    prev[i]->sl_next[i];
		if (prev[i]->sl_next[i] == NULL)
			priv_timer[lcore_id].curr_skiplist_depth--;
		prev[i] ->sl_next[i] = NULL;
	}
	run_first_tim = tim;
	pprev = &run_first_tim;
	for ( ; tim != NULL; tim = next_tim) {
		next_tim = tim->sl_next[0];
		ret = timer_set_running_state(tim);
		if (likely(ret == 0)) {
			pprev = &tim->sl_next[0];
		} else {
			*pprev = next_tim;
		}
	}
	priv_timer[lcore_id].pending_head.expire =
	    (priv_timer[lcore_id].pending_head.sl_next[0] == NULL) ? 0 :
		priv_timer[lcore_id].pending_head.sl_next[0]->expire;
	rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
	for (tim = run_first_tim; tim != NULL; tim = next_tim) {
		next_tim = tim->sl_next[0];
		priv_timer[lcore_id].updated = 0;
		priv_timer[lcore_id].running_tim = tim;
		tim->f(tim, tim->arg);
		__TIMER_STAT_ADD(priv_timer, pending, -1);
		if (priv_timer[lcore_id].updated == 1)
			continue;
		if (tim->period == 0) {
			status.state = RTE_TIMER_STOP;
			status.owner = RTE_TIMER_NO_OWNER;
			__atomic_store_n(&tim->status.u32, status.u32,
				__ATOMIC_RELEASE);
		}
		else {
			rte_spinlock_lock(&priv_timer[lcore_id].list_lock);
			status.state = RTE_TIMER_PENDING;
			__TIMER_STAT_ADD(priv_timer, pending, 1);
			status.owner = (int16_t)lcore_id;
			__atomic_store_n(&tim->status.u32, status.u32,
				__ATOMIC_RELEASE);
			__rte_timer_reset(tim, tim->expire + tim->period,
				tim->period, lcore_id, tim->f, tim->arg, 1,
				timer_data);
			rte_spinlock_unlock(&priv_timer[lcore_id].list_lock);
		}
	}
	priv_timer[lcore_id].running_tim = NULL;
}
static void __rte_timer_manage ( struct rte_timer_data * timer_data ) { union rte_timer_status status ; struct rte_timer * tim , * next_tim ; struct rte_timer * run_first_tim , * * pprev ; unsigned lcore_id = rte_lcore_id ( ) ; struct rte_timer * prev [ MAX_SKIPLIST_DEPTH + 1 ] ; uint64_t cur_time ; int i , ret ; struct priv_timer * priv_timer = timer_data -> priv_timer ; assert ( lcore_id < RTE_MAX_LCORE ) ; __TIMER_STAT_ADD ( priv_timer , manage , 1 ) ; if ( priv_timer [ lcore_id ] . pending_head . sl_next [ 0 ] == NULL ) return ; cur_time = rte_get_timer_cycles ( ) ; #ifdef RTE_ARCH_64 if ( likely ( priv_timer [ lcore_id ] . pending_head . expire > cur_time ) ) return ; #endif rte_spinlock_lock ( & priv_timer [ lcore_id ] . list_lock ) ; if ( priv_timer [ lcore_id ] . pending_head . sl_next [ 0 ] == NULL || priv_timer [ lcore_id ] . pending_head . sl_next [ 0 ] -> expire > cur_time ) { rte_spinlock_unlock ( & priv_timer [ lcore_id ] . list_lock ) ; return ; } tim = priv_timer [ lcore_id ] . pending_head . sl_next [ 0 ] ; timer_get_prev_entries ( cur_time , lcore_id , prev , priv_timer ) ; for ( i = priv_timer [ lcore_id ] . curr_skiplist_depth - 1 ; i >= 0 ; i -- ) { if ( prev [ i ] == & priv_timer [ lcore_id ] . pending_head ) continue ; priv_timer [ lcore_id ] . pending_head . sl_next [ i ] = prev [ i ] -> sl_next [ i ] ; if ( prev [ i ] -> sl_next [ i ] == NULL ) priv_timer [ lcore_id ] . curr_skiplist_depth -- ; prev [ i ] -> sl_next [ i ] = NULL ; } run_first_tim = tim ; pprev = & run_first_tim ; for ( ; tim != NULL ; tim = next_tim ) { next_tim = tim -> sl_next [ 0 ] ; ret = timer_set_running_state ( tim ) ; if ( likely ( ret == 0 ) ) { pprev = & tim -> sl_next [ 0 ] ; } else { * pprev = next_tim ; } } priv_timer [ lcore_id ] . pending_head . expire = ( priv_timer [ lcore_id ] . pending_head . sl_next [ 0 ] == NULL ) ? 0 : priv_timer [ lcore_id ] . pending_head . sl_next [ 0 ] -> expire ; rte_spinlock_unlock ( & priv_timer [ lcore_id ] . list_lock ) ; for ( tim = run_first_tim ; tim != NULL ; tim = next_tim ) { next_tim = tim -> sl_next [ 0 ] ; priv_timer [ lcore_id ] . updated = 0 ; priv_timer [ lcore_id ] . running_tim = tim ; tim -> f ( tim , tim -> arg ) ; __TIMER_STAT_ADD ( priv_timer , pending , -1 ) ; if ( priv_timer [ lcore_id ] . updated == 1 ) continue ; if ( tim -> period == 0 ) { status . state = RTE_TIMER_STOP ; status . owner = RTE_TIMER_NO_OWNER ; __atomic_store_n ( & tim -> status . u32 , status . u32 , __ATOMIC_RELEASE ) ; } else { rte_spinlock_lock ( & priv_timer [ lcore_id ] . list_lock ) ; status . state = RTE_TIMER_PENDING ; __TIMER_STAT_ADD ( priv_timer , pending , 1 ) ; status . owner = ( int16_t ) lcore_id ; __atomic_store_n ( & tim -> status . u32 , status . u32 , __ATOMIC_RELEASE ) ; __rte_timer_reset ( tim , tim -> expire + tim -> period , tim -> period , lcore_id , tim -> f , tim -> arg , 1 , timer_data ) ; rte_spinlock_unlock ( & priv_timer [ lcore_id ] . list_lock ) ; } } priv_timer [ lcore_id ] . running_tim = NULL ; }
must be called periodically, run all timer that expired
must be called periodically run all timer that expired
/* timer manager only runs on EAL thread with valid lcore_id */ /* optimize for the case where per-cpu list is empty */ /* on 64-bit the value cached in the pending_head.expired will be
	 * updated atomically, so we can consult that for a quick check here
	 * outside the lock */ /* browse ordered list, add expired timers in 'expired' list */ /* if nothing to do just unlock and return */ /* save start of list of expired timers */ /* break the existing list at current time point */ /* transition run-list from PENDING to RUNNING */ /* another core is trying to re-config this one,
			 * remove it from local expired list
			 */ /* update the next to expire timer value */ /* now scan expired list and call callbacks */ /* execute callback function with list unlocked */ /* the timer was stopped or reloaded by the callback
		 * function, we have nothing to do here */ /* remove from done list and mark timer as stopped */ /* The "RELEASE" ordering guarantees the memory
			 * operations above the status update are observed
			 * before the update by all threads
			 */ /* keep it in list and mark timer as pending */ /* The "RELEASE" ordering guarantees the memory
			 * operations above the status update are observed
			 * before the update by all threads
			 */