1. About races
If there are two processes that open the device for data write operation at the same time, when process A writes data, it will apply for a new device memory and append one to the device dev data link table. The new quantum, which points the pointer to this new device memory block, and the same operation in the process B write operation, so if no driver modification is done, because the device is opened by both processes at the same time, the two processes have the same device data link table. The information will be modified to the same data. Obviously, the data created by the first operation will be overwritten by the subsequent process, which is the result of the race.
However, the less positive argument is that this does not happen on a single processor because the code running in the kernel is non-preemptive, meaning that the processor can only process one code at a time. But a multiprocessor system can happen.
LINUX provides a race solution:
1) semaphore semaphore, used for mutual exclusion
#include
It is very simple, that is A tag needs to be defined in the data block that needs to be avoided. When a process is used, the flag is set to 0, indicating that the signal is already occupied and can no longer be used. All processes must first check the tag if they want to access the data block. If it is 0, it means that a process is occupying, you must wait.
Therefore there is a semaphore tag in the data structure Scull_Dev of scull0.
But the semaphore is handled by the kernel, because we want the process to be semaphore, if the semaphore is used, the process should be handed over to the kernel, waiting, not looped by ourselves. Check and wait for semaphores.
ok, since it has to be handed over to the kernel management, the semaphore must be initialized.
sema_init(&scull_devices.sem, 1); //; Register a semaphore, initialized to 1, indicating that it is available.
When you need to get a semaphore, call down_interruptable(&sem), release the semaphore up(&sem), up and wake up the process that is waiting for the semaphore.
if (down_interruptable(&dev->sem)) return -ERESTARTSYS; //; If it fails, return directly, can't call up(&sem)//;data operations...
up(&dev->sem);
Note that you should be careful with the use of semaphores, visible if a process holds a semaphore and it fails when it releases the semaphore If you do, other processes will block.
In addition, because the semaphore will cause the process to sleep, the semaphore cannot be applied in the interrupt processing.
2) Lock
As you can see, using a semaphore, if one process holds a semaphore, another process will go to sleep. In many cases, the process does not need to wait for sleep. For example, interrupt processing is not allowed to enter sleep, or in some cases, it is simply to test whether public data is occupied by other processes. If it is occupied, it will be retested until it can be used. Use a spinlock. Of course, when the spin lock is used, the processor is occupied, so the spin lock is suitable for holding the data for a relatively short time, and it is absolutely impossible to go to sleep when the lock is held.
#include
spinlock_t my_lock = SPIN_LOCK_UNLOCKED; or spin_lock_init(&my_lock); declare/create a lock
spin_lock(spinlock_t *my_lock); get the given lock If the lock is occupied, it spins until the lock is available. When the spin_lock returns, the calling function holds the lock until the spin_unlock (spinlock_t *my_lock) is released; the lock is released
2 About blocking and non-blocking < Br>
2.1 About blocking
There is a problem with the read call. When the device has no data to read, there are two ways to solve it. One is to prevent the direct read failure from jumping out. The second is to block the read operation, the process goes to sleep, and wakes up when there is data.
Discuss the blocking IO here to handle sleep and wake up.
Sleep is when a process needs to wait for an event, it should be temporarily suspended, let out the CPU, and then wake up after the event arrives.
One way to handle sleep is to add a process to the wait queue:
1) First you need to declare and initialize a wait queue entry.
#include
wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
If you are awaiting a static global wait queue, you can use the above two definitions instead of
DECLARE_WAIT_QUEUE_HEAD( My_queue); //static declaration will be automatically initialized at compile time
2) use initialized wait queue item
call interrupt30_and_on(&my_queue) when it needs to join the kernel wait queue ; or sleep_on(&my_queue)
When wakeup is required, call wake_up_interruptible(&my_queue); or wake_up(&my_queue)
3)interruptible_sleep_on() defect
a. The resulting race:
To understand the possible race state caused by interruptible_sleep_on() and other sleep_on functions, you need to know more about the implementation of interruptible_sleep_on().
The waiting queue is actually a queue list. The data in the linked list is of type wait_queue_t. The simplified internal interruptible_sleep_on() is probably like this:
#include
wait_queue_t wait; //; Define a wait queue
init_wait_queue_entry(&wait, current); //;Initialize
current->state = TASK_INTERRUPTILBE; //; Set to sleep state, will enter Sleep
add_wait_queue(&my_queue, &wait); //; Add the wait queue item we defined to this wait queue
schedule(); //; actually go to sleep
remove_wait_queue(&my_queue, &wait); //; Event arrives, schedule() returns
The race happens in current->state = TASK_INTERRUPTIBLE and schedule() In some cases, when the driver is ready to go to sleep, that is, when the current->state has been set, there may be just data arrival. At this time, wake_up will not wake up the process that has not actually gone to sleep, which may result in The process has been sleeping because it has not responded to wake up, thus generating this competition. This race is very prone. The solution is to not use interruptible_sleep_on(), but instead use its internal implementation directly.
Example:
#include
wait_queue_t wait; //;Define a wait queue
init_wait_queue_entry(&wait, current); //; Initialize
add_wait_queue(&my_queue, &wait); //; Add the wait queue item we defined to this wait queue
while(1){
current->state = TASK_INTERRUPTILBE; //; set to sleep, will go to sleep
if (short_head != short_tail) break; //; test if there is data arriving, if any, jump out
schedule(); //;Real to sleep
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&my_queue, &wait); //; Event arrives, schedule() returns
In fact, we can do these complicated things without the kernel. The kernel defines a macro
wait_event_interruptible(wq, condition); or wait_event(wq, Condition) condition is the condition of the test
The Linux command line is useful, efficient, and fun, but sometimes dangerous, especially if you are
Webalizer is a commonly used web log analysis script under Linux, of course, for nginx. I am curious
The Go language (ie Golang) is a programming language originally developed by Google. It has severa
The Linux operating system has been around for 20 years without knowing it. Just 20 years ago, just
LVS ipvsadm Command Reference Guide
Eight solutions for Linux hard disk problems
PC and NB running the lowest processing of modern desktop Linux
How to re-hang the mongo replica set slave server for a long time to re-attach to the set
In the Linux system, use the DD command to make the ISO image U disk boot disk
What does the Unix/linux kernel play in the system?
Configuring PHP environment under Linux XAMPP basic tutorial
Arm linux boot process into the kernel
Use Ghost to achieve backup of Linux system
Solve the win8 system.exe program disk takes up 100% of the tutorial
Win10 system uses IE browser to watch online video how to solve the green screen?
Win7 computer watching video black screen has sound solution tutorial
I have evidence! Let Win7 help you monitor the whole process
How does Win7 cancel the unknown publisher warning?
Optimize your computer system to lose weight 8 ways (2)
Win XP super support tool set comprehensive contact
SSD ReadyCache's simplest computer acceleration solution
What should I do if the text is incomplete after Win10 is updated to 9860? After the release of the
Win7 boot prompts Windows can not find the file how to solve?