Download presentation
Presentation is loading. Please wait.
Published byOlivia Taylor Modified over 8 years ago
1
Timers and Time Management Ok-Kyun Ha 2007.05.18
2
Contents Kernel Notion of Time The Tick Rate: HZ Jiffies Hardware Clocks and Timers The Timer Interrupt Handler Timers Delaying Execution
3
Introduction The passing of time is very important to the kernel almost kernel functions are time driven (not event driven) Focus (in this chapter) - system timer and timer interrupt - the system timer is a programmable piece of hardware that issues an interrupt at a fixed frequency - dynamic timers - used to schedule events that run once after specified time complete 3
4
Kernel notion of Time Kernel can comprehend and manage time through tick rate of system timer in hardware When the system timer goes off, it issues an interrupt that the kernel handles via a special interrupt handler The kernel keeps track of it simply because the kernel controls the timer interrupt The timer interrupt is very important to the management of the operating system 4
5
The Tick Rate: HZ The tick rate is programmed on system boot based on a static preprocessor define, HZ The value of HZ differs for each supported architectures The kernel defines the value in #define HZ 1000 /* internal kernel time frequency */ When writing kernel code, never assume that HZ has any given value 5
6
The Tick Rate - The Ideal HZ Value Changing its frequency has a reasonable impact on the system Increasing the tick rate means the timer interrupt runs more frequently Benefits - the timer interrupt has a higher resolution - all timed events have a higher resolution - the accuracy of timed events improves Downside - implies more frequent timer interrupts - implies higher overhead - processor must spend more time executing the timer interrupt handler 6
7
Jiffies The global variable jiffies holds the number of ticks that have occurred since the system booted extern unsigned long volatile jiffies; /* */ - on boot: jiffies = 0; - each timer interrupt: jiffies++; convert forms of jiffies - second to jiffies : (second*HZ) - jiffies to second: (jiffies/HZ) ex) unsigned long next_tick = jiffies + _1;/* one tick from now */ unsigned long later = jiffies + 5 * HZ;/* five second from now */ 7
8
Jiffies – Internal Representation of Jiffies The jiffies variable has 32 bit in size on 32-bit architectures and 64-bit on 64- bit architectures - overflow: 49.7days (1000 HZ / 32-bit) jiffies_64 extern u64 jiffies_64;/* */ - overlays the jiffies variable over the start of the jiffies_64 variable - jiffies is the lower 32 bit of the full 64-bit jiffies_64 variable - time management code uses the entire 64 bits - prevents overflow of the full 64-bit value bit 63310 jiffies_64 (jiffies on 64-bit machines) jiffies on 32-bit machine 8
9
Jiffies – Jiffies Wraparound equal to maximum and it is incremented, it wraps around to zero macros for comparing tick counts #define time_after(unknown, known) ((long)(known) – (long)(unknown) < 0) #define time_before(unknown, known) ((long)(unknown) – (long)(known) < 0) #define time_after_eq(unknown, known) ((long)(unkown) – (long)(known) >= 0) #define time_before_eq(unknown, known) ((long)(known) – (long)(unkown) >= 0) unsigned long timeout = jiffies + HZ/2; /* timeout in 0.5s */ /* … */ if (timeout > jiffies) { /* we did not time out, good … */ } else { /* we time out, error … */ } 9 unsigned long timeout = jiffies + HZ/2; /* timeout in 0.5s */ /* … */ if (time_after(jiffies, timeout)) { /* we did not time out, good … */ } else { /* we time out, error … */ }
10
Hardware Clock and Timers Real-Time Clock (RTC) - a nonvolatile device for storing the system time - the kernel reads the RTC and use it to initialize the wall time - stored in the ‘ xtime’ variable System Timer - serves a much more important (and frequent) role in the kernel’s timekeeping - provide a mechanism for driving an interrupt at a periodic rate - primary system timer is the PIT (on x86) - the kernel programs the PIT on boot to drive the system timer interrupt at HZ frequency 10
11
The Timer Interrupt Handler (1/3) The architecture-dependent routine - registered as the interrupt handler for the system timer Obtain the xtime_lock lock, which protects access to jiffies_64 and the wall time value, xtime Acknowledge or reset the system timer as required Periodically save the updated wall time to the real time clock Call the architecture-independent timer routine, do_timer() The architecture-independent routine: do_timer() Increment the jiffies_64 count by one Update resource usages for the currently running process (such as system and user time) Run any dynamic timers that have expired Execute scheduler_tick() Update the wall time, which is stored in xtime Calculate the load average 11
12
The Timer Interrupt Handler (2/3) do_timer( ) void do_timer (struct pt_regs *regs) { jiffies_64 ++; update_process_times(user_mode(regs)); update_times( ); } void update_process_times(int user_tick) { struct task_struct *p = current; int cpu = smp_processor_id(); int system = user_tick ^ 1; update_one_process(p, user_tick, system, cpu); run_local_timers(); scheduler_tick(user_tick, system); } 12
13
The Timer Interrupt Handler (3/3) update_times() all this occurs every 1/ HZ of a second void update_times(void) { unsigned long ticks; ticks = jiffies – wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time (ticks); } last_time_offset = 0; calc_load(ticks); } 13
14
Timers Bottom-half - used great for deferring work until later - not so much to delay work, but simply to not do the work now Kernel Timer - can delaying a work during a specified amount of time - easy to use perform some initial setup specify an expiration time specify a function to execute upon said expiration activate the timer 14
15
Timers – Using Timer (1/2) represented by struct timer_list struct timer_list { struct list_head entry;/* entry in linked list of timers */ unsigned long expires;/* expiration value, in jiffies */ spinlock_t lock;/* lock protecting this timer */ void (*function)(unsigned long);/* the timer handler function */ unsigned long data;/* lone argument to the handler */ struct tvec_t_base_s *base;/* internal timer field */ }; 15
16
Timers – Using Timer (2/2) Using 1. define using timer struct timer_list my_timer; 2. initialize the timer init_timer(&my_timer); 3. setting the timer funtions my_timer.expires = jiffies + delay; my_timer.data = 0; my_timer.function = my_function; 4. activate the timer add_timer(&my_timer); 16
17
Timers – Timer Race condition potential race conditions exist (run asynchronously) - a timer could be executed another processor in multi-processing system - a potential race condition that must be guarded against exists when deleting timers delete timer - del_timer(&my_timer); - del_timer_sync(&my_timer); modify timer: changes the expiration of a given timer - del_timer(my_timer); my_timer->expires = jiffies + new_delay; add_timer(my_timer); - mod_timer(&my_timer, jiffies+new_delay); 17
18
Timers – The Timer Implementation The Timer Implementation - the kernel executes timers in bottom-half context after the timer interrupt completes - the timer interrupt handler runs update_process_times() which calls run_local_timers() - the kernel partitions timers into five groups based on their expiration value - timers move down through the groups as their expiration time draws closer void run_local_timers(void) { raise_softirq(TIMER_SOFTIRQ); } 18
19
Delaying Execution kernel code (especially drivers) needs a way to delay execution for some time without using timers or bottom-half mechanism - usually to allow hardware time to complete a given task - network card driver should wait at least the two microseconds before continuing the solutions (depending on the semantics of the delay) - Busy Looping - Small Delays - schedule_timeout() 19
20
Delaying Execution – Busy looping Busy looping: spin in a loop until the desired number of clock ticks pass reschedule for current process - conditionally invokes the scheduler only if there is some more important task to run unsigned long delay = jiffies + 5 * HZ; while (time_before(jiffies, delay)) ; unsigned long delay = jiffies + 5 * HZ; while (time_before(jiffies, delay)) cond_resched(); 20
21
Delaying Execution – Small Delays requires very short and rather precise delays - kernel provide two functions for microsecond and millisecond delays - delays execution by busy looping for the specified number of microseconds or milliseconds using the functions - the udelay() function should be called only for small delays - larger delays on fast machines might result in overflow - as delays over 1 millisecond for longer durations mdelay() function should be called void udelay(unsigned long usecs);/* udelay(150) */ void mdelay(unsigned long msecs);/* mdelay(150) */ 21
22
Delaying Execution – schedule_timeout() optimal method - task to sleep until at least the specified time has elapsed - the kernel wakes the task up and places it back on the runqueue using the functions sleeping on a waiting queue, with a timeout - first occur want to make desirable to wait for a specific event or wait for a specified time to elapse - call schedule_timeout() instead of schedule() after placing itself on a wait queue /* set task’state to interruptible sleep */ set_current_state(TASK_INTERRUPTIBLE);/*TASK_UNINTERRUPTIBLE */ /* take a nap and wake up in “s” seconds */ schedule_timeout(s * HZ); 22
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.