static int lw_ethtool_event_watch_port_changed(struct teamd_context *ctx, struct teamd_port *tdport, void *priv) { struct lw_common_port_priv *common_ppriv = priv; struct lw_ethtool_port_priv *ethtool_ppriv = priv; bool link_up; struct timespec *delay; int err; if (common_ppriv->tdport != tdport || !team_is_port_changed(tdport->team_port)) return 0; /* * Link changed for sure, so if there is some delay in progress, * cancel it before proceeding. */ teamd_loop_callback_disable(ctx, LW_ETHTOOL_DELAY_CB_NAME, priv); link_up = team_is_port_link_up(tdport->team_port); if (!teamd_link_watch_link_up_differs(common_ppriv, link_up)) return 0; if (link_up) { if (timespec_is_zero(ðtool_ppriv->delay_up)) goto nodelay; delay = ðtool_ppriv->delay_up; } else { if (timespec_is_zero(ðtool_ppriv->delay_down)) goto nodelay; delay = ðtool_ppriv->delay_down; } err = teamd_loop_callback_timer_set(ctx, LW_ETHTOOL_DELAY_CB_NAME, priv, NULL, delay); if (err) { teamd_log_err("Failed to set delay timer."); return err; } teamd_loop_callback_enable(ctx, LW_ETHTOOL_DELAY_CB_NAME, priv); return 0; nodelay: return teamd_link_watch_check_link_up(ctx, tdport, common_ppriv, link_up); }
int timer_settime( timer_t id, int flags, const struct itimerspec* spec, struct itimerspec* ospec ) { if (spec == NULL) { errno = EINVAL; return -1; } if ( __likely(!TIMER_ID_IS_WRAPPED(id)) ) { return __timer_settime( id, flags, spec, ospec ); } else { thr_timer_t* timer = thr_timer_from_id(id); struct timespec expires, now; if (timer == NULL) { errno = EINVAL; return -1; } thr_timer_lock(timer); /* return current timer value if ospec isn't NULL */ if (ospec != NULL) { timer_gettime_internal(timer, ospec ); } /* compute next expiration time. note that if the * new it_interval is 0, we should disarm the timer */ expires = spec->it_value; if (!timespec_is_zero(&expires)) { clock_gettime( timer->clock, &now ); if (!(flags & TIMER_ABSTIME)) { timespec_add(&expires, &now); } else { if (timespec_cmp(&expires, &now) < 0) expires = now; } } timer->expires = expires; timer->period = spec->it_interval; thr_timer_unlock( timer ); /* signal the change to the thread */ pthread_cond_signal( &timer->cond ); } return 0; }
/* return the relative time until the next expiration, or 0 if * the timer is disarmed */ static void timer_gettime_internal( thr_timer_t* timer, struct itimerspec* spec) { struct timespec diff; diff = timer->expires; if (!timespec_is_zero(&diff)) { struct timespec now; clock_gettime( timer->clock, &now ); timespec_sub(&diff, &now); /* in case of overrun, return 0 */ if (timespec_cmp0(&diff) < 0) { timespec_zero(&diff); } } spec->it_value = diff; spec->it_interval = timer->period; }
static void* timer_thread_start( void* _arg ) { thr_timer_t* timer = _arg; thr_timer_lock( timer ); /* we loop until timer->done is set in timer_delete() */ while (!timer->done) { struct timespec expires = timer->expires; struct timespec period = timer->period; struct timespec now; /* if the timer is stopped or disarmed, wait indefinitely * for a state change from timer_settime/_delete/_start_stop */ if ( timer->stopped || timespec_is_zero(&expires) ) { pthread_cond_wait( &timer->cond, &timer->mutex ); continue; } /* otherwise, we need to do a timed wait until either a * state change of the timer expiration time. */ clock_gettime(timer->clock, &now); if (timespec_cmp( &expires, &now ) > 0) { /* cool, there was no overrun, so compute the * relative timeout as 'expires - now', then wait */ int ret; struct timespec diff = expires; timespec_sub( &diff, &now ); ret = __pthread_cond_timedwait_relative( &timer->cond, &timer->mutex, &diff); /* if we didn't timeout, it means that a state change * occured, so reloop to take care of it. */ if (ret != ETIMEDOUT) continue; } else { /* overrun was detected before we could wait ! */ if (!timespec_is_zero( &period ) ) { /* for periodic timers, compute total overrun count */ do { timespec_add( &expires, &period ); if (timer->overruns < DELAYTIMER_MAX) timer->overruns += 1; } while ( timespec_cmp( &expires, &now ) < 0 ); /* backtrack the last one, because we're going to * add the same value just a bit later */ timespec_sub( &expires, &period ); } else { /* for non-periodic timer, things are simple */ timer->overruns = 1; } } /* if we get there, a timeout was detected. * first reload/disarm the timer has needed */ if ( !timespec_is_zero(&period) ) { timespec_add( &expires, &period ); } else { timespec_zero( &expires ); } timer->expires = expires; /* now call the timer callback function. release the * lock to allow the function to modify the timer setting * or call timer_getoverrun(). * * NOTE: at this point we trust the callback not to be a * total moron and pthread_kill() the timer thread */ thr_timer_unlock(timer); timer->callback( timer->value ); thr_timer_lock(timer); /* now clear the overruns counter. it only makes sense * within the callback */ timer->overruns = 0; } thr_timer_unlock( timer ); /* free the timer object now. there is no need to call * __timer_table_get() since we're guaranteed that __timer_table * is initialized in this thread */ thr_timer_table_free(__timer_table, timer); return NULL; }