제46강 : Timers and Time Management Ch 10 Timers and Time Management 1 Terminology • HZ – tick rate (differs for each architecture) #define HZ 1000 (include/asm-i386/param.h) – In most other architecture, HZ is 100 – i386 architecture (since 2.5 series) tick • jiffies – number of ticks since system boot – global variable • jiffies-Hz-Time – To convert from [seconds to jiffies] 1000 Hz 100 Hz • (second * HZ) – To convert from [jiffies to seconds] Jiffies • (jiffies / HZ) 2 Terminology • Issues on HZ – If increase the tick rate from 100 Hz 1000 Hz? • All timed events have a higher resolution • and the accuracy of timed events improve • overhead of timer Interrupt increase . • Issues on jiffies – Internal representation of jiffies – jiffies wrap-around 3 Hardware Clocks and Timers • System Timer – Drive an interrupt at a periodic rate – Programmable Interrupt Timer (PIT) on X86 – kernel programs PIT on boot to drive timer interrupt at HZ • Real-Time Clock (RTC) – – – – Nonvolatile device for storing the time RTC continues even when the system is off (small battery) On boot, kernel reads the RTC Initialize the wall time (in struct timespec xtime) 4 Timer Interrupt Handler • The architecture-dependent routine – Acknowledge or reset system timer as required – Periodically save the updated wall time to the RTC – Call the architecture-independent timer routine, do_timer() • The architecture-independent routine – – – – – jiffies++ Update the wall time Update resource usages Run any dynamic timers that have expired Calculate load average 5 Timer Interrupt Handler void do_timer(struct pt_regs *regs) { jiffies_64++; /* increment jiffies */ update_process_times(user_mode(regs)); update_times(); } 1 if user mode 0 if kernel mode p->utime += user; p->stime += system; void update_process_times(int user_tick) { struct task_struct *p = current; int cpu = smp_processor_id(), system = user_tick ^ 1; update_one_process(p, user_tick, system, cpu); run_local_timers(); /* marks a softirq */ scheduler_tick(user_tick, system); /* decrements the currently running process’s timeslice and sets need_resched if needed */ } static inline void update_times(void) { unsigned long ticks; ticks = jiffies - wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); } calc_load(ticks); } 6 The Time of Day • The wall time struct timespec xtime; strut timespec { time_t tv_sec; long tv_nsec; }; /* seconds */ /* nanoseconds */ – xtime.tv_sec value stores the number of seconds that have elapsed since January 1, 1970 (epoch) – xtime.tv_nsec value stores the number of nanosecnds that have elapsed in the last second 7 Timers • Timers --- eg “run fA() every 250 ms.” – Kernel code often needs to delay execution of some function until a later time – e.g.) bottom half mechanisms • How to use timers – Initial setup • Specify expiration time • Specify function to execute upon said expiration – Activate the timer 8 Timers • Timer structure struct timer_list { struct list_head entry; /* timers are part of linked list */ 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 */ }; 9 Timers • Using Timers – Define timer struct timer_list my_timer; – Initialize the timer’s internal values init_timer(&my_timer); – Fill out the remaining values as required my_timer.expires = jiffies + delay; /* timer expires in delay ticks */ my_timer.data = 0; /* zero is passed to timer handler */ my_timer.function = my_function; /* function to run when timer expires */ – Activate the timer add_timer(&my_timer); 10 Delaying Execution • Schedule_timeout() set_current_state (TASK_INTERRUPTIBLE); schedule_timeout (s * HZ); /* put the task to sleep */ signed long schedule_timeout(signed long timeout) { struct timer_list timer; /* create timer */ unsigned long expire; expire = timeout + jiffies; init_timer(&timer); /* initialize the timer */ timer.expires = expire; timer.data = (unsigned long) current; timer.function = process_timeout; add_timer(&timer); /* activate the timer */ schedule(); /* call schedule() */ del_timer_sync(&timer); timeout = expire - jiffies; return timeout < 0 ? 0 : timeout; } static void process_timeout(unsigned long __data) { wake_up_process((task_t *)__data); } 11 Other Ways to Delay Execution • Busy Looping (as soon as …) unsigned long delay = jiffies + 10; /* ten ticks */ while (time_before(jiffies, delay)); • Small Delays (micro-, or milli- seconds) void udelay(unsigned long usecs); void mdelay(unsigned long msecs); udelay(150); /* delay for 150 us 12