1. Simple deadlock example T1: acquire(mutexA); acquire(mutexB); // do some stuff release(mutexB); release(mutexA); T2: acquire(mutexB); acquire(mutexA); // do some stuff release(mutexA); release(mutexB); ======================================================================= 2. More subtle deadlock example Let M be a monitor (shared object with methods protected by mutex) Let N be another monitor class M { private: Mutex mutex_m; // instance of monitor N N another_monitor; // Assumption: no other objects in the system hold a pointer // to our "another_monitor" public: M(); ~M(); void methodA(); void methodB(); }; class N { private: Mutex mutex_n; Cond cond_n; int navailable; public: N(); ~N(); void* alloc(int nwanted); void free(void*); } int N::alloc(int nwanted) { acquire(&mutex_n); while (navailable < nwanted) { wait(&cond_n, &mutex_n); } // peel off the memory navailable −= nwanted; release(&mutex_n); } void N::free(void* returning_mem) { acquire(&mutex_n); // put the memory back navailable += returning_mem; broadcast(&cond_n, &mutex_n); release(&mutex_n); } void M::methodA() { acquire(&mutex_m); void* new_mem = another_monitor.alloc(int nbytes); // do a bunch of stuff using this nice // chunk of memory n allocated for us release(&mutex_m); } void M::methodB() { acquire(&mutex_m); // do a bunch of stuff another_monitor.free(some_pointer); release(&mutex_m); } QUESTION: What’s the problem? ======================================================================= 3. Locking brings a performance vs. complexity trade−off /* * linux/mm/filemap.c * * Copyright (C) 1994-1999 Linus Torvalds */ /* * This file handles the generic file mmap semantics used by * most "normal" filesystems (but you don't /have/ to use this: * the NFS filesystem used to do this differently, for example) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "internal.h" #define CREATE_TRACE_POINTS #include /* * FIXME: remove all knowledge of the buffer layer from the core VM */ #include /* for try_to_free_buffers */ #include /* * Shared mappings implemented 30.11.1994. It's not fully working yet, * though. * * Shared mappings now work. 15.8.1995 Bruno. * * finished 'unifying' the page and buffer cache and SMP-threaded the * page-cache, 21.05.1999, Ingo Molnar * * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli */ /* * Lock ordering: * * ->i_mmap_rwsem (truncate_pagecache) * ->private_lock (__free_pte->__set_page_dirty_buffers) * ->swap_lock (exclusive_swap_page, others) * ->i_pages lock * * ->i_mutex * ->i_mmap_rwsem (truncate->unmap_mapping_range) * * ->mmap_sem * ->i_mmap_rwsem * ->page_table_lock or pte_lock (various, mainly in memory.c) * ->i_pages lock (arch-dependent flush_dcache_mmap_lock) * * ->mmap_sem * ->lock_page (access_process_vm) * * ->i_mutex (generic_perform_write) * ->mmap_sem (fault_in_pages_readable->do_page_fault) * * bdi->wb.list_lock * sb_lock (fs/fs-writeback.c) * ->i_pages lock (__sync_single_inode) * * ->i_mmap_rwsem * ->anon_vma.lock (vma_adjust) * * ->anon_vma.lock * ->page_table_lock or pte_lock (anon_vma_prepare and various) * * ->page_table_lock or pte_lock * ->swap_lock (try_to_unmap_one) * ->private_lock (try_to_unmap_one) * ->i_pages lock (try_to_unmap_one) * ->zone_lru_lock(zone) (follow_page->mark_page_accessed) * ->zone_lru_lock(zone) (check_pte_range->isolate_lru_page) * ->private_lock (page_remove_rmap->set_page_dirty) * ->i_pages lock (page_remove_rmap->set_page_dirty) * bdi.wb->list_lock (page_remove_rmap->set_page_dirty) * ->inode->i_lock (page_remove_rmap->set_page_dirty) * ->memcg->move_lock (page_remove_rmap->lock_page_memcg) * bdi.wb->list_lock (zap_pte_range->set_page_dirty) * ->inode->i_lock (zap_pte_range->set_page_dirty) * ->private_lock (zap_pte_range->__set_page_dirty_buffers) * * ->i_mmap_rwsem * ->tasklist_lock (memory_failure, collect_procs_ao) */ static void page_cache_delete(struct address_space *mapping, struct page *page, void *shadow) { XA_STATE(xas, &mapping->i_pages, page->index); unsigned int nr = 1; .... [the point is: fine−grained locking leads to complexity.]