В каком контексте работает функция таймера ядра Linux?

Когда истечет таймер, созданный с помощью API add_timer, и запускается функция, назначенная в структуре таймера, в каком контексте она выполняется? Это контекст прерывания или некоторый контекст процесса ядра?

Ответ 1

Это, конечно, в контексте прерывания, точнее, в контексте softirq, см. ниже (kernel/timer.c):

static inline void __run_timers(struct tvec_base *base)
{
        struct timer_list *timer;

        spin_lock_irq(&base->lock);
        while (time_after_eq(jiffies, base->timer_jiffies)) {
                struct list_head work_list;
                struct list_head *head = &work_list;
                int index = base->timer_jiffies & TVR_MASK;

                /*
                 * Cascade timers:
                 */
                if (!index &&
                        (!cascade(base, &base->tv2, INDEX(0))) &&
                                (!cascade(base, &base->tv3, INDEX(1))) &&
                                        !cascade(base, &base->tv4, INDEX(2)))
                        cascade(base, &base->tv5, INDEX(3));
                ++base->timer_jiffies;
                list_replace_init(base->tv1.vec + index, &work_list);
                while (!list_empty(head)) {
                        void (*fn)(unsigned long);
                        unsigned long data;
                        bool irqsafe;

                        timer = list_first_entry(head, struct timer_list,entry);
                        fn = timer->function;
                        data = timer->data;
                        irqsafe = tbase_get_irqsafe(timer->base);

                        timer_stats_account_timer(timer);

                        base->running_timer = timer;
                        detach_expired_timer(timer, base);

                        if (irqsafe) {
                                spin_unlock(&base->lock);
                                call_timer_fn(timer, fn, data); // <=========== HERE
                                spin_lock(&base->lock);
                        } else {
                                spin_unlock_irq(&base->lock);
                                call_timer_fn(timer, fn, data); // <============ HERE
                                spin_lock_irq(&base->lock);
                        }
                }
        }
        base->running_timer = NULL;
        spin_unlock_irq(&base->lock);
}


/*
 * This function runs timers and the timer-tq in bottom half context.
 */
static void run_timer_softirq(struct softirq_action *h)
{
        struct tvec_base *base = __this_cpu_read(tvec_bases);

        hrtimer_run_pending();

        if (time_after_eq(jiffies, base->timer_jiffies))
                __run_timers(base);
}

void __init init_timers(void)
{
        int err;

        /* ensure there are enough low bits for flags in timer->base pointer */
        BUILD_BUG_ON(__alignof__(struct tvec_base) & TIMER_FLAG_MASK);

        err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
                               (void *)(long)smp_processor_id());
        init_timer_stats();

        BUG_ON(err != NOTIFY_OK);
        register_cpu_notifier(&timers_nb);
        open_softirq(TIMER_SOFTIRQ, run_timer_softirq); // <============= HERE
}