CLOCKINTR(9)
π clockintr(9) β the clock interrupt scheduler, explained π
okay so bestie, welcome to clockintr(9) from the Kernel Developer's Manual β section 9, kernel-land only, this is not a drill. she's the whole clock interrupt scheduling situation and tbh she's kind of the main character of your CPU's sense of time. let's get into it π°οΈβ¨
πΈ NAME πΈ
clockintr_init, clockintr_cpu_init, clockintr_dispatch, clockintr_setstatclockrate, clockintr_trigger β the clock interrupt scheduler. that's the whole squad, all five of them, no cap π
β¨ SYNOPSIS β¨
#include <sys/clockintr.h>
void
clockintr_init(u_int flags);
void
clockintr_cpu_init(struct intrclock *ic);
int
clockintr_dispatch(void *frame);
void
clockintr_setstatclockrate(int freq);
void
clockintr_trigger(void);
#include <sys/kernel.h>
extern int hz;
extern int stathz;
extern int profhz;
#include <sys/sched.h>
extern int schedhz;
π¦ DESCRIPTION π¦
so the clockintr_init subsystem (yes, the subsystem and the function share a name, it's giving shared identity, iconic) does three things: it keeps a schedule of events, it dispatches expired events, and it rearms the local interrupt clock for each CPU in the system. that's the whole vibe check. π
π what clockintr_init() actually does
the clockintr_init() function initializes the subsystem like this:
hardclock(9)gets configured to runhz(9)times per second on each CPU. it is an error ifhzis less than one or greater than one billion. (one billion!! bestie. do not.)statclock()gets configured to runstathztimes per second on each CPU. it is an error ifstathzis less than one or greater than one billion.- when appropriate,
statclock()will be reconfigured to runprofhztimes per second on each CPU.profhzmust be a non-zero integer multiple ofstathz. it is an error ifprofhzis less thanstathzor greater than one billion. - if
schedhzis non-zero,schedclock()gets configured to runschedhztimes per second on each CPU. it is an error ifschedhzis less than zero or greater than one billion.
β οΈ the event schedule has a resolution of one nanosecond, and event periods are computed using integer division. so ifhz,stathz,profhz, orschedhzdon't divide evenly into one billion, the corresponding event will not be dispatched at the specified frequency. that's not a bug, that's just math being math π
π the flags
clockintr_init() accepts the bitwise OR of zero or more of these flags:
CL_RNDSTATβ randomize thestatclock(). instead of a fixed period, the subsystem picks pseudorandom intervals in a range such that the averagestatclock()period equals the inverse ofstathz. chaotic in a mathematically responsible way, obsessed π²
π rules of engagement
clockintr_init() must be called exactly once and only by the primary CPU. it should be called after all timecounters are installed with tc_init(9). read that again. exactly once. only the primary CPU. after tc_init(9). iykyk β
π§ clockintr_cpu_init()
the clockintr_cpu_init() function prepares the calling CPU for clockintr_dispatch().
- the first time it's called on a given CPU: if
icis notNULL, the caller is configured to use the givenintrclockduringclockintr_dispatch(). otherwise, the caller is responsible for rearming its own interrupt clock after eachclockintr_dispatch(). (you either get the helper or you do it yourself, both are valid slay π ) - subsequent calls ignore
ic. instead, the caller's event schedule is advanced past any expired events without dispatching those events. no double-dipping, periodt. - it is an error to call this function before the subsystem is initialized with
clockintr_init(). - all CPUs should call
clockintr_cpu_init()during each system resume, after the system time is updated withinittodr(9)β otherwise they'll needlessly dispatch every single event that expired while the system was suspended. like, every one. π don't do that to yourself.
π₯ clockintr_dispatch()
the clockintr_dispatch() function executes all expired events on the caller's event schedule and, if configured, rearms the caller's interrupt clock to fire when the next event is scheduled to expire.
framemust point to the caller'sclockframestruct.- it should only be called from a clock interrupt handler at
IPL_CLOCK(seespl(9)). - it is an error to call this function on a given CPU before
clockintr_cpu_init().
π clockintr_setstatclockrate()
the clockintr_setstatclockrate() function changes the effective dispatch frequency for statclock() to freq.
- it should be called from the machine-dependent
setstatclockrate()function, after doing any needed hardware reconfiguration. - it is an error if
freqis not equal tostathzorprofhz. those are the only two choices, bestie, pick one. - it is an error to call this function before the subsystem is initialized with
clockintr_init().
β clockintr_trigger()
the clockintr_trigger() function causes clockintr_dispatch() to run in the appropriate context as soon as possible β but only if the caller was configured with an intrclock when clockintr_cpu_init() was first called. if the caller was not configured with an intrclock, the function does nothing. #nothin
- it is an error to call this function on a given CPU before
clockintr_cpu_init().
π«Ά the intrclock struct
the ic argument to clockintr_cpu_init() points to an intrclock structure:
struct intrclock {
void *ic_cookie;
void (*ic_rearm)(void *cookie, uint64_t nsecs);
void (*ic_trigger)(void *cookie);
};
the intrclock structure gives the clockintr_init subsystem a uniform interface for manipulating an interrupt clock. here are the members, one by one, no skips:
ic_cookieβ may point to any resources needed duringic_rearmoric_triggerto arm the underlying interrupt clock (see below). it's the lil bag of stuff you carry around πic_rearmβ should causeclockintr_dispatch()to run on the calling CPU in the appropriate context after at leastnsecsnanoseconds have elapsed. the first argument,cookie, is theic_cookiemember of the parent structure. the second argument,nsecs, is a non-zero count of nanoseconds. non-zero. important.ic_triggerβ should causeclockintr_dispatch()to run on the calling CPU in the appropriate context as soon as possible. the first argument,cookie, is theic_cookiemember of the parent structure.
π CONTEXT π
where you're allowed to call these, aka the dress code:
clockintr_init(),clockintr_cpu_init(), andclockintr_trigger()may be called during autoconf.clockintr_dispatch()may be called from interrupt context atIPL_CLOCK.clockintr_setstatclockrate()may be called during autoconf, from process context, or from interrupt context. she's flexible, we love her πΈ
π RETURN VALUES π
clockintr_dispatch() returns non-zero if at least one event was dispatched, otherwise it returns zero. that's it, that's the whole return section π
π CODE REFERENCES π
sys/kern/kern_clockintr.c β go read the source, bestie, it's right there π
π SEE ALSO π
hardclock(9), hz(9), inittodr(9), nanouptime(9), spl(9), tc_init(9), timeout(9)
and the reading list, because we're cultured:
- Steven McCanne and Chris Torek, βA Randomized Sampling Clock for CPU Utilization Estimation and Code Profilingβ, In Proc. Winter 1993 USENIX Conference, USENIX Association, pp. 387β394, 1993.
- Richard McDougall and Jim Mauro, Solaris Internals: Solaris 10 and OpenSolaris Kernel Architecture, Prentice Hall Sun Microsystems Press, pp. 912β925, 2nd Edition, 2007.
π¦ HISTORY π¦
the clockintr_init subsystem first appeared in OpenBSD 7.3. a relatively recent icon, tbh β¨
and that's the page, bestie!! every flag, every error condition, every struct member, every reference β all accounted for, no crumbs left behind ππ
πΈ sign-off time: this beauty came from the Debian rendering, dated November 10, 2022. mwah, go schedule some interrupts responsibly π β¨
π¦ where this page comes from
- nixpkgs unstable: cvs-export
- Copyright (c) 2020-2022 Scott Cheloha <cheloha@openbsd.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms