The Linux timer interrupt handler doesn’t do all that much directly. For x86, you’ll find the default PIT/HPET timer interrupt handler in arch/x86/kernel/time.c:

static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
    global_clock_event->event_handler(global_clock_event);
    return IRQ_HANDLED;
}

This calls the event handler for global clock events, tick_handler_periodic by default, which updates the jiffies counter, calculates the global load, and updates a few other places where time is tracked.

As a side-effect of an interrupt occurring, __schedule might end up being called, so a timer interrupt can also lead to a task switch (like any other interrupt).

Changing CONFIG_HZ changes the timer interrupt’s periodicity. Increasing HZ means that it fires more often, so there’s more timer-related overhead, but less opportunity for task scheduling to wait for a while (so interactivity is improved); decreasing HZ means that it fires less often, so there’s less timer-related overhead, but a higher risk that tasks will wait to be scheduled (so throughput is improved at the expense of interactive responsiveness). As always, the best compromise depends on your specific workload. Nowadays CONFIG_HZ is less relevant for scheduling aspects anyway; see How to change the length of time-slices used by the Linux CPU scheduler?

See also How is an Interrupt handled in Linux?

Answer from Stephen Kitt on Stack Exchange
Top answer
1 of 2
14

The Linux timer interrupt handler doesn’t do all that much directly. For x86, you’ll find the default PIT/HPET timer interrupt handler in arch/x86/kernel/time.c:

static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
    global_clock_event->event_handler(global_clock_event);
    return IRQ_HANDLED;
}

This calls the event handler for global clock events, tick_handler_periodic by default, which updates the jiffies counter, calculates the global load, and updates a few other places where time is tracked.

As a side-effect of an interrupt occurring, __schedule might end up being called, so a timer interrupt can also lead to a task switch (like any other interrupt).

Changing CONFIG_HZ changes the timer interrupt’s periodicity. Increasing HZ means that it fires more often, so there’s more timer-related overhead, but less opportunity for task scheduling to wait for a while (so interactivity is improved); decreasing HZ means that it fires less often, so there’s less timer-related overhead, but a higher risk that tasks will wait to be scheduled (so throughput is improved at the expense of interactive responsiveness). As always, the best compromise depends on your specific workload. Nowadays CONFIG_HZ is less relevant for scheduling aspects anyway; see How to change the length of time-slices used by the Linux CPU scheduler?

See also How is an Interrupt handled in Linux?

2 of 2
1

what Linux does in the timer interrupt?

I take this as asking for the in-between actions.

I copy from that __schedule():

 *   3. Wakeups don't really cause entry into schedule(). They add a
 *      task to the run-queue and that's it.
 *
 *      Now, if the new task added to the run-queue preempts the current
 *      task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets
 *      called on the nearest possible occasion:

This is a good starting point; it is well documented. This is the start of a long story. What is a "wakeup"? Is it about R and S states? and blocking?

I have only one slight objection to S.K.'s answer, and to one of the links: about HZ being "not so important anymore".

Can be because there was some confusion in the past, some overcorrection from 100HZ to 1000HZ then back to 300HZ, so to fit "multimedia" at the same time (think of HPET origin 2005: "multimedia timer").

Can be with 4 and more cores it also matters less. But depending on what you want to do with your "server" it still should matter - this latency / throughput trade-off can be important under heavy load.

And if the scheduling is not done in the timer interrupts, then it is done in these "other" interrupts.

And why is HZ not configurable (boot or even runtime)?

