Chapter 6 Time Flow
At this point, we basically know how to write a complete character module. In the real equipment driver, in addition to achieving the necessary operations, you have to do more, such as timing, memory management, hardware access, and more. Fortunately, many mechanisms provided in the kernel can simplify the work of driver developers, and we will discuss some kernel resources that drivers can access in the following chapters. This chapter, let's first see how the kernel code is processed for time problems. Increment in complex degree, this problem includes:
Understanding how the kernel time mechanism gets the current time how to schedule how to schedule an operational delay to execute an asynchronous function to the specified time. 6.1 Interval in the kernel. We must first involve the clock interrupt, the operating system is interrupted by clock interrupt to determine the interval . Interrupt is asynchronous event, usually triggered by external hardware. When the interrupt occurs, the CPU stops the ongoing task, and turn on another special code (ie interrupt service routine, also known as ISR) to respond to this interrupt. The implementation of interrupts and ISR will be discussed in Chapter 9. The clock interrupt is generated by the system timer at a periodic interval, which is set by the kernel according to the value of Hz, and Hz is a constant associated with the architecture, defined in the file
The most famous counter register is TSC (TimeStamp Counter, Time Stamp Counter), which provides the register from the Pentium processor of the x86 and includes all CPUs later. It is a 64-bit register that records the number of CPU clock cycles, kernel space and user space can read it. After the header file
Unsigned long iNi, end; RDTSCL (INI); RDTSCL (END); Printk ("Time Lapse:% li / n", end - ini); other platforms also provide similar functions, and in the internal nuclear head files A function that is unrelated to the architecture can replace RDTSC, which is get_cycles, which is introduced during the development of version 2.1. The prototype is:
#include
#define rdtscl (dest) / _ _ASM_ _ _ _Volatile__ ("MFC0% 0, $ 9; NOP": "= r" (DEST))
Note: The NOP instruction is required to prevent the compiler from accessing the target register immediately after the instruction MFC0. This interlock is typical in the RISC processor, and during the delay period, the compiler can still schedule other instructions. We use NOP here because embedded instructions are a black box for compilers and cannot be optimized. By using this macro, the MIPS processor can perform the same code as the X86 shown in the previous side. The interest of the GCC embedded assembly is that the allocation of the general register is done by the compiler. The% 0 used in this macro is only "parameter 0" placeholder, parameter 0 is defined by any register (R) "as an output (=). This macro also illustrates the output register to correspond to the C expression DEST. The syntax function of embedding compilation is strong but also complicated, especially in the platform that is restricted to each register, such as the x86 series. A complete grammatical description is provided in the GCC documentation, usually found in Info. The short C code segment showing this show has been running on a K7 class X86 processor and a MIPS VR4181 processor (using just macro). The time given by the former is consumed to be 11 clock cycles, and the latter is only 2 clock cycles. This is understood because the RISC processor typically runs a command per hour cycle. 6.2 Getting the current time core usually gets the current time through the Jiffies value. This value is indicated by the most recent system to start to the current interval, and it is not related to the device driver because its life is limited to the system's runtime. However, the driver can utilize the current value of Jiffies to calculate the time interval between different events (such as using it in the input device driver to resolve the midst of the midst). Briefly, the measurement time interval is sufficient, and if you need to measure a shorter time, you can use a register-specific register. The driver generally does not need to know the wall clock time (referring to the time of daily life), usually only the wall clock time is required like CRON and AT. The case where the wall clock time is to use the special case of the device driver, at which time the wall clock time can be converted into a system clock via the user program. Direct treatment wall clock often means that some strategy is being realized, should be carefully examined. If the driver really needs to get the current time, you can use the Do_getTimeOfDay function. This function does not return today's week a week or similar information; it is a pointer variable pointing to Struct TimeVal in seconds or microsecond values, which is also the same variable in the GetTimeOfDay system call. The prototype of Do_gettimeOfDay is as follows: #include
Void get_fast_time (struct timeval * TV); get the code for the current time can be found in the Just ("Just In Time" module, the source file can be obtained from O'Reilly's FTP site. The JIT module will create the / proc / currentime file, read the file to return three items in the form of the ASCII code: The current time returned by Do_getTimeOfDay from the xi_gettimeofday Current Time Jiffies of the current time Jiffies, we choose the dynamic / proc file, Because this module code amount will be small - it is not worthwhile to write a complete device driver for returning three lines of text. If you read this file multiple times in a clock tick with a CAT command, you will find that Xtime and Do_getTimeOfDay are different, and the number of XTime updates is not so frequent:
morgana% cd / proc; cat currentime currentime currentime gettime: 846157215.937221 xtime: 846157215.931188 jiffies: 1308094 gettime: 846157215.939950 xtime: 846157215.931188 jiffies: 1308094 gettime: 846157215.942465 xtime: 846157215.941188 jiffies: 1308095