Home arrow Kernal Programming arrow Time, Delays, and Deferred Work

Language Translator

Hacking Zone

Hacking Tools
Attacking

Configure Windows

Windows Configuration

Mix Tutorials

Asterisk
Website Building

Novels

Mix Novels

Human Personality

Body Language
Time, Delays, and Deferred Work Print E-mail
Article Index
Time, Delays, and Deferred Work
Page 2
Page 3
Page 4
Page 5
Page 6
Page 7
Page 8
Page 9

Time, Delays, and Deferred Work

 

              At this point, we know the basics of how to write a full-featured char module. Real world drivers, however, need to do more than implement the operations that control a device; they have to deal with issues such as timing, memory management, hardware access, and more. Fortunately, the kernel exports a number of facilities to ease the task of the driver writer. In the next few chapters, we’ll describe some of the kernel resources you can use. This chapter leads the way by describing how timing issues are addressed. Dealing with time involves the following tasks, in order of increasing complexity:
  • Measuring time lapses and comparing times
  • Knowing the current time
  • Delaying operation for a specified amount of time
  • Scheduling asynchronous functions to happen at a later time

 

Measuring Time Lapses

               The kernel keeps track of the flow of time by means of timer interrupts. Interrupts
               are covered in detail in Chapter 10.
               Timer interrupts are generated by the system’s timing hardware at regular intervals;
               this interval is programmed at boot time by the kernel according to the value of HZ,
               which is an architecture-dependent value defined in <linux/param.h> or a subplat-
               form file included by it. Default values in the distributed kernel source range from 50
               to 1200 ticks per second on real hardware, down to 24 for software simulators. Most
               platforms run at 100 or 1000 interrupts per second; the popular x86 PC defaults to
               1000, although it used to be 100 in previous versions (up to and including 2.4). As a
               general rule, even if you know the value of HZ, you should never count on that spe-
               cific value when programming.
               It is possible to change the value of HZ for those who want systems with a different
               clock interrupt frequency. If you change HZ in the header file, you need to recompile
               the kernel and all modules with the new value. You might want to raise HZ to get a
               more fine-grained resolution in your asynchronous tasks, if you are willing to pay the
               overhead of the extra timer interrupts to achieve your goals. Actually, raising HZ to
               1000 was pretty common with x86 industrial systems using Version 2.4 or 2.2 of the
               kernel. With current versions, however, the best approach to the timer interrupt is to
               keep the default value for HZ, by virtue of our complete trust in the kernel develop-
               ers, who have certainly chosen the best value. Besides, some internal calculations are
               currently implemented only for HZ in the range from 12 to 1535 (see <linux/timex.h>
               and RFC-1589).
               Every time a timer interrupt occurs, the value of an internal kernel counter is incre-
               mented. The counter is initialized to 0 at system boot, so it represents the number of
               clock ticks since last boot. The counter is a 64-bit variable (even on 32-bit architec-
               tures) and is called jiffies_64. However, driver writers normally access the jiffies
               variable, an unsigned long that is the same as either jiffies_64 or its least significant
               bits. Using jiffies is usually preferred because it is faster, and accesses to the 64-bit
               jiffies_64 value are not necessarily atomic on all architectures.
               In addition to the low-resolution kernel-managed jiffy mechanism, some CPU plat-
               forms feature a high-resolution counter that software can read. Although its actual
               use varies somewhat across platforms, it’s sometimes a very powerful tool.

 

 Using the jiffies Counter

               The counter and the utility functions to read it live in <linux/jiffies.h>, although
               you’ll usually just include <linux/sched.h>, that automatically pulls jiffies.h in. Need-
               less to say, both jiffies and jiffies_64 must be considered read-only.
               Whenever your code needs to remember the current value of jiffies, it can simply
               access the unsigned long variable, which is declared as volatile to tell the compiler
               not to optimize memory reads. You need to read the current counter whenever your
               code needs to calculate a future time stamp, as shown in the following example:
                     #include <linux/jiffies.h>
                     unsigned long j, stamp_1, stamp_half, stamp_n;
                     j = jiffies;                                /*  read the current value */
                     stamp_1        = j + HZ;                    /*  1 second in the future */
                     stamp_half = j + HZ/2;                      /*  half a second */
                     stamp_n        = j + n * HZ / 1000;         /*  n milliseconds */
               This code has no problem with jiffies wrapping around, as long as different values
               are compared in the right way. Even though on 32-bit platforms the counter wraps
               around only once every 50 days when HZ is 1000, your code should be prepared to
               face that event. To compare your cached value (like stamp_1 above) and the current
               value, you should use one of the following macros:


                     #include <linux/jiffies.h>
                     int time_after(unsigned long a, unsigned long b);
                      int time_before(unsigned long a, unsigned long b);
                     int time_after_eq(unsigned long a, unsigned long b);
                     int time_before_eq(unsigned long a, unsigned long b);


               The first evaluates true when a, as a snapshot of jiffies, represents a time after b,
               the second evaluates true when time a is before time b, and the last two compare for
               “after or equal” and “before or equal.” The code works by converting the values to
               signed long, subtracting them, and comparing the result. If you need to know the dif-
               ference between two instances of jiffies in a safe way, you can use the same trick:


               diff = (long)t2 - (long)t1;.


               You can convert a jiffies difference to milliseconds trivially through:


                     msec = diff * 1000 / HZ;


               Sometimes, however, you need to exchange time representations with user space
               programs that tend to represent time values with struct timeval and struct
               timespec. The two structures represent a precise time quantity with two numbers:
               seconds and microseconds are used in the older and popular struct timeval, and sec-
               onds and nanoseconds are used in the newer struct timespec. The kernel exports
               four helper functions to convert time values expressed as jiffies to and from those
               structures:


                     #include <linux/time.h>
                     unsigned long timespec_to_jiffies(struct timespec *value);
                     void jiffies_to_timespec(unsigned long jiffies, struct timespec *value);
                     unsigned long timeval_to_jiffies(struct timeval *value);
                     void jiffies_to_timeval(unsigned long jiffies, struct timeval *value);


               Accessing the 64-bit jiffy count is not as straightforward as accessing jiffies. While
               on 64-bit computer architectures the two variables are actually one, access to the
               value is not atomic for 32-bit processors. This means you might read the wrong value
               if both halves of the variable get updated while you are reading them. It’s extremely
               unlikely you’ll ever need to read the 64-bit counter, but in case you do, you’ll be glad
               to know that the kernel exports a specific helper function that does the proper lock-
               ing for you:


                     #include <linux/jiffies.h>
                     u64 get_jiffies_64(void);


               In the above prototype, the u64 type is used. This is one of the types defined by
               <linux/types.h>, discussed in Chapter 11, and represents an unsigned 64-bit type.
               If you’re wondering how 32-bit platforms update both the 32-bit and 64-bit counters
               at the same time, read the linker script for your platform (look for a file whose name
               matches vmlinux*.lds*). There, the jiffies symbol is defined to access the least sig-
               nificant word of the 64-bit value, according to whether the platform is little-endian
               or big-endian. Actually, the same trick is used for 64-bit platforms, so that the
               unsigned long and u64 variables are accessed at the same address.
               Finally, note that the actual clock frequency is almost completely hidden from user
               space. The macro HZ always expands to 100 when user-space programs include
               param.h, and every counter reported to user space is converted accordingly. This
               applies to clock(3), times(2), and any related function. The only evidence available to
               users of the HZ value is how fast timer interrupts happen, as shown in /proc/
               interrupts. For example, you can obtain HZ by dividing this count by the system
               uptime reported in /proc/uptime.



 
< Prev   Next >
Your Ad Here

RSS socialnet

Add to MyYahoo!
Subscribe in NewsGator Online
Add to Newsburst
Add to Google
Add to My AOL
Add to Pluck
Subscribe in FeedLounge
Add to Windows Live
Add to NetVibes
Subscribe in Rojo
Subscribe in Bloglines
Add to MyMSN
Add to Plusmo for your cellphone
Add to PageFlakes
Add to Technorati
Add to BlinkBits
Do you want to learn how to make a burglar alarm for your home today?