/* * This is not really a fixup. The timer was * statically initialized. We just make sure that it * is tracked in the object tracker. */ debug_object_init(timer, &timer_debug_descr); return 0; } else { setup_timer(timer, stub_timer, 0); return 1; } default: return 0; }} static struct debug_obj_descr timer_debug_descr = { .name = "timer_list", .debug_hint = timer_debug_hint, .fixup_init = timer_fixup_init, .fixup_activate = timer_fixup_activate, .fixup_free = timer_fixup_free, .fixup_assert_init = timer_fixup_assert_init,}; static inline void debug_timer_init(struct timer_list *timer){ debug_object_init(timer, &timer_debug_descr);} static inline void debug_timer_activate(struct timer_list *timer){ debug_object_activate(timer, &timer_debug_descr);} static inline void debug_timer_deactivate(struct timer_list *timer){ debug_object_deactivate(timer, &timer_debug_descr);} static inline void debug_timer_free(struct timer_list *timer){ debug_object_free(timer, &timer_debug_descr);} static inline void debug_timer_assert_init(struct timer_list *timer){ debug_object_assert_init(timer, &timer_debug_descr);} static void __init_timer(struct timer_list *timer, const char *name, struct lock_class_key *key); void init_timer_on_stack_key(struct timer_list *timer, const char *name, struct lock_class_key *key){ debug_object_init_on_stack(timer, &timer_debug_descr); __init_timer(timer, name, key);}EXPORT_SYMBOL_GPL(init_timer_on_stack_key); void destroy_timer_on_stack(struct timer_list *timer){ debug_object_free(timer, &timer_debug_descr);}EXPORT_SYMBOL_GPL(destroy_timer_on_stack); #elsestatic inline void debug_timer_init(struct timer_list *timer) { }static inline void debug_timer_activate(struct timer_list *timer) { }static inline void debug_timer_deactivate(struct timer_list *timer) { }static inline void debug_timer_assert_init(struct timer_list *timer) { }#endif static inline void debug_init(struct timer_list *timer){ debug_timer_init(timer); trace_timer_init(timer);} static inline voiddebug_activate(struct timer_list *timer, unsigned long expires){ debug_timer_activate(timer); trace_timer_start(timer, expires);} static inline void debug_deactivate(struct timer_list *timer){ debug_timer_deactivate(timer); trace_timer_cancel(timer);} static inline void debug_assert_init(struct timer_list *timer){ debug_timer_assert_init(timer);} static void __init_timer(struct timer_list *timer, const char *name, struct lock_class_key *key){ timer->entry.next = NULL; timer->base = __raw_get_cpu_var(tvec_bases); timer->slack = -1;#ifdef CONFIG_TIMER_STATS timer->start_site = NULL; timer->start_pid = -1; memset(timer->start_comm, 0, TASK_COMM_LEN);#endif lockdep_init_map(&timer->lockdep_map, name, key, 0);} void setup_deferrable_timer_on_stack_key(struct timer_list *timer, const char *name, struct lock_class_key *key, void (*function)(unsigned long), unsigned long data){ timer->function = function; timer->data = data; init_timer_on_stack_key(timer, name, key); timer_set_deferrable(timer);}EXPORT_SYMBOL_GPL(setup_deferrable_timer_on_stack_key); /** * init_timer_key - initialize a timer * @timer: the timer to be initialized * @name: name of the timer * @key: lockdep class key of the fake lock used for tracking timer * sync lock dependencies * * init_timer_key() must be done to a timer prior calling *any* of the * other timer functions. */void init_timer_key(struct timer_list *timer, const char *name, struct lock_class_key *key){ debug_init(timer); __init_timer(timer, name, key);}EXPORT_SYMBOL(init_timer_key); void init_timer_deferrable_key(struct timer_list *timer, const char *name, struct lock_class_key *key){ init_timer_key(timer, name, key); timer_set_deferrable(timer);}EXPORT_SYMBOL(init_timer_deferrable_key); static inline void detach_timer(struct timer_list *timer, int clear_pending){ struct list_head *entry = &timer->entry; debug_deactivate(timer); __list_del(entry->prev, entry->next); if (clear_pending) entry->next = NULL; entry->prev = LIST_POISON2;} /* * We are using hashed locking: holding per_cpu(tvec_bases).lock * means that all timers which are tied to this base via timer->base are * locked, and the base itself is locked too. * * So __run_timers/migrate_timers can safely modify all timers which could * be found on ->tvX lists. * * When the timer's base is locked, and the timer removed from list, it is * possible to set timer->base = NULL and drop the lock: the timer remains * locked. */static struct tvec_base *lock_timer_base(struct timer_list *timer, unsigned long *flags) __acquires(timer->base->lock){ struct tvec_base *base; for (;;) { struct tvec_base *prelock_base = timer->base; base = tbase_get_base(prelock_base); if (likely(base != NULL)) { spin_lock_irqsave(&base->lock, *flags); if (likely(prelock_base == timer->base)) return base; /* The timer has migrated to another CPU */ spin_unlock_irqrestore(&base->lock, *flags); } cpu_relax(); }} static inline int__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only, int pinned){ struct tvec_base *base, *new_base; unsigned long flags; int ret = 0 , cpu; timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); base = lock_timer_base(timer, &flags); if (timer_pending(timer)) { detach_timer(timer, 0); if (timer->expires == base->next_timer && !tbase_get_deferrable(timer->base)) base->next_timer = base->timer_jiffies; ret = 1; } else { if (pending_only) goto out_unlock; } debug_activate(timer, expires); cpu = smp_processor_id(); #if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) cpu = get_nohz_timer_target();#endif new_base = per_cpu(tvec_bases, cpu); if (base != new_base) { /* * We are trying to schedule the timer on the local CPU. * However we can't change timer's base while it is running, * otherwise del_timer_sync() can't detect that the timer's * handler yet has not finished. This also guarantees that * the timer is serialized wrt itself. */ if (likely(base->running_timer != timer)) { /* See the comment in lock_timer_base() */ timer_set_base(timer, NULL); spin_unlock(&base->lock); base = new_base; spin_lock(&base->lock); timer_set_base(timer, base); } } timer->expires = expires; if (time_before(timer->expires, base->next_timer) && !tbase_get_deferrable(timer->base)) base->next_timer = timer->expires; internal_add_timer(base, timer); out_unlock: spin_unlock_irqrestore(&base->lock, flags); return ret;} /** * mod_timer_pending - modify a pending timer's timeout * @timer: the pending timer to be modified * @expires: new timeout in jiffies * * mod_timer_pending() is the same for pending timers as mod_timer(), * but will not re-activate and modify already deleted timers. * * It is useful for unserialized use of timers. */int mod_timer_pending(struct timer_list *timer, unsigned long expires){ return __mod_timer(timer, expires, true, TIMER_NOT_PINNED);}EXPORT_SYMBOL(mod_timer_pending); /* * Decide where to put the timer while taking the slack into account * * Algorithm: * 1) calculate the maximum (absolute) time * 2) calculate the highest bit where the expires and new max are different * 3) use this bit to make a mask * 4) use the bitmask to round down the maximum time, so that all last * bits are zeros */static inlineunsigned long apply_slack(struct timer_list *timer, unsigned long expires){ unsigned long expires_limit, mask; int bit; if (timer->slack >= 0) { expires_limit = expires + timer->slack; } else { long delta = expires - jiffies; if (delta < 256) return expires; expires_limit = expires + delta / 256; } mask = expires ^ expires_limit; if (mask == 0) return expires; bit = find_last_bit(&mask, BITS_PER_LONG); mask = (1 << bit) - 1; expires_limit = expires_limit & ~(mask); return expires_limit;} /** * mod_timer - modify a timer's timeout * @timer: the timer to be modified * @expires: new timeout in jiffies * * mod_timer() is a more efficient way to update the expire field of an * active timer (if the timer is inactive it will be activated) * * mod_timer(timer, expires) is equivalent to: * * del_timer(timer); timer->expires = expires; add_timer(timer); * * Note that if there are multiple unserialized concurrent users of the * same timer, then mod_timer() is the only safe way to modify the timeout, * since add_timer() cannot modify an already running timer. * * The function returns whether it has modified a pending timer or not. * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an * active timer returns 1.) */int mod_timer(struct timer_list *timer, unsigned long expires){ expires = apply_slack(timer, expires); /* * This is a common optimization triggered by the * networking code - if the timer is re-modified * to be the same thing then just return: */ if (timer_pending(timer) && timer->expires == expires) return 1; return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);}EXPORT_SYMBOL(mod_timer); /** * mod_timer_pinned - modify a timer's timeout * @timer: the timer to be modified * @expires: new timeout in jiffies * * mod_timer_pinned() is a way to update the expire field of an * active timer (if the timer is inactive it will be activated) * and to ensure that the timer is scheduled on the current CPU. * * Note that this does not prevent the timer from being migrated * when the current CPU goes offline. If this is a problem for * you, use CPU-hotplug notifiers to handle it correctly, for * example, cancelling the timer when the corresponding CPU goes * offline. * * mod_timer_pinned(timer, expires) is equivalent to: * * del_timer(timer); timer->expires = expires; add_timer(timer); */int mod_timer_pinned(struct timer_list *timer, unsigned long expires){ if (timer->expires == expires && timer_pending(timer)) return 1; return __mod_timer(timer, expires, false, TIMER_PINNED);}EXPORT_SYMBOL(mod_timer_pinned); /** * add_timer - start a timer * @timer: the timer to be added * * The kernel will do a ->function(->data) callback from the * timer interrupt at the ->expires point in the future. The * current time is 'jiffies'. * * The timer's ->expires, ->function (and if the handler uses it, ->data) * fields must be set prior calling this function. * * Timers with an ->expires field in the past will be executed in the next * timer tick. */void add_timer(struct timer_list *timer){ BUG_ON(timer_pending(timer)); mod_timer(timer, timer->expires);}EXPORT_SYMBOL(add_timer); /** * add_timer_on - start a timer on a particular CPU * @timer: the timer to be added * @cpu: the CPU to start it on * * This is not very scalable on SMP. Double adds are not possible. */void add_timer_on(struct timer_list *timer, int cpu){ struct tvec_base *base = per_cpu(tvec_bases, cpu); unsigned long flags; timer_stats_timer_set_start_info(timer); BUG_ON(timer_pending(timer) || !timer->function); spin_lock_irqsave(&base->lock, flags); timer_set_base(timer, base); debug_activate(timer, timer->expires); if (time_before(timer->expires, base->next_timer) && !tbase_get_deferrable(timer->base)) base->next_timer = timer->expires; internal_add_timer(base, timer); /* * Check whether the other CPU is idle and needs to be * triggered to reevaluate the timer wheel when nohz is * active. We are protected against the other CPU fiddling * with the timer by holding the timer base lock. This also * makes sure that a CPU on the way to idle can not evaluate * the timer wheel. */ wake_up_idle_cpu(cpu); spin_unlock_irqrestore(&base->lock, flags);}EXPORT_SYMBOL_GPL(add_timer_on); /** * del_timer - deactive a timer. * @timer: the timer to be deactivated * * del_timer() deactivates a timer - this works on both active and inactive * timers. * * The function returns whether it has deactivated a pending timer or not. * (ie. del_timer() of an inactive timer returns 0, del_timer() of an * active timer returns 1.) */int del_timer(struct timer_list *timer){ struct tvec_base *base; unsigned long flags; int ret = 0; debug_assert_init(timer); timer_stats_timer_clear_start_info(timer); if (timer_pending(timer)) { base = lock_timer_base(timer, &flags); if (timer_pending(timer)) { detach_timer(timer, 1); if (timer->expires == base->next_timer && !tbase_get_deferrable(timer->base)) base->next_timer = base->timer_jiffies; ret = 1; } spin_unlock_irqrestore(&base->lock, flags); } return ret;}EXPORT_SYMBOL(del_timer); /** * try_to_del_timer_sync - Try to deactivate a timer * @timer: timer do del * * This function tries to deactivate a timer. Upon successful (ret >= 0) * exit the timer is not queued and the handler is not running on any CPU. */int try_to_del_timer_sync(struct timer_list *timer){ struct tvec_base *base; unsigned long flags; int ret = -1; debug_assert_init(timer); base = lock_timer_base(timer, &flags); if (base->running_timer == timer) goto out; timer_stats_timer_clear_start_info(timer); ret = 0; if (timer_pending(timer)) { detach_timer(timer, 1); if (timer->expires == base->next_timer &&Lines 501–1000 of 1850. Previous lines Load more
/* * This is not really a fixup. The timer was * statically initialized. We just make sure that it * is tracked in the object tracker. */ debug_object_init(timer, &timer_debug_descr); return 0; } else { setup_timer(timer, stub_timer, 0); return 1; } default: return 0; } } static struct debug_obj_descr timer_debug_descr = { .name = "timer_list", .debug_hint = timer_debug_hint, .fixup_init = timer_fixup_init, .fixup_activate = timer_fixup_activate, .fixup_free = timer_fixup_free, .fixup_assert_init = timer_fixup_assert_init, }; static inline void debug_timer_init(struct timer_list *timer) { debug_object_init(timer, &timer_debug_descr); } static inline void debug_timer_activate(struct timer_list *timer) { debug_object_activate(timer, &timer_debug_descr); } static inline void debug_timer_deactivate(struct timer_list *timer) { debug_object_deactivate(timer, &timer_debug_descr); } static inline void debug_timer_free(struct timer_list *timer) { debug_object_free(timer, &timer_debug_descr); } static inline void debug_timer_assert_init(struct timer_list *timer) { debug_object_assert_init(timer, &timer_debug_descr); } static void __init_timer(struct timer_list *timer, const char *name, struct lock_class_key *key); void init_timer_on_stack_key(struct timer_list *timer, const char *name, struct lock_class_key *key) { debug_object_init_on_stack(timer, &timer_debug_descr); __init_timer(timer, name, key); } EXPORT_SYMBOL_GPL(init_timer_on_stack_key); void destroy_timer_on_stack(struct timer_list *timer) { debug_object_free(timer, &timer_debug_descr); } EXPORT_SYMBOL_GPL(destroy_timer_on_stack); #else static inline void debug_timer_init(struct timer_list *timer) { } static inline void debug_timer_activate(struct timer_list *timer) { } static inline void debug_timer_deactivate(struct timer_list *timer) { } static inline void debug_timer_assert_init(struct timer_list *timer) { } #endif static inline void debug_init(struct timer_list *timer) { debug_timer_init(timer); trace_timer_init(timer); } static inline void debug_activate(struct timer_list *timer, unsigned long expires) { debug_timer_activate(timer); trace_timer_start(timer, expires); } static inline void debug_deactivate(struct timer_list *timer) { debug_timer_deactivate(timer); trace_timer_cancel(timer); } static inline void debug_assert_init(struct timer_list *timer) { debug_timer_assert_init(timer); } static void __init_timer(struct timer_list *timer, const char *name, struct lock_class_key *key) { timer->entry.next = NULL; timer->base = __raw_get_cpu_var(tvec_bases); timer->slack = -1; #ifdef CONFIG_TIMER_STATS timer->start_site = NULL; timer->start_pid = -1; memset(timer->start_comm, 0, TASK_COMM_LEN); #endif lockdep_init_map(&timer->lockdep_map, name, key, 0); } void setup_deferrable_timer_on_stack_key(struct timer_list *timer, const char *name, struct lock_class_key *key, void (*function)(unsigned long), unsigned long data) { timer->function = function; timer->data = data; init_timer_on_stack_key(timer, name, key); timer_set_deferrable(timer); } EXPORT_SYMBOL_GPL(setup_deferrable_timer_on_stack_key); /** * init_timer_key - initialize a timer * @timer: the timer to be initialized * @name: name of the timer * @key: lockdep class key of the fake lock used for tracking timer * sync lock dependencies * * init_timer_key() must be done to a timer prior calling *any* of the * other timer functions. */ void init_timer_key(struct timer_list *timer, const char *name, struct lock_class_key *key) { debug_init(timer); __init_timer(timer, name, key); } EXPORT_SYMBOL(init_timer_key); void init_timer_deferrable_key(struct timer_list *timer, const char *name, struct lock_class_key *key) { init_timer_key(timer, name, key); timer_set_deferrable(timer); } EXPORT_SYMBOL(init_timer_deferrable_key); static inline void detach_timer(struct timer_list *timer, int clear_pending) { struct list_head *entry = &timer->entry; debug_deactivate(timer); __list_del(entry->prev, entry->next); if (clear_pending) entry->next = NULL; entry->prev = LIST_POISON2; } /* * We are using hashed locking: holding per_cpu(tvec_bases).lock * means that all timers which are tied to this base via timer->base are * locked, and the base itself is locked too. * * So __run_timers/migrate_timers can safely modify all timers which could * be found on ->tvX lists. * * When the timer's base is locked, and the timer removed from list, it is * possible to set timer->base = NULL and drop the lock: the timer remains * locked. */ static struct tvec_base *lock_timer_base(struct timer_list *timer, unsigned long *flags) __acquires(timer->base->lock) { struct tvec_base *base; for (;;) { struct tvec_base *prelock_base = timer->base; base = tbase_get_base(prelock_base); if (likely(base != NULL)) { spin_lock_irqsave(&base->lock, *flags); if (likely(prelock_base == timer->base)) return base; /* The timer has migrated to another CPU */ spin_unlock_irqrestore(&base->lock, *flags); } cpu_relax(); } } static inline int __mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only, int pinned) { struct tvec_base *base, *new_base; unsigned long flags; int ret = 0 , cpu; timer_stats_timer_set_start_info(timer); BUG_ON(!timer->function); base = lock_timer_base(timer, &flags); if (timer_pending(timer)) { detach_timer(timer, 0); if (timer->expires == base->next_timer && !tbase_get_deferrable(timer->base)) base->next_timer = base->timer_jiffies; ret = 1; } else { if (pending_only) goto out_unlock; } debug_activate(timer, expires); cpu = smp_processor_id(); #if defined(CONFIG_NO_HZ) && defined(CONFIG_SMP) if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu)) cpu = get_nohz_timer_target(); #endif new_base = per_cpu(tvec_bases, cpu); if (base != new_base) { /* * We are trying to schedule the timer on the local CPU. * However we can't change timer's base while it is running, * otherwise del_timer_sync() can't detect that the timer's * handler yet has not finished. This also guarantees that * the timer is serialized wrt itself. */ if (likely(base->running_timer != timer)) { /* See the comment in lock_timer_base() */ timer_set_base(timer, NULL); spin_unlock(&base->lock); base = new_base; spin_lock(&base->lock); timer_set_base(timer, base); } } timer->expires = expires; if (time_before(timer->expires, base->next_timer) && !tbase_get_deferrable(timer->base)) base->next_timer = timer->expires; internal_add_timer(base, timer); out_unlock: spin_unlock_irqrestore(&base->lock, flags); return ret; } /** * mod_timer_pending - modify a pending timer's timeout * @timer: the pending timer to be modified * @expires: new timeout in jiffies * * mod_timer_pending() is the same for pending timers as mod_timer(), * but will not re-activate and modify already deleted timers. * * It is useful for unserialized use of timers. */ int mod_timer_pending(struct timer_list *timer, unsigned long expires) { return __mod_timer(timer, expires, true, TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer_pending); /* * Decide where to put the timer while taking the slack into account * * Algorithm: * 1) calculate the maximum (absolute) time * 2) calculate the highest bit where the expires and new max are different * 3) use this bit to make a mask * 4) use the bitmask to round down the maximum time, so that all last * bits are zeros */ static inline unsigned long apply_slack(struct timer_list *timer, unsigned long expires) { unsigned long expires_limit, mask; int bit; if (timer->slack >= 0) { expires_limit = expires + timer->slack; } else { long delta = expires - jiffies; if (delta < 256) return expires; expires_limit = expires + delta / 256; } mask = expires ^ expires_limit; if (mask == 0) return expires; bit = find_last_bit(&mask, BITS_PER_LONG); mask = (1 << bit) - 1; expires_limit = expires_limit & ~(mask); return expires_limit; } /** * mod_timer - modify a timer's timeout * @timer: the timer to be modified * @expires: new timeout in jiffies * * mod_timer() is a more efficient way to update the expire field of an * active timer (if the timer is inactive it will be activated) * * mod_timer(timer, expires) is equivalent to: * * del_timer(timer); timer->expires = expires; add_timer(timer); * * Note that if there are multiple unserialized concurrent users of the * same timer, then mod_timer() is the only safe way to modify the timeout, * since add_timer() cannot modify an already running timer. * * The function returns whether it has modified a pending timer or not. * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an * active timer returns 1.) */ int mod_timer(struct timer_list *timer, unsigned long expires) { expires = apply_slack(timer, expires); /* * This is a common optimization triggered by the * networking code - if the timer is re-modified * to be the same thing then just return: */ if (timer_pending(timer) && timer->expires == expires) return 1; return __mod_timer(timer, expires, false, TIMER_NOT_PINNED); } EXPORT_SYMBOL(mod_timer); /** * mod_timer_pinned - modify a timer's timeout * @timer: the timer to be modified * @expires: new timeout in jiffies * * mod_timer_pinned() is a way to update the expire field of an * active timer (if the timer is inactive it will be activated) * and to ensure that the timer is scheduled on the current CPU. * * Note that this does not prevent the timer from being migrated * when the current CPU goes offline. If this is a problem for * you, use CPU-hotplug notifiers to handle it correctly, for * example, cancelling the timer when the corresponding CPU goes * offline. * * mod_timer_pinned(timer, expires) is equivalent to: * * del_timer(timer); timer->expires = expires; add_timer(timer); */ int mod_timer_pinned(struct timer_list *timer, unsigned long expires) { if (timer->expires == expires && timer_pending(timer)) return 1; return __mod_timer(timer, expires, false, TIMER_PINNED); } EXPORT_SYMBOL(mod_timer_pinned); /** * add_timer - start a timer * @timer: the timer to be added * * The kernel will do a ->function(->data) callback from the * timer interrupt at the ->expires point in the future. The * current time is 'jiffies'. * * The timer's ->expires, ->function (and if the handler uses it, ->data) * fields must be set prior calling this function. * * Timers with an ->expires field in the past will be executed in the next * timer tick. */ void add_timer(struct timer_list *timer) { BUG_ON(timer_pending(timer)); mod_timer(timer, timer->expires); } EXPORT_SYMBOL(add_timer); /** * add_timer_on - start a timer on a particular CPU * @timer: the timer to be added * @cpu: the CPU to start it on * * This is not very scalable on SMP. Double adds are not possible. */ void add_timer_on(struct timer_list *timer, int cpu) { struct tvec_base *base = per_cpu(tvec_bases, cpu); unsigned long flags; timer_stats_timer_set_start_info(timer); BUG_ON(timer_pending(timer) || !timer->function); spin_lock_irqsave(&base->lock, flags); timer_set_base(timer, base); debug_activate(timer, timer->expires); if (time_before(timer->expires, base->next_timer) && !tbase_get_deferrable(timer->base)) base->next_timer = timer->expires; internal_add_timer(base, timer); /* * Check whether the other CPU is idle and needs to be * triggered to reevaluate the timer wheel when nohz is * active. We are protected against the other CPU fiddling * with the timer by holding the timer base lock. This also * makes sure that a CPU on the way to idle can not evaluate * the timer wheel. */ wake_up_idle_cpu(cpu); spin_unlock_irqrestore(&base->lock, flags); } EXPORT_SYMBOL_GPL(add_timer_on); /** * del_timer - deactive a timer. * @timer: the timer to be deactivated * * del_timer() deactivates a timer - this works on both active and inactive * timers. * * The function returns whether it has deactivated a pending timer or not. * (ie. del_timer() of an inactive timer returns 0, del_timer() of an * active timer returns 1.) */ int del_timer(struct timer_list *timer) { struct tvec_base *base; unsigned long flags; int ret = 0; debug_assert_init(timer); timer_stats_timer_clear_start_info(timer); if (timer_pending(timer)) { base = lock_timer_base(timer, &flags); if (timer_pending(timer)) { detach_timer(timer, 1); if (timer->expires == base->next_timer && !tbase_get_deferrable(timer->base)) base->next_timer = base->timer_jiffies; ret = 1; } spin_unlock_irqrestore(&base->lock, flags); } return ret; } EXPORT_SYMBOL(del_timer); /** * try_to_del_timer_sync - Try to deactivate a timer * @timer: timer do del * * This function tries to deactivate a timer. Upon successful (ret >= 0) * exit the timer is not queued and the handler is not running on any CPU. */ int try_to_del_timer_sync(struct timer_list *timer) { struct tvec_base *base; unsigned long flags; int ret = -1; debug_assert_init(timer); base = lock_timer_base(timer, &flags); if (base->running_timer == timer) goto out; timer_stats_timer_clear_start_info(timer); ret = 0; if (timer_pending(timer)) { detach_timer(timer, 1); if (timer->expires == base->next_timer &&