200 likes | 230 Views
Explore race conditions, shared data sync, locking, deadlocks, and lock ordering in Linux Kernel synchronization. Understand when to use different lock types and prevent concurrency bugs.
E N D
Kernel Synchronization David Ferry, Chris Gill CSE 522S - Advanced Operating Systems Washington University in St. Louis St. Louis, MO 63143
Linux is a Preemptive Kernel The Linux kernel executes concurrently with itself: • Multiple processors (CONFIG_SMP) • Interrupts • Kernel Threads Many data structures can be accessed concurrently from different contexts, which may cause concurrency bugs. CSE 522S – Advanced Operating Systems
Single Variable Race Condition Suppose two concurrent processes are accessing avariable X with initial value of 1, what is the final value of X?: Thread 1: load X X = X + 1 store X Thread 2: load X X = X + 1 store X CSE 522S – Advanced Operating Systems
Data Structure Race Condition Suppose two threads are accessing a list: Node A Node B Node C Next Next Next Deleter: Node* = A->Next A->Next = B->Next Kfree(Node); Reader: Node* = A->Next Value = Node->val CSE 522S – Advanced Operating Systems
Shared Data Synchronization Accessing shared data requires appropriate synchronization Protect data, not code! A region of code that accesses shared data is called a critical section CSE 522S – Advanced Operating Systems
Basic Kernel Synchronization The Linux kernel supports most of the same synchronization primitives as userspace. • Atomic variables • Spin locks (non-sleepable locks) • Mutexes (sleepable locks) • Reader-writer locks • Semaphores CSE 522S – Advanced Operating Systems
Locking Example Node A Node B Node C Next Next Next Deleter: lock( list_lock ); Node* = A->Next; A->Next = B->Next; Kfree(Node); Unlock(list_lock); Reader: lock( list_lock ); Node* = A->Next; Value = Node->val; unlock( list_lock); CSE 522S – Advanced Operating Systems
When to Use Different Types of Locks Spin locks - very short lock durations and/or very low overhead requirements Mutexes - Long lock duration and/or process needs to sleep while holding lock Atomics - When shared data fits inside a single word of memory Other locks - special cases CSE 522S – Advanced Operating Systems
Sleeping With Locks Sleeping with a lock is generally a bad idea unless absolutely necessary • Delays other processes • Deadlock risk: is it guaranteed to eventually wake up and release the lock? A process cannot sleep holding a spinlock. • Restructure code to back out of lock • Use a mutex instead CSE 522S – Advanced Operating Systems
Deadlock Deadlock occurs when a process can never progress while waiting for a lock, e.g.: Thread 1: lock( A ); lock( B ); //critical section unlock( A ); unlock( B ); Thread 2: lock( B ); lock( A ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Deadlock Deadlock occurs when a process can never progress while waiting for a lock, e.g.: Thread 1: lock( A ); lock( B ); //critical section unlock( A ); unlock( B ); Thread 2: lock( B ); lock( A ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Deadlock Deadlock occurs when a process can never progress while waiting for a lock, e.g.: Thread 1: lock( A ); lock( B ); //critical section unlock( A ); unlock( B ); Thread 2: lock( B ); lock( A ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Deadlock Deadlock occurs when a process can never progress while waiting for a lock, e.g.: Thread 1: lock( A ); lock( B ); //critical section unlock( A ); unlock( B ); Thread 2: lock( B ); lock( A ); //critical section unlock( B ); unlock( A ); Lock A Deadlock! Lock B CSE 522S – Advanced Operating Systems
Lock Ordering Always acquire and release locks in the same order! (Does not solve all deadlocks, but it’s a good place to start.) Thread 1: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Thread 2: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Lock Ordering Always acquire and release locks in the same order! (Does not solve all deadlocks, but it’s a good place to start.) Thread 1: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Thread 2: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Lock Ordering Always acquire and release locks in the same order! (Does not solve all deadlocks, but it’s a good place to start.) Thread 1: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Thread 2: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Lock Ordering Always acquire and release locks in the same order! (Does not solve all deadlocks, but it’s a good place to start.) Thread 1: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Thread 2: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
Lock Ordering Always acquire and release locks in the same order! (Does not solve all deadlocks, but it’s a good place to start.) Thread 1: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Thread 2: lock( A ); lock( B ); //critical section unlock( B ); unlock( A ); Lock A Lock B CSE 522S – Advanced Operating Systems
The BKL is No Longer Used The Big Kernel Lock (BKL) was the first lock introduced to the kernel • Locks the entire kernel • Provides correctness, but very slow • New uses are prohibited • Gradually replaced with finer-grained locking schemes CSE 522S – Advanced Operating Systems