Concurrency and race of Linux device drivers (ii)

Source: Internet
Author: User
Tags semaphore

In fact, this blog is reading ldd3 Some of the summary, to consolidate their own learning, but also convenient for later use. You can also read the original LDD3 directly.


Lock traps are the so-called lock traps that prevent deadlocks.        Ambiguous rules: 1, whether it is a semaphore or a spin lock, the lock owner is not allowed to acquire this lock for the second time (deadlock). 2, the system directly call those functions to obtain a semaphore, to protect the structure of the device to access. Access to the internal functions can be locked as needed.
Lock sequence Rules: 1, if you want to get a series of locks, then you can follow a certain sequence of rules to obtain the lock, that is: To obtain multiple locks, the order of the lock has been, 2, if you want to get their own local lock and the central lock of the system, then obtain their own local lock, and then to obtain a central lock; If you want to get semaphores and spin locks, you need to get the semaphore first, because the function that releases the semaphore may be dormant;
Lock-Free algorithm: There are a lot of lock-free algorithm, LDD3 mentioned a loop buffer, feeling very useful (also encountered in the work). Loop buffer: For example, an array a[9] is a critical section, you can read data from the a[0] end toward the a[9] end, and write data from the a[9] end to the a[0] end. is an algorithm to chase each other, so that the data can be guaranteed to be consistent without a lock, the buffer is encountered in the work, the request structure is placed in a circular queue, and the kernel at the other end of the queue to read the request structure to execute.
Atomic operation atomic operations are used very frequently in the kernel source code, in fact, this atomic operation is mainly for the variable operation. It's essentially a lock, because if we lock a variable with a lock mechanism, it's a bit wasteful. After all, the lock still consumes some CPU time, for a small variable, the use of locks, not worth it.        So the atomic operation was born. header file <asm/atomic.h>, data structure is: atomic_t
void Atomic_set (atomic_t *v, int i); Dynamic initialization, which is atomic assignment: v = i atomic_t v = atomic_init (o);//static initialization, initialization at compile time
int Atomic_read (atomic_t *v);//Returns the current value of V
void Atomic_add (int i, atomic_t *v),//The atom variable to which I was added to V, returned as void, because the return value is not required in most cases, so it is not returned, reducing the cost of the function; void Atomic_sub (i n i, atomic_t *v);//Contrary to the function above
void Atomic_inc (atomic_t *v);//self-increment void Atomic_dec (atomic_t *v);//self-reduction
int atomic_inc_and_test (atomic_t *v);       int atomic_dec_and_test (atomic_t *v);       int atomic_sub_and_test (int i, atomic_t *v); Perform the operation and test the result: Returns True if the atomic value is 0 after the operation;
int atomic_add_negative (int i, atomic_t *v);//Add I to V, if the result is negative, return true, otherwise false;
int Atomic_add_return (int i, atomic_t *v);               int Atomic_sub_return (int i, atomic_t *v);               int Atomic_inc_return (atomic_t *v);               int Atomic_dec_return (atomic_t *v); Perform the action above and then return the new value after the Operation V
Bit operations, like atomic operations, are essentially a locking mechanism, but relatively small in size. Semaphores and spin locks are protections for a piece of code, a block of memory, or an atomic operation that protects a variable, while a bitwise operation is an atomic operation that sets the individual bits in the variable.        Because atomic operations are very fast, they can be executed with a single machine instruction, so no interruption is allowed. NR parameters are generally defined as int, but some different systems are positioned as unsigned long and so on;
void Set_bit (nr, void *addr),///Set addr point to the data item of the NR bit void Clear_bit (nr, void *addr);//clear addr points to the NR bit of the data item
void Change_bit (nr, void *addr);//Toggle Pointing position
Test_bit (nr, void *addr);//return current value
int Test_and_set_bit (nr, void *addr);        int Test_and_clear_bit (nr, void *addr);        int Test_and_change_bit (nr, void *addr); Performs the corresponding operation, and returns the previous value
Seqlock Seqlock enables fast, lock-free access to shared resources. Seqlock can be used when the resources to be protected are small, simple, frequently accessed, and write access rarely occurs and must be fast. Seqlock allows the reader to freely access, but to check if there is a conflict with the writer, to re-read the data when a conflict occurs, Seqlock does not protect the data structure that contains the pointer, because the reader may read an invalid pointer when the writer modifies the data; header file <linux        /seqlock.h> initialization: seqlock_t lock1 = seqlock_unlocked;//static initialization seqlock_t Lock2; Seqlock_init (&AMP;LOCK2);//Dynamic initialization
When the reader accesses the critical section, it obtains an unsigned integer, then completes its operation, obtains the next integer when exiting, compares it to see if it is equal, and if not equal, needs to retrieve the integer = = "complete operation = =" Exit to get the parameter comparison; code as follows: unsigned int seq;               do {seq = Read_seqbegin (&the_lock);        /* Complete the corresponding work */}while (read_seqretry (&the_lock, seq)); This type of lock is only used to protect simple calculations, but data consistency is required, so inconsistencies must be re-read data;
If you use Seqlock in an interrupt-handling routine, you should use an IRQ-safe version: Unsigned int read_seqbegin_irqsave (seqlock_t *lock, unsigned long flags); int Read_seqretry_irqrestore (seqlock_t *lock,unsigned int seq, unsigned long flags);
The writer must obtain a mutex when entering a critical section protected by Seqlock: void Write_seqlock (seqlock_t *lock); void Write_sequnlock (seqlock_t *lock);
Since write locks are implemented using spin locks, spin locks control write access, so common variants of the spin lock can be used: void Write_seqlock_irqsave (seqlock_t *lock, unsigned long flags);        void Write_seqlock_irq (seqlock_t *lock); void Write_seqlock_bh (seqlock_t *lock);
void Write_sequnlock_irqrestore (seqlock_t *lock, unsigned long flags);        void Write_sequnlock_irq (seqlock_t *lock,); void Write_sequnlock_bh (seqlock_t *lock);
Reprint Address: http://blog.csdn.net/yuzhihui_no1/article/details/46762723

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Concurrency and race of Linux device drivers (ii)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.