Calls to cpu_relex will be executed in a system-related manner. In many systems, it does not do anything at all. This method should be explicitly avoided. For the arm system:
# Define cpu_relax () barrier ()
That is to say, running a busy wait on ARM is equivalent:
While (time_before (jiffies, J1 ));
This busy Wait seriously reduces system performance. If the kernel is not configured as preemptible, this loop completely locks the processor during the delay and the computer will completely die until J1. If you run a preemptible kernel, it will improve a little, but waiting for the system to be preemptible is still a waste of resources. Worse, jiffies will not be updated if the interruption happens to be disabled when it enters the loop, and the while condition will always be true, and running a preemptible kernel will not be helpful, the only solution is to restart.
Transfer Processor
Busy waiting increases the system load and a better technology must be found: Release the CPU when no CPU is needed. This can be achieved by calling the schedule function (declared in <Linux/sched. h> ):
While (time_before (jiffies, J1 )){
Schedule ();
}
Running idle tasks (process number 0, also known as Swapper for historical reasons) when the computer is idle can reduce the workload of the processor, reduce the temperature, and increase the service life.
Timeout
The best way to implement latency is to let the kernel complete the corresponding work for us.
(1) if the driver uses a waiting queue to wait for some other events and wants to ensure that it runs within a specific period of time, use:
# Include <Linux/Wait. H>
Long wait_event_timeout (wait_queue_head_t Q, condition, long timeout );
Long wait_event_interruptible_timeout (wait_queue_head_t Q, condition, long timeout );
/* These functions sleep on a given queue, but they are returned after timeout (expressed as jiffies. If the process times out, the function returns 0. if the process is awakened by other events, the system returns the remaining latency Implementation represented by jiffies. The returned value is never a negative value */
(2) The schedule_timeout function is provided in the kernel to enable the process to be awakened upon timeout and not wait for a specific event (to avoid the Declaration and use of a redundant waiting queue header:
# Include <Linux/sched. h>
Signed long schedule_timeout (signed long timeout );
/* Timeout is the number of jiffies to be delayed. The return value is 0 unless this function is returned before the given timeout is lost. Schedule_timeout requires the caller to set the current process status first. To obtain an uninterrupted latency, use task_uninterruptible instead. If you forget to change the status of the current process, calling schedule_time is like calling shcedule to create an unused timer. A typical call is as follows :*/
Set_current_state (task_interruptible );
Schedule_timeout (Delay );
Short latency
When a device driver needs to handle hardware latencies (latency latencies), the latency involved is usually several milliseconds at most. In this case, the kernel function ndelay should not rely on the clock, udelay and mdelay, respectively. They delay the execution of the specified number of nanoseconds, the number of microseconds or the number of milliseconds, defined in <ASM/delay. h>. The prototype is as follows:
# Include <Linux/delay. h>
Void ndelay (unsigned long nsecs );
Void udelay (unsigned long usecs );
Void mdelay (unsigned long msecs );
It is important to remember that these three delayed functions are busy waiting; other tasks cannot run when time is lost. Every system implements udelay, but other functions may be undefined. If they are not defined, <Linux/delay. h> provides a default udelay-based version. In all cases, the obtained latency must be at least the required value, but there may be more. Udelay uses a software loop based on the processor speed calculated at startup and the number of cycles determined using the integer variable loos_per_jiffy.
To avoid Integer Overflow in cyclic computing, there is an upper limit on the values passed to udelay and ndelay. If your module cannot load or display an unsolved symbol :__ bad_udelay, this means that you use too many parameters when calling udleay.
As a general rule: if you try to delay several thousand seconds, you should use udelay instead of ndelay. Similarly, latency in milliseconds should be completed using mdelay instead of a more fine-grained function.
Another way to get latency in milliseconds (and longer) instead of busy waiting is to use the following function (declared in <Linux/delay. h> ):
Void msleep (unsigned int millisecs );
Unsigned long msleep_interruptible (unsigned int millisecs );
Void ssleep (unsigned int seconds)
If the latency is longer than the request, schedule_timeout, msleep, or ssleep should be used.
--------------------------------------------------------------------------------
Kernel Timer
You can use the kernel timer when you need to schedule an action that occurs later and do not block the current process when the time is reached. The kernel timer is used to schedule a function to run at a specific time (based on the clock) in the future, so as to complete various tasks.
The kernel timer is a data structure that tells the kernel to use user-defined parameters to execute a user-defined function at a user-defined time point. The function is located in <Linux/Timer. h> and kernel/Timer. c. The scheduled functions are almost certainly not run while the processes that register them run, but asynchronously. In fact, the kernel timer is usually implemented as a result of "software interruption. When running outside the process context (that is, in the interrupt context)ProgramThe following rules must be observed:
(1) Access to user space is not allowed;
(2) The current pointer has no significance in the atomic state;
(3) sleep or scheduling is not allowed. For example, calling kmalloc (..., gfp_kernel) is illegal, and semaphores cannot be used because they may sleep.
By calling the in_interrupt () function, you can tell whether it is running in the interrupt context. No parameters are required and if the processor is currently running in the interrupt context, a non-zero value is returned.
Source: http://www.diybl.com/course/6_system/linux/Linuxjs/20081213/153686_4.html