Avoiding deadlock

Avoiding deadlock is obviously something we would want to ensure. In addition to the points covered in the Locking guidelines section, there is one more key point, which is that the order in which multiple locks are taken matters; keeping the lock ordering consistent throughout will provide protection against deadlocks.

To understand why, let's re-look at the ABBA deadlock scenario we just covered (refer to the preceding table). Look at the table again: notice that thread A takes lock L1 and then attempts to take lock L2, while thread B does the opposite. We shall now represent this scenario, but with a key caveat: lock ordering! This time, we shall have a lock ordering rule; it could be as simple as this: first, take lock L1, and then take lock L2:

lock L1 --> lock L2

With this lock ordering in mind, we find the scenario could play out as follows:

Time Thread A Thread B
t1 Attempt to take lock L1 Attempt to take lock L1
t2 Gets lock L1
t3 <Waits for L1 to be unlocked> <--- In critical section of L1 --->
t4 Unlock L1
t5 Gets lock L1
t6 <--- In critical section of L1 ---> Attempt to take lock L2
t7 Unlock L1 Gets locks L2
t8 Attempt to take lock L2 <--- In critical section of L2 
t9 <Waits for L2 to be unlocked>                                                             --->
t10 Unlock L2
t11 Gets lock L2 <Continues with other work>
t12  <--- In critical section of L2 ---> ...
t13 Unlock L2 ...


The key point here is that both threads attempt to take locks in a given order; first L1, and then L2. In the preceding table, we can visualize a case in which thread B obtains the locks first, forcing thread A to wait. This is completely fine and expected; no deadlock occurring is the whole point.

The precise ordering itself does not really matter; what does matter is the fact that the designers and developers document the lock ordering to be followed and stick to it.

The lock ordering semantics, and indeed developer comments regarding this key point, can be often found within the source tree of the Linux kernel (ver 4.19, as of this writing). Here's one example: virt/kvm/kvm_main.c

...
/*
 * Ordering of locks:
 *
 * kvm->lock --> kvm->slots_lock --> kvm->irq_lock
 */
...

So, looking back at our first table, we can now clearly see that the deadlock occurred because the lock ordering rule was violated: thread B took lock L2 before taking lock L1!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.143.22.26