The linux kernel lock principle BKL is designed to introduce large-granularity locks when kernelhacker is not sure about multi-processor synchronization. His design idea is that once a kernel path gets the lock, all other kernel paths cannot get the lock again ....
The linux kernel lock principle BKL is designed to introduce large-granularity locks when the kernel hackers are not sure about multi-processor synchronization. His design philosophy is that once a kernel path gets the lock, all other kernel paths cannot get the lock. The spin lock object is generally a global variable. the large kernel lock object is a piece of code, which may contain multiple global variables. The problem is that although A only needs to access global variable a through mutual exclusion, it locks global variable B and thus B cannot access B. The first implementation of a large kernel lock relies on a global spin lock. However, we feel that the overhead of this lock is too large and affects real-time performance. Therefore, we changed the spin lock to mutex, however, the blocking time is generally not very long, so the suspension and wake-up of lock failure are very costly, so it was changed to spin lock implementation later. Large kernel locks are usually used in file systems and drivers. Currently, kernel hackers are still trying to remove the large kernel lock from linux. Next we will analyze the implementation of the large kernel lock. We mentioned earlier that there are two major kernel locks: Spin Locks and mutex locks. If the mutex lock is implemented, the large kernel lock cannot be used in the interrupted environment, because scheduling prohibition is a golden rule. Can I schedule tasks within a large kernel lock? We know that if a kernel process gets resources, it should be done to release the resources as soon as possible, so that the next competitor can get the resources. Therefore, it is a general consensus that resource holders should not sleep. But the big kernel lock does not think so. users who hold the big kernel lock allow sleep-although we do not encourage this, in the design scheme of the big kernel lock of the kernel, during the process switch, check whether the current process holds the large kernel lock and releases it. after obtaining the cpu again, try to catch the large kernel lock. That is to say, the process can sleep when holding a large kernel lock, which leads to resource starvation. in this case, the large kernel lock based on the spin lock implements static inline void _ lock_kernel (void) {preempt_disable (); if (unlikely (! _ Raw_spin_trylock (& kernel_flag) {/** If preemption was disabled even before this * was called, there's nothing we can be polite * about-just spin. */if (preempt_count ()> 1) {_ raw_spin_lock (& kernel_flag); return; www.2cto.com}/** Otherwise, let's wait for the kernel lock * with preemption enabled .. */do {preempt_enable (); while (spin_is_locked (& kernel_flag) cpu_relax (); preempt_disable ();} while (! _ Raw_spin_trylock (& kernel_flag) ;}} void _ lockfunc lock_kernel (void) {int depth = current-> lock_depth + 1; if (likely (! Depth) _ lock_kernel (); current-> lock_depth = depth;} the code in www.2cto.com indicates, 1) if the current process does not repeat the lock, try to catch the lock and add 1 to the lock depth. The purpose of this operation is to avoid re-locking. 2) in actual locking, preemptible is disabled first. if the attempt to lock fails, preemptible is disabled based on whether or not the lock_kernel is called to determine whether the round robin of the backend or large portal is performed. If it is a large kernel lock kernel_lock implemented by mutex, then step 1 directly mutex_lock -- either succeed or block. As we mentioned earlier, when a process is switched, the system checks whether the current process holds a large kernel lock. this is done in schedule. Asmlinkage void _ sched schedule (void) {www.2cto.com release_kernel_lock (prev); context_switch (); unlock (current);} release_kernel_lock determines if the current process holds a large kernel lock, the lock is released. Reacquire_kernel_lock checks whether the current process holds a large kernel lock before being switched after the process is scheduled back again. If any, it indicates that during Process switching, the current process's large kernel lock is forcibly released and needs to be acquired again. It should be noted that the spin lock version: release_kernel_lock will also be preemptible after the lock is released, because it will be closed after a large kernel lock is obtained; reacquire_kernel_lock will be closed after the lock is acquired again. Focus on the implementation version of the spin lock implemented by _ reacquire_kernel_lock: After the lock is successfully captured, the lock is locked for Preemption. if the lock is not captured, the need resched mark is traversed until it exits. Be sure to compare it with lock_kernel. The mutex version is bullshit: int _ lockfunc _ reacquire_kernel_lock (void) {www.2cto.com int saved_lock_depth = current-> lock_depth; BUG_ON (saved_lock_depth <0 ); current-> lock_depth =-1; preempt_enable_no_resched (); mutex_lock (& kernel_sem); preempt_disable (); current-> lock_depth = saved_lock_depth; return 0 ;} we have seen that the mutex implementation of kernel_lock is a mutex_lock, and here the _ reacquire_kernel_lock has some details differences. 1) first, set the lock depth of the current process to-1, which indicates that no one locks. This means that if the mutex_lock in step 1 generates scheduling and enters the shedule again, the large kernel lock will not be released again because the lock has been released before _ reacquire_kernel_lock. 2) after the preemption is temporarily forcibly enabled, execute mutex_lock www.2cto.com because the preemption is disabled in schedule, and process switching is not allowed. 3) If the lock is caught, the preemption is restored to the preemption status before the _ reacquire_kernel_lock in schedule. 4) recover the lock depth to the depth before _ reacquire_kernel_lock to schedule and call the large kernel lock hold status before _ reacquire_kernel_lock. In short, remember two points for the large kernel lock: 1) a global variable is locked by a spinlock or mutex_lock. 2) when a process is switched, the system checks whether the current process holds a large kernel lock and takes the release and re-obtain actions, to support sleep of user code holding a large kernel lock. Author: chenyu105
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