🌐
O'Reilly
oreilly.com › library › view › understanding-the-linux › 0596000022 › 0596000022_ch05-5-fm2xml.html
The Timer Interrupt Handler - Understanding the Linux Kernel [Book]
October 1, 2000 - 5.2. The Timer Interrupt Handler Each occurrence of a timer interrupt triggers the following major activities: Updates the time elapsed since system startup.Updates the time and... - Selection from Understanding the Linux Kernel [Book]
Authors   Daniel P. BovetMarco Cesati
Published   2000
Pages   704
🌐
Umass
lass.cs.umass.edu › ~shenoy › courses › spring20 › lectures › Lec20.pdf pdf
Linux Kernel Synchronization and Timers Ahmed Ali-Eldin
via a special interrupt handler. ○ · a tick and is equal to 1/(tick rate) seconds · ● · Important for many kernel functions, specially scheduling · The Tick Rate: HZ · ● · The frequency of the system timer (the tick rate) is programmed on system · boot based on a static preprocessor define, HZ. ○ · Defined in https://github.com/torvalds/linux/blob/master/include/asm-generic/param.h and ·
🌐
Linux Inside
0xax.gitbooks.io › linux-insides › content › Timers › linux-timers-4.html
Timers and time management in the Linux kernel. Part 4. - 0xax
The thec_base structure contains following fields: The lock for tvec_base protection, the next running_timer field points to the currently running timer for the certain processor, the timer_jiffies fields represents the earliest expiration time (it will be used by the Linux kernel to find already expired timers). The next field - next_timer contains the next pending timer for a next timer interrupt in a case when a processor goes to sleep and the NO_HZ mode is enabled in the Linux kernel.
🌐
LWN.net
lwn.net › Kernel › LDD2 › ch06.lwn
Linux Device Drivers, Second Edition [LWN.net]
August 1, 2015 - Linux offers three different interfaces for this purpose: task queues, tasklets (as of kernel 2.3.43), and kernel timers. Task queues and tasklets provide a flexible utility for scheduling execution at a later time, with various meanings for "later''; they are most useful when writing interrupt handlers, and we'll see them again in "Tasklets and Bottom-Half Processing", in Chapter 9, "Interrupt Handling".
🌐
University of Hawaii
www2.hawaii.edu › ~esb › 2006fall.ics412 › sep29.html
Slides
the time between system timer interrupts is 1 jiffy · the variable jiffies keeps track of time since boot: ... time_before, time_after, time_before_eq, and time_after_eq provide time comparisons that work with the lower 32 bits and correclty handle wrap-around if HZ == 1000, jiffies wraps around in about 49 days · hardware dependent part, e.g. timer_interrupt in arch/i386/kernel/time.c:
🌐
HackMD
hackmd.io › @sysprog › linux-timer
Linux 核心設計: Timer 及其管理機制 - HackMD
* The timer interrupt is broken into two pieces * interrupt handler: Architecture Depedent * tick_periodic(): Architecture independent routine ![](https://i.imgur.com/ZCXIorb.png) ## Timer interrupt ```cpp static void tick_periodic(int cpu) { if (tick_do_timer_cpu == cpu) { write_seqlock(&xtime_lock); /* Keep track of the next tick event */ tick_next_period = ktime_add(tick_next_period, tick_period); do_timer(1); write_sequnlock(&xtime_lock); } update_process_times(user_mode(get_irq_regs())); profile_tick(CPU_PROFILING); } ``` `do_timer()` is responsible for actually performing the increment to jiffies_64: ```cpp void do_timer(unsigned long ticks) { jiffies_64 += ticks; update_wall_time(); calc_global_load(); } ``` * `update_wall_time()`: updates the wall time in accordance with the elapsed ticks * `calc_global_load()`: updates the system’s load average statistics.
Find elsewhere
🌐
Linux Inside
0xax.gitbooks.io › linux-insides › content › Timers › linux-timers-3.html
The tick broadcast framework and dyntick · Linux Inside - 0xax
which actually represents interrupt handler of the local timer of a processor. After this a processor will wake up. That is all about tick broadcast framework in the Linux kernel. We have missed some aspects of this framework, for example reprogramming of a clock event device and broadcast ...
🌐
University of Hawaii
www2.hawaii.edu › ~esb › 2005spring.ics412 › feb18.html
Timer Interrupt Handler
the time between system timer interrupts is 1 jiffy · the variable jiffies keeps track of time since boot: ... time_before, time_after, time_before_eq, and time_after_eq provide time comparisons that work with the lower 32 bits and correclty handle wrap-around if HZ == 1000, jiffies wraps around in about 49 days · hardware dependent part, e.g. timer_interrupt in arch/i386/kernel/time.c:
🌐
O'Reilly
oreilly.com › library › view › understanding-the-linux › 0596005652 › ch04s06.html
4.6. Interrupt Handling - Understanding the Linux Kernel, 3rd Edition [Book]
November 17, 2005 - An I/O device requires attention; the corresponding interrupt handler must query the device to determine the proper course of action. We cover this type of interrupt in the later section "I/O Interrupt Handling.” ... Some timer, either a local APIC timer or an external timer, has issued an interrupt; this kind of interrupt tells the kernel that a fixed-time interval has elapsed.
Authors   Daniel P. BovetMarco Cesati
Published   2005
Pages   942
🌐
GitHub
github.com › s-matyukevich › raspberry-pi-os › blob › master › docs › lesson03 › linux › timer.md
raspberry-pi-os/docs/lesson03/linux/timer.md at master · s-matyukevich/raspberry-pi-os
The most important property here is handler, which points to bcm2835_time_interrupt - this is the function that is called after an interrupt is fired. If you take a look at it, you will see that it redirects all work to the event handler, registered by the clock events framework. We will examine this event handler in a while. ret = setup_irq(irq, &timer->act); if (ret) { pr_err("Can't set up timer IRQ\n"); goto err_iounmap; }
Author   s-matyukevich
🌐
Toradex Community
community.toradex.com › technical support
Linux EPIT timer interrupt handler - Technical Support - Toradex Community
July 18, 2017 - Hello, For a project I’m using the Aplis iMX6Q embedded platform. I have my basic stuff already running like GPIO and SPI. But now I want to add and Timer interrupt. For this interrupt I’m going to use the EPIT1 timer (according to my research it should be free to use, otherwise EPIT2 would ...
🌐
Zeph1912
zeph1912.github.io › notes_and_journal_repo › kernel_tick.html
Kernel code reading notes: timer tick | Zephyr’s notes and journal
A broadcast timer will do it. ... static void tick_setup_device(struct tick_device *td, struct clock_event_device *newdev, int cpu, const struct cpumask *cpumask) { void (*handler)(struct clock_event_device *) = NULL; ktime_t next_event = 0; /* * First device setup ?
🌐
Opensource.com
opensource.com › article › 21 › 10 › linux-timers
Create a timer on Linux | Opensource.com
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> #include <signal.h> #include <time.h> #include <unistd.h> #include <errno.h> #include <string.h> #define UNUSED(x) (void)(x) static void handler(int sig, siginfo_t *si, void *uc); pid_t gettid(void); struct t_eventData{ int myData; }; int main() { int res = 0; timer_t timerId = 0; struct sigevent sev = { 0 }; struct t_eventData eventData = { .myData = 0 }; /* specifies the action when receiving a signal */ struct sigaction sa = { 0 }; /* specify start delay and interval */ struct itimerspec its = { .it_value.tv_sec
Top answer
1 of 1
8

The simple answer is that neither the execution of the hardware clock interrupt service routine, nor the scheduling of the dynamic timer handlers are affected by the mode the system was in before the hardware clock interrupt. The reason is that the clock timer interrupt is a hardware interrupt that is serviced immediately, regardless of whether the execution is in kernel or user context (assuming that the timer interrupt is enabled that is), and the interrupt service routine for the clock timer interrupt itself raises the software interrupt that runs the dynamic timer handlers.

Caveat: 1) I haven't actually proved this empirically. 2) This does not apply to tickless kernels or highres timers.

The Linux kernel code uses the word "timer" to mean several different things:

  1. the hardware timer or clock interrupt that gives the kernel its "ticks"
  2. dynamic timers - software timers used by the kernel and drivers
  3. interval timers - (setitimer and alarm system calls) software timers for user mode processes

The hardware clock or tick timer

On systems that use a hardware clock to provide the "tick", the clock timer interrupt is an architecture dependent hardware interrupt. For example, look for "timer_interrupt" in arch/powerpc/kernel/head_booke.h and then see the interrupt service routine (ISR) timer_interrupt implementation in arch/powerpc/kernel/time.c. This ISR executes immediately when the timer interrupt occurs, regardless of current execution context. This hardware interrupt differs from other hardware interrupts though, in that when it returns, processing does not return to the prior context. Instead, the scheduler is entered.

For a system that is set to produce 1000 clock interrupts per second, there is a chance that clock interrupts will sometimes be masked when other interrupts are being serviced. This is usually called the "lost ticks" problem. Without compensating for lost ticks, a loaded system could have a slowed sense of time. On some architectures the kernel compensates for lost ticks by using a finer grained hardware increment counter, whose value is read and recorded every clock timer interrupt. By comparing the increment counter value of the current tick against the increment counter value of the previous tick, the kernel can tell if a tick has been lost.

The software timers

The list of dynamic timer handlers (the type you set with the linux/timer.h) of dynamic timers that have expired is set at the end of the clock timer interrupt, before it returns. The sequence is (approximately):

[arch dependent]:timer_interrupt( )
kernel/time/tick-common.c:tick_handle_periodic( )
kernel/time/tick-common.c:tick_periodic( )
kernel/timer.c:update_process_times( )
kernel/timer.c:run_local_timers( )
kernel/softirq.c:raise_softirq(TIMER_SOFTIRQ)

I have omitted the initialilzations that set the handler for the timer_interrupt to tick_handle_periodic, and the handler for TIMER_SOFTIRQ.

The call to raise_softirq(TIMER_SOFTIRQ) generates a software interrupt that is serviced immediately. The ISR for the interrupt runs the dynamic timer queue. The timer handlers run in softirq context, with hardware interrupts enabled. When the ISR returns, the scheduler is called. This means that if there are a lot of timers set, whatever process happens to be next in the run queue will be delayed.

If there were lost ticks, then the execution of the timer handlers could be delayed, however, the delay does not depend on the contect of execution prior to running the clock timer interrupt.

Note about dynamic timer accuracy

"...the kernel cannot ensure that timer functions will start right at their expiration times. It can only ensure that they are executed either at the proper time or after with a delay of up to a few hundred milliseconds." Understanding the Linux Kernel, Bovet and Cesati, 3rd edition, O'reilly.

So, if you need better timer accuracy, you need to use highres timers.

References: Software interrupts and realtime

🌐
EmbeTronicX
embetronicx.com › tutorials › linux › device-drivers › using-kernel-timer-in-linux-device-driver
Using Kernel Timer In Linux Device Driver – Linux Device Driver Tutorial Part 26
September 16, 2023 - Upon exit, the timer is not queued and the handler is not running on any CPU. int timer_pending(const struct timer_list * timer); This will tell whether a given timer is currently pending, or not. Callers must ensure serialization wrt. other operations done to this timer, eg. interrupt contexts or other CPUs on SMP. ... The function returns whether the timer is pending or not. ... In this example, we took the basic driver source code from the Linux ...
🌐
Litux
litux.nl › mirror › kerneldevelopment › 0672327201 › ch10lev1sec5.html
The Timer Interrupt Handler - Litux
Now that we have an understanding of HZ, jiffies, and what the system timer's role is, let's look at the actual implementation of the timer interrupt handler. The timer interrupt is broken into two pieces: an architecture-dependent and an architecture-independent routine · The architectur...
🌐
Medium
medium.com › @satya.devicedriver › the-use-of-timers-in-linux-drivers-419662ad2f2d
The use of Timers in Linux drivers ? | by Satya Prakash | Medium
December 6, 2023 - After the kernel timer registration is turned on, it will not run again after running it once(equivalant to automatic logout). We can reset the timeout time of the timer and let the timer run repeatedly. > Whenever a clock interrupt occurs, the global variable jiffies, is incremented by 1. Therefore jiffies records the number of clock interrupts after the linux system is started.
🌐
LinuxVox
linuxvox.com › blog › what-are-linux-local-timer-interrupts
What Are Linux Local Timer Interrupts? A Comprehensive Guide with Documentation Links — linuxvox.com
Common Timer Processing: The ISR calls local_timer_interrupt(), which coordinates with the kernel’s tick subsystem. Tick Handling: Depending on the mode (periodic/tickless), tick_handle_periodic() or tick_nohz_handler() runs, performing tasks like: