Dynamic timers

Dynamic timers can be created and destroyed at any time, hence the name dynamic timers. Dynamic timers are represented by the struct timer_list object, defined in include/linux/timer.h:

struct timer_list {
        /*
        * Every field that changes during normal runtime grouped to the
        * same cacheline
        */
        struct hlist_node entry;
        unsigned long           expires;
        void                    (*function)(unsigned long);
        unsigned long           data;
        u32                      flags;

#ifdef CONFIG_LOCKDEP
        struct lockdep_map        lockdep_map;
#endif
};

All timers in a system are managed by a doubly linked list, and are sorted in order of their expiry time, represented by the expires field. The expires field specifies the time duration, after which the timer expires. As soon as the current jiffies value matches or exceeds this field's value, the timer decays. Through the entry field, a timer is added into this timer linked list. The function field points to the routine to be invoked on expiry of the timer and the data field holds the parameter to be passed to the function, if needed. The expires field is constantly compared with jiffies_64 values to determine whether the timer has expired or not.

A dynamic timer can be created and activated as follows:

  • Create a new timer_list object, let's say t_obj.
  • Initialize this timer object using macro init_timer(&t_obj), defined in include/linux/timer.h.
  • Initialize the function field with the function's address to be invoked on expiry of the timer. If the function requires a parameter, initialize the data field too.
  • If the timer object is already added to a timer list, update the expires field by calling the function mod_timer(&t_obj, <timeout-value-in-jiffies>), defined in kernel/time/timer.c.
  • If not, initialize the expires field and add the timer object into the timer list using add_timer(&t_obj), defined in /kernel/time/timer.c.

The kernel removes a decayed timer from its timer list automatically, but there are other methods too to remove a timer from its list. The del_timer() and del_timer_sync() routines and the macro del_singleshot_timer_sync() defined in kernel/time/timer.c help in doing so:

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;
}


int del_timer_sync(struct timer_list *timer) { #ifdef CONFIG_LOCKDEP unsigned long flags; /* * If lockdep gives a backtrace here, please reference * the synchronization rules above. */ local_irq_save(flags); lock_map_acquire(&timer->lockdep_map); lock_map_release(&timer->lockdep_map); local_irq_restore(flags); #endif /* * don't use it in hardirq context, because it * could lead to deadlock. */ WARN_ON(in_irq()); for (;;) { int ret = try_to_del_timer_sync(timer); if (ret >= 0) return ret; cpu_relax(); } }

#define del_singleshot_timer_sync(t) del_timer_sync(t)

del_timer() removes both active and inactive timers. Particularly useful in SMP systems, del_timer_sync() deactivates the timer and waits until the handler has finished executing on other CPUs.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.40.207