€•ëŒsphinx.addnodes”Œdocument”“”)�”}”(Œ rawsource”Œ”Œchildren”]”(Œ translations”Œ LanguagesNode”“”)�”}”(hhh]”(hŒ pending_xref”“”)�”}”(hhh]”Œdocutils.nodes”ŒText”“”ŒChinese (Simplified)”…”�”}”Œparent”hsbaŒ attributes”}”(Œids”]”Œclasses”]”Œnames”]”Œdupnames”]”Œbackrefs”]”Œ refdomain”Œstd”Œreftype”Œdoc”Œ reftarget”Œ%/translations/zh_CN/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuŒtagname”hhh ubh)�”}”(hhh]”hŒChinese (Traditional)”…”�”}”hh2sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/zh_TW/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒItalian”…”�”}”hhFsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/it_IT/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒJapanese”…”�”}”hhZsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/ja_JP/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒKorean”…”�”}”hhnsbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/ko_KR/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒPortuguese (Brazilian)”…”�”}”hh‚sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/pt_BR/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubh)�”}”(hhh]”hŒSpanish”…”�”}”hh–sbah}”(h]”h ]”h"]”h$]”h&]”Œ refdomain”h)Œreftype”h+Œ reftarget”Œ%/translations/sp_SP/locking/locktypes”Œmodname”NŒ classname”NŒ refexplicit”ˆuh1hhh ubeh}”(h]”h ]”h"]”h$]”h&]”Œcurrent_language”ŒEnglish”uh1h hhŒ _document”hŒsource”NŒline”NubhŒcomment”“”)�”}”(hŒ SPDX-License-Identifier: GPL-2.0”h]”hŒ SPDX-License-Identifier: GPL-2.0”…”�”}”hh·sbah}”(h]”h ]”h"]”h$]”h&]”Œ xml:space”Œpreserve”uh1hµhhh²hh³Œ?/var/lib/git/docbuild/linux/Documentation/locking/locktypes.rst”h´KubhŒtarget”“”)�”}”(hŒ.. _kernel_hacking_locktypes:”h]”h}”(h]”h ]”h"]”h$]”h&]”Œrefid”Œkernel-hacking-locktypes”uh1hÈh´Khhh²hh³hÇubhŒsection”“”)�”}”(hhh]”(hŒtitle”“”)�”}”(hŒLock types and their rules”h]”hŒLock types and their rules”…”�”}”(hhÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhhØh²hh³hÇh´Kubh×)�”}”(hhh]”(hÜ)�”}”(hŒ Introduction”h]”hŒ Introduction”…”�”}”(hhîh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhhëh²hh³hÇh´K ubhŒ paragraph”“”)�”}”(hŒ_The kernel provides a variety of locking primitives which can be divided into three categories:”h]”hŒ_The kernel provides a variety of locking primitives which can be divided into three categories:”…”�”}”(hhþh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K hhëh²hubhŒ block_quote”“”)�”}”(hŒ4- Sleeping locks - CPU local locks - Spinning locks ”h]”hŒ bullet_list”“”)�”}”(hhh]”(hŒ list_item”“”)�”}”(hŒSleeping locks”h]”hý)�”}”(hjh]”hŒSleeping locks”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)�”}”(hŒCPU local locks”h]”hý)�”}”(hj2h]”hŒCPU local locks”…”�”}”(hj4h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khj0ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)�”}”(hŒSpinning locks ”h]”hý)�”}”(hŒSpinning locks”h]”hŒSpinning locks”…”�”}”(hjKh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KhjGubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubeh}”(h]”h ]”h"]”h$]”h&]”Œbullet”Œ-”uh1jh³hÇh´Khjubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Khhëh²hubhý)�”}”(hŒ‰This document conceptually describes these lock types and provides rules for their nesting, including the rules for use under PREEMPT_RT.”h]”hŒ‰This document conceptually describes these lock types and provides rules for their nesting, including the rules for use under PREEMPT_RT.”…”�”}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khhëh²hubeh}”(h]”Œ introduction”ah ]”h"]”Œ introduction”ah$]”h&]”uh1hÖhhØh²hh³hÇh´K ubh×)�”}”(hhh]”(hÜ)�”}”(hŒLock categories”h]”hŒLock categories”…”�”}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjƒh²hh³hÇh´Kubh×)�”}”(hhh]”(hÜ)�”}”(hŒSleeping locks”h]”hŒSleeping locks”…”�”}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj”h²hh³hÇh´Kubhý)�”}”(hŒ@Sleeping locks can only be acquired in preemptible task context.”h]”hŒ@Sleeping locks can only be acquired in preemptible task context.”…”�”}”(hj¥h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khj”h²hubhý)�”}”(hXMAlthough implementations allow try_lock() from other contexts, it is necessary to carefully evaluate the safety of unlock() as well as of try_lock(). Furthermore, it is also necessary to evaluate the debugging versions of these primitives. In short, don't acquire sleeping locks from other contexts unless there is no other option.”h]”hXOAlthough implementations allow try_lock() from other contexts, it is necessary to carefully evaluate the safety of unlock() as well as of try_lock(). Furthermore, it is also necessary to evaluate the debugging versions of these primitives. In short, don’t acquire sleeping locks from other contexts unless there is no other option.”…”�”}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Khj”h²hubhý)�”}”(hŒSleeping lock types:”h]”hŒSleeping lock types:”…”�”}”(hjÁh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K%hj”h²hubj )�”}”(hŒO- mutex - rt_mutex - semaphore - rw_semaphore - ww_mutex - percpu_rw_semaphore ”h]”j)�”}”(hhh]”(j)�”}”(hŒmutex”h]”hý)�”}”(hjØh]”hŒmutex”…”�”}”(hjÚh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K'hjÖubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÓubj)�”}”(hŒrt_mutex”h]”hý)�”}”(hjïh]”hŒrt_mutex”…”�”}”(hjñh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K(hjíubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÓubj)�”}”(hŒ semaphore”h]”hý)�”}”(hjh]”hŒ semaphore”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K)hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÓubj)�”}”(hŒ rw_semaphore”h]”hý)�”}”(hjh]”hŒ rw_semaphore”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K*hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÓubj)�”}”(hŒww_mutex”h]”hý)�”}”(hj4h]”hŒww_mutex”…”�”}”(hj6h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K+hj2ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÓubj)�”}”(hŒpercpu_rw_semaphore ”h]”hý)�”}”(hŒpercpu_rw_semaphore”h]”hŒpercpu_rw_semaphore”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K,hjIubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÓubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´K'hjÏubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K'hj”h²hubhý)�”}”(hŒHOn PREEMPT_RT kernels, these lock types are converted to sleeping locks:”h]”hŒHOn PREEMPT_RT kernels, these lock types are converted to sleeping locks:”…”�”}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K.hj”h²hubj )�”}”(hŒ&- local_lock - spinlock_t - rwlock_t ”h]”j)�”}”(hhh]”(j)�”}”(hŒ local_lock”h]”hý)�”}”(hj„h]”hŒ local_lock”…”�”}”(hj†h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K0hj‚ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)�”}”(hŒ spinlock_t”h]”hý)�”}”(hj›h]”hŒ spinlock_t”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K1hj™ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj)�”}”(hŒ rwlock_t ”h]”hý)�”}”(hŒrwlock_t”h]”hŒrwlock_t”…”�”}”(hj´h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K2hj°ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´K0hj{ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K0hj”h²hubeh}”(h]”Œsleeping-locks”ah ]”h"]”Œsleeping locks”ah$]”h&]”uh1hÖhjƒh²hh³hÇh´Kubh×)�”}”(hhh]”(hÜ)�”}”(hŒCPU local locks”h]”hŒCPU local locks”…”�”}”(hjßh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÜh²hh³hÇh´K6ubj )�”}”(hŒ - local_lock ”h]”j)�”}”(hhh]”j)�”}”(hŒ local_lock ”h]”hý)�”}”(hŒ local_lock”h]”hŒ local_lock”…”�”}”(hjøh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K8hjôubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjñubah}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´K8hjíubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K8hjÜh²hubhý)�”}”(hXOn non-PREEMPT_RT kernels, local_lock functions are wrappers around preemption and interrupt disabling primitives. Contrary to other locking mechanisms, disabling preemption or interrupts are pure CPU local concurrency control mechanisms and not suited for inter-CPU concurrency control.”h]”hXOn non-PREEMPT_RT kernels, local_lock functions are wrappers around preemption and interrupt disabling primitives. Contrary to other locking mechanisms, disabling preemption or interrupts are pure CPU local concurrency control mechanisms and not suited for inter-CPU concurrency control.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K:hjÜh²hubeh}”(h]”Œcpu-local-locks”ah ]”h"]”Œcpu local locks”ah$]”h&]”uh1hÖhjƒh²hh³hÇh´K6ubh×)�”}”(hhh]”(hÜ)�”}”(hŒSpinning locks”h]”hŒSpinning locks”…”�”}”(hj1h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj.h²hh³hÇh´KBubj )�”}”(hŒ!- raw_spinlock_t - bit spinlocks ”h]”j)�”}”(hhh]”(j)�”}”(hŒraw_spinlock_t”h]”hý)�”}”(hjHh]”hŒraw_spinlock_t”…”�”}”(hjJh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KDhjFubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjCubj)�”}”(hŒbit spinlocks ”h]”hý)�”}”(hŒ bit spinlocks”h]”hŒ bit spinlocks”…”�”}”(hjah²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KEhj]ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjCubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´KDhj?ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KDhj.h²hubhý)�”}”(hŒDOn non-PREEMPT_RT kernels, these lock types are also spinning locks:”h]”hŒDOn non-PREEMPT_RT kernels, these lock types are also spinning locks:”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KGhj.h²hubj )�”}”(hŒ- spinlock_t - rwlock_t ”h]”j)�”}”(hhh]”(j)�”}”(hŒ spinlock_t”h]”hý)�”}”(hj˜h]”hŒ spinlock_t”…”�”}”(hjšh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KIhj–ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubj)�”}”(hŒ rwlock_t ”h]”hý)�”}”(hŒrwlock_t”h]”hŒrwlock_t”…”�”}”(hj±h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KJhj­ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´KIhj�ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KIhj.h²hubhý)�”}”(hŒSpinning locks implicitly disable preemption and the lock / unlock functions can have suffixes which apply further protections:”h]”hŒSpinning locks implicitly disable preemption and the lock / unlock functions can have suffixes which apply further protections:”…”�”}”(hjÑh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KLhj.h²hubj )�”}”(hXU=================== ==================================================== _bh() Disable / enable bottom halves (soft interrupts) _irq() Disable / enable interrupts _irqsave/restore() Save and disable / restore interrupt disabled state =================== ==================================================== ”h]”hŒtable”“”)�”}”(hhh]”hŒtgroup”“”)�”}”(hhh]”(hŒcolspec”“”)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jíhjêubjî)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”K4uh1jíhjêubhŒtbody”“”)�”}”(hhh]”(hŒrow”“”)�”}”(hhh]”(hŒentry”“”)�”}”(hhh]”hý)�”}”(hŒ_bh()”h]”hŒ_bh()”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KPhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj ubj)�”}”(hhh]”hý)�”}”(hŒ0Disable / enable bottom halves (soft interrupts)”h]”hŒ0Disable / enable bottom halves (soft interrupts)”…”�”}”(hj)h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KPhj&ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒ_irq()”h]”hŒ_irq()”…”�”}”(hjIh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KQhjFubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjCubj)�”}”(hhh]”hý)�”}”(hŒDisable / enable interrupts”h]”hŒDisable / enable interrupts”…”�”}”(hj`h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KQhj]ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjCubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒ_irqsave/restore()”h]”hŒ_irqsave/restore()”…”�”}”(hj€h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KRhj}ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjzubj)�”}”(hhh]”hý)�”}”(hŒ3Save and disable / restore interrupt disabled state”h]”hŒ3Save and disable / restore interrupt disabled state”…”�”}”(hj—h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KRhj”ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjzubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjêubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1jèhjåubah}”(h]”h ]”h"]”h$]”h&]”uh1jãhjßubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KOhj.h²hubeh}”(h]”Œspinning-locks”ah ]”h"]”Œspinning locks”ah$]”h&]”uh1hÖhjƒh²hh³hÇh´KBubeh}”(h]”Œlock-categories”ah ]”h"]”Œlock categories”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Kubh×)�”}”(hhh]”(hÜ)�”}”(hŒOwner semantics”h]”hŒOwner semantics”…”�”}”(hjÝh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÚh²hh³hÇh´KWubhý)�”}”(hŒLThe aforementioned lock types except semaphores have strict owner semantics:”h]”hŒLThe aforementioned lock types except semaphores have strict owner semantics:”…”�”}”(hjëh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KYhjÚh²hubj )�”}”(hŒ;The context (task) that acquired the lock must release it. ”h]”hý)�”}”(hŒ:The context (task) that acquired the lock must release it.”h]”hŒ:The context (task) that acquired the lock must release it.”…”�”}”(hjýh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K\hjùubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K\hjÚh²hubhý)�”}”(hŒRrw_semaphores have a special interface which allows non-owner release for readers.”h]”hŒRrw_semaphores have a special interface which allows non-owner release for readers.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K^hjÚh²hubeh}”(h]”Œowner-semantics”ah ]”h"]”Œowner semantics”ah$]”h&]”uh1hÖhhØh²hh³hÇh´KWubh×)�”}”(hhh]”(hÜ)�”}”(hŒrtmutex”h]”hŒrtmutex”…”�”}”(hj*h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj'h²hh³hÇh´Kcubhý)�”}”(hŒBRT-mutexes are mutexes with support for priority inheritance (PI).”h]”hŒBRT-mutexes are mutexes with support for priority inheritance (PI).”…”�”}”(hj8h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kehj'h²hubhý)�”}”(hŒ_PI has limitations on non-PREEMPT_RT kernels due to preemption and interrupt disabled sections.”h]”hŒ_PI has limitations on non-PREEMPT_RT kernels due to preemption and interrupt disabled sections.”…”�”}”(hjFh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kghj'h²hubhý)�”}”(hXQPI clearly cannot preempt preemption-disabled or interrupt-disabled regions of code, even on PREEMPT_RT kernels. Instead, PREEMPT_RT kernels execute most such regions of code in preemptible task context, especially interrupt handlers and soft interrupts. This conversion allows spinlock_t and rwlock_t to be implemented via RT-mutexes.”h]”hXQPI clearly cannot preempt preemption-disabled or interrupt-disabled regions of code, even on PREEMPT_RT kernels. Instead, PREEMPT_RT kernels execute most such regions of code in preemptible task context, especially interrupt handlers and soft interrupts. This conversion allows spinlock_t and rwlock_t to be implemented via RT-mutexes.”…”�”}”(hjTh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kjhj'h²hubeh}”(h]”Œrtmutex”ah ]”h"]”Œrtmutex”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Kcubh×)�”}”(hhh]”(hÜ)�”}”(hŒ semaphore”h]”hŒ semaphore”…”�”}”(hjmh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjjh²hh³hÇh´Krubhý)�”}”(hŒ1semaphore is a counting semaphore implementation.”h]”hŒ1semaphore is a counting semaphore implementation.”…”�”}”(hj{h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kthjjh²hubhý)�”}”(hŒ¯Semaphores are often used for both serialization and waiting, but new use cases should instead use separate serialization and wait mechanisms, such as mutexes and completions.”h]”hŒ¯Semaphores are often used for both serialization and waiting, but new use cases should instead use separate serialization and wait mechanisms, such as mutexes and completions.”…”�”}”(hj‰h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kvhjjh²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒsemaphores and PREEMPT_RT”h]”hŒsemaphores and PREEMPT_RT”…”�”}”(hjšh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj—h²hh³hÇh´K{ubhý)�”}”(hX8PREEMPT_RT does not change the semaphore implementation because counting semaphores have no concept of owners, thus preventing PREEMPT_RT from providing priority inheritance for semaphores. After all, an unknown owner cannot be boosted. As a consequence, blocking on semaphores can result in priority inversion.”h]”hX8PREEMPT_RT does not change the semaphore implementation because counting semaphores have no concept of owners, thus preventing PREEMPT_RT from providing priority inheritance for semaphores. After all, an unknown owner cannot be boosted. As a consequence, blocking on semaphores can result in priority inversion.”…”�”}”(hj¨h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K}hj—h²hubeh}”(h]”Œsemaphores-and-preempt-rt”ah ]”h"]”Œsemaphores and preempt_rt”ah$]”h&]”uh1hÖhjjh²hh³hÇh´K{ubeh}”(h]”Œ semaphore”ah ]”h"]”Œ semaphore”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Krubh×)�”}”(hhh]”(hÜ)�”}”(hŒ rw_semaphore”h]”hŒ rw_semaphore”…”�”}”(hjÉh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÆh²hh³hÇh´K…ubhý)�”}”(hŒDrw_semaphore is a multiple readers and single writer lock mechanism.”h]”hŒDrw_semaphore is a multiple readers and single writer lock mechanism.”…”�”}”(hj×h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K‡hjÆh²hubhý)�”}”(hŒXOn non-PREEMPT_RT kernels the implementation is fair, thus preventing writer starvation.”h]”hŒXOn non-PREEMPT_RT kernels the implementation is fair, thus preventing writer starvation.”…”�”}”(hjåh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K‰hjÆh²hubhý)�”}”(hŒÕrw_semaphore complies by default with the strict owner semantics, but there exist special-purpose interfaces that allow non-owner release for readers. These interfaces work independent of the kernel configuration.”h]”hŒÕrw_semaphore complies by default with the strict owner semantics, but there exist special-purpose interfaces that allow non-owner release for readers. These interfaces work independent of the kernel configuration.”…”�”}”(hjóh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KŒhjÆh²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒrw_semaphore and PREEMPT_RT”h]”hŒrw_semaphore and PREEMPT_RT”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjh²hh³hÇh´K‘ubhý)�”}”(hŒlPREEMPT_RT kernels map rw_semaphore to a separate rt_mutex-based implementation, thus changing the fairness:”h]”hŒlPREEMPT_RT kernels map rw_semaphore to a separate rt_mutex-based implementation, thus changing the fairness:”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K“hjh²hubj )�”}”(hX‹Because an rw_semaphore writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers. ”h]”hý)�”}”(hX‰Because an rw_semaphore writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers.”h]”hX‰Because an rw_semaphore writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers.”…”�”}”(hj$h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K–hj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K–hjh²hubeh}”(h]”Œrw-semaphore-and-preempt-rt”ah ]”h"]”Œrw_semaphore and preempt_rt”ah$]”h&]”uh1hÖhjÆh²hh³hÇh´K‘ubeh}”(h]”Œ rw-semaphore”ah ]”h"]”Œ rw_semaphore”ah$]”h&]”uh1hÖhhØh²hh³hÇh´K…ubh×)�”}”(hhh]”(hÜ)�”}”(hŒ local_lock”h]”hŒ local_lock”…”�”}”(hjKh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjHh²hh³hÇh´KŸubhý)�”}”(hŒqlocal_lock provides a named scope to critical sections which are protected by disabling preemption or interrupts.”h]”hŒqlocal_lock provides a named scope to critical sections which are protected by disabling preemption or interrupts.”…”�”}”(hjYh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¡hjHh²hubhý)�”}”(hŒvOn non-PREEMPT_RT kernels local_lock operations map to the preemption and interrupt disabling and enabling primitives:”h]”hŒvOn non-PREEMPT_RT kernels local_lock operations map to the preemption and interrupt disabling and enabling primitives:”…”�”}”(hjgh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¤hjHh²hubj )�”}”(hX¥=============================== ====================== local_lock(&llock) preempt_disable() local_unlock(&llock) preempt_enable() local_lock_irq(&llock) local_irq_disable() local_unlock_irq(&llock) local_irq_enable() local_lock_irqsave(&llock) local_irq_save() local_unlock_irqrestore(&llock) local_irq_restore() =============================== ====================== ”h]”jä)�”}”(hhh]”jé)�”}”(hhh]”(jî)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jíhj|ubjî)�”}”(hhh]”h}”(h]”h ]”h"]”h$]”h&]”Œcolwidth”Kuh1jíhj|ubj)�”}”(hhh]”(j )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒlocal_lock(&llock)”h]”hŒlocal_lock(&llock)”…”�”}”(hjœh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¨hj™ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj–ubj)�”}”(hhh]”hý)�”}”(hŒpreempt_disable()”h]”hŒpreempt_disable()”…”�”}”(hj³h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¨hj°ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj–ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒlocal_unlock(&llock)”h]”hŒlocal_unlock(&llock)”…”�”}”(hjÓh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K©hjÐubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÍubj)�”}”(hhh]”hý)�”}”(hŒpreempt_enable()”h]”hŒpreempt_enable()”…”�”}”(hjêh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K©hjçubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjÍubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒlocal_lock_irq(&llock)”h]”hŒlocal_lock_irq(&llock)”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kªhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubj)�”}”(hhh]”hý)�”}”(hŒlocal_irq_disable()”h]”hŒlocal_irq_disable()”…”�”}”(hj!h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kªhjubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒlocal_unlock_irq(&llock)”h]”hŒlocal_unlock_irq(&llock)”…”�”}”(hjAh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K«hj>ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj;ubj)�”}”(hhh]”hý)�”}”(hŒlocal_irq_enable()”h]”hŒlocal_irq_enable()”…”�”}”(hjXh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K«hjUubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj;ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒlocal_lock_irqsave(&llock)”h]”hŒlocal_lock_irqsave(&llock)”…”�”}”(hjxh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¬hjuubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjrubj)�”}”(hhh]”hý)�”}”(hŒlocal_irq_save()”h]”hŒlocal_irq_save()”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K¬hjŒubah}”(h]”h ]”h"]”h$]”h&]”uh1j hjrubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubj )�”}”(hhh]”(j)�”}”(hhh]”hý)�”}”(hŒlocal_unlock_irqrestore(&llock)”h]”hŒlocal_unlock_irqrestore(&llock)”…”�”}”(hj¯h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K­hj¬ubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj©ubj)�”}”(hhh]”hý)�”}”(hŒlocal_irq_restore()”h]”hŒlocal_irq_restore()”…”�”}”(hjÆh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K­hjÃubah}”(h]”h ]”h"]”h$]”h&]”uh1j hj©ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj“ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj|ubeh}”(h]”h ]”h"]”h$]”h&]”Œcols”Kuh1jèhjyubah}”(h]”h ]”h"]”h$]”h&]”uh1jãhjuubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K§hjHh²hubhý)�”}”(hŒMThe named scope of local_lock has two advantages over the regular primitives:”h]”hŒMThe named scope of local_lock has two advantages over the regular primitives:”…”�”}”(hjùh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K°hjHh²hubj )�”}”(hXþ- The lock name allows static analysis and is also a clear documentation of the protection scope while the regular primitives are scopeless and opaque. - If lockdep is enabled the local_lock gains a lockmap which allows to validate the correctness of the protection. This can detect cases where e.g. a function using preempt_disable() as protection mechanism is invoked from interrupt or soft-interrupt context. Aside of that lockdep_assert_held(&llock) works as with any other locking primitive. ”h]”j)�”}”(hhh]”(j)�”}”(hŒ–The lock name allows static analysis and is also a clear documentation of the protection scope while the regular primitives are scopeless and opaque. ”h]”hý)�”}”(hŒ•The lock name allows static analysis and is also a clear documentation of the protection scope while the regular primitives are scopeless and opaque.”h]”hŒ•The lock name allows static analysis and is also a clear documentation of the protection scope while the regular primitives are scopeless and opaque.”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K³hjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubj)�”}”(hXWIf lockdep is enabled the local_lock gains a lockmap which allows to validate the correctness of the protection. This can detect cases where e.g. a function using preempt_disable() as protection mechanism is invoked from interrupt or soft-interrupt context. Aside of that lockdep_assert_held(&llock) works as with any other locking primitive. ”h]”hý)�”}”(hXVIf lockdep is enabled the local_lock gains a lockmap which allows to validate the correctness of the protection. This can detect cases where e.g. a function using preempt_disable() as protection mechanism is invoked from interrupt or soft-interrupt context. Aside of that lockdep_assert_held(&llock) works as with any other locking primitive.”h]”hXVIf lockdep is enabled the local_lock gains a lockmap which allows to validate the correctness of the protection. This can detect cases where e.g. a function using preempt_disable() as protection mechanism is invoked from interrupt or soft-interrupt context. Aside of that lockdep_assert_held(&llock) works as with any other locking primitive.”…”�”}”(hj*h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K·hj&ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´K³hjubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´K³hjHh²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒlocal_lock and PREEMPT_RT”h]”hŒlocal_lock and PREEMPT_RT”…”�”}”(hjMh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjJh²hh³hÇh´K¾ubhý)�”}”(hŒSPREEMPT_RT kernels map local_lock to a per-CPU spinlock_t, thus changing semantics:”h]”hŒSPREEMPT_RT kernels map local_lock to a per-CPU spinlock_t, thus changing semantics:”…”�”}”(hj[h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÀhjJh²hubj )�”}”(hŒ3- All spinlock_t changes also apply to local_lock. ”h]”j)�”}”(hhh]”j)�”}”(hŒ1All spinlock_t changes also apply to local_lock. ”h]”hý)�”}”(hŒ0All spinlock_t changes also apply to local_lock.”h]”hŒ0All spinlock_t changes also apply to local_lock.”…”�”}”(hjth²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÃhjpubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjmubah}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´KÃhjiubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´KÃhjJh²hubeh}”(h]”Œlocal-lock-and-preempt-rt”ah ]”h"]”Œlocal_lock and preempt_rt”ah$]”h&]”uh1hÖhjHh²hh³hÇh´K¾ubh×)�”}”(hhh]”(hÜ)�”}”(hŒlocal_lock usage”h]”hŒlocal_lock usage”…”�”}”(hjŸh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjœh²hh³hÇh´KÆubhý)�”}”(hŒ¾local_lock should be used in situations where disabling preemption or interrupts is the appropriate form of concurrency control to protect per-CPU data structures on a non PREEMPT_RT kernel.”h]”hŒ¾local_lock should be used in situations where disabling preemption or interrupts is the appropriate form of concurrency control to protect per-CPU data structures on a non PREEMPT_RT kernel.”…”�”}”(hj­h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÈhjœh²hubhý)�”}”(hŒ’local_lock is not suitable to protect against preemption or interrupts on a PREEMPT_RT kernel due to the PREEMPT_RT specific spinlock_t semantics.”h]”hŒ’local_lock is not suitable to protect against preemption or interrupts on a PREEMPT_RT kernel due to the PREEMPT_RT specific spinlock_t semantics.”…”�”}”(hj»h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÌhjœh²hubeh}”(h]”Œlocal-lock-usage”ah ]”h"]”Œlocal_lock usage”ah$]”h&]”uh1hÖhjHh²hh³hÇh´KÆubh×)�”}”(hhh]”(hÜ)�”}”(hŒCPU local scope and bottom-half”h]”hŒCPU local scope and bottom-half”…”�”}”(hjÔh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÑh²hh³hÇh´KÐubhý)�”}”(hXYPer-CPU variables that are accessed only in softirq context should not rely on the assumption that this context is implicitly protected due to being non-preemptible. In a PREEMPT_RT kernel, softirq context is preemptible, and synchronizing every bottom-half-disabled section via implicit context results in an implicit per-CPU "big kernel lock."”h]”hX]Per-CPU variables that are accessed only in softirq context should not rely on the assumption that this context is implicitly protected due to being non-preemptible. In a PREEMPT_RT kernel, softirq context is preemptible, and synchronizing every bottom-half-disabled section via implicit context results in an implicit per-CPU “big kernel lock.â€�”…”�”}”(hjâh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÒhjÑh²hubhý)�”}”(hŒ‹A local_lock_t together with local_lock_nested_bh() and local_unlock_nested_bh() for locking operations help to identify the locking scope.”h]”hŒ‹A local_lock_t together with local_lock_nested_bh() and local_unlock_nested_bh() for locking operations help to identify the locking scope.”…”�”}”(hjðh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KØhjÑh²hubhý)�”}”(hŒèWhen lockdep is enabled, these functions verify that data structure access occurs within softirq context. Unlike local_lock(), local_unlock_nested_bh() does not disable preemption and does not add overhead when used without lockdep.”h]”hŒèWhen lockdep is enabled, these functions verify that data structure access occurs within softirq context. Unlike local_lock(), local_unlock_nested_bh() does not disable preemption and does not add overhead when used without lockdep.”…”�”}”(hjþh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KÜhjÑh²hubhý)�”}”(hŒ¿On a PREEMPT_RT kernel, local_lock_t behaves as a real lock and local_unlock_nested_bh() serializes access to the data structure, which allows removal of serialization via local_bh_disable().”h]”hŒ¿On a PREEMPT_RT kernel, local_lock_t behaves as a real lock and local_unlock_nested_bh() serializes access to the data structure, which allows removal of serialization via local_bh_disable().”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´KáhjÑh²hubeh}”(h]”Œcpu-local-scope-and-bottom-half”ah ]”h"]”Œcpu local scope and bottom-half”ah$]”h&]”uh1hÖhjHh²hh³hÇh´KÐubeh}”(h]”Œ local-lock”ah ]”h"]”Œ local_lock”ah$]”h&]”uh1hÖhhØh²hh³hÇh´KŸubh×)�”}”(hhh]”(hÜ)�”}”(hŒraw_spinlock_t and spinlock_t”h]”hŒraw_spinlock_t and spinlock_t”…”�”}”(hj- h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj* h²hh³hÇh´Kæubh×)�”}”(hhh]”(hÜ)�”}”(hŒraw_spinlock_t”h]”hŒraw_spinlock_t”…”�”}”(hj> h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj; h²hh³hÇh´Kéubhý)�”}”(hX•raw_spinlock_t is a strict spinning lock implementation in all kernels, including PREEMPT_RT kernels. Use raw_spinlock_t only in real critical core code, low-level interrupt handling and places where disabling preemption or interrupts is required, for example, to safely access hardware state. raw_spinlock_t can sometimes also be used when the critical section is tiny, thus avoiding RT-mutex overhead.”h]”hX•raw_spinlock_t is a strict spinning lock implementation in all kernels, including PREEMPT_RT kernels. Use raw_spinlock_t only in real critical core code, low-level interrupt handling and places where disabling preemption or interrupts is required, for example, to safely access hardware state. raw_spinlock_t can sometimes also be used when the critical section is tiny, thus avoiding RT-mutex overhead.”…”�”}”(hjL h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Këhj; h²hubeh}”(h]”Œraw-spinlock-t”ah ]”h"]”Œraw_spinlock_t”ah$]”h&]”uh1hÖhj* h²hh³hÇh´Kéubh×)�”}”(hhh]”(hÜ)�”}”(hŒ spinlock_t”h]”hŒ spinlock_t”…”�”}”(hje h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjb h²hh³hÇh´Kóubhý)�”}”(hŒ@The semantics of spinlock_t change with the state of PREEMPT_RT.”h]”hŒ@The semantics of spinlock_t change with the state of PREEMPT_RT.”…”�”}”(hjs h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kõhjb h²hubhý)�”}”(hŒeOn a non-PREEMPT_RT kernel spinlock_t is mapped to raw_spinlock_t and has exactly the same semantics.”h]”hŒeOn a non-PREEMPT_RT kernel spinlock_t is mapped to raw_spinlock_t and has exactly the same semantics.”…”�”}”(hj� h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´K÷hjb h²hubeh}”(h]”Œ spinlock-t”ah ]”h"]”Œ spinlock_t”ah$]”h&]”uh1hÖhj* h²hh³hÇh´Kóubh×)�”}”(hhh]”(hÜ)�”}”(hŒspinlock_t and PREEMPT_RT”h]”hŒspinlock_t and PREEMPT_RT”…”�”}”(hjš h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj— h²hh³hÇh´Kûubhý)�”}”(hŒwOn a PREEMPT_RT kernel spinlock_t is mapped to a separate implementation based on rt_mutex which changes the semantics:”h]”hŒwOn a PREEMPT_RT kernel spinlock_t is mapped to a separate implementation based on rt_mutex which changes the semantics:”…”�”}”(hj¨ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Kýhj— h²hubj )�”}”(hX - Preemption is not disabled. - The hard interrupt related suffixes for spin_lock / spin_unlock operations (_irq, _irqsave / _irqrestore) do not affect the CPU's interrupt disabled state. - The soft interrupt related suffix (_bh()) still disables softirq handlers. Non-PREEMPT_RT kernels disable preemption to get this effect. PREEMPT_RT kernels use a per-CPU lock for serialization which keeps preemption enabled. The lock disables softirq handlers and also prevents reentrancy due to task preemption. ”h]”j)�”}”(hhh]”(j)�”}”(hŒPreemption is not disabled. ”h]”hý)�”}”(hŒPreemption is not disabled.”h]”hŒPreemption is not disabled.”…”�”}”(hjÁ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhj½ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjº ubj)�”}”(hŒœThe hard interrupt related suffixes for spin_lock / spin_unlock operations (_irq, _irqsave / _irqrestore) do not affect the CPU's interrupt disabled state. ”h]”hý)�”}”(hŒ›The hard interrupt related suffixes for spin_lock / spin_unlock operations (_irq, _irqsave / _irqrestore) do not affect the CPU's interrupt disabled state.”h]”hŒ�The hard interrupt related suffixes for spin_lock / spin_unlock operations (_irq, _irqsave / _irqrestore) do not affect the CPU’s interrupt disabled state.”…”�”}”(hjÙ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MhjÕ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjº ubj)�”}”(hX;The soft interrupt related suffix (_bh()) still disables softirq handlers. Non-PREEMPT_RT kernels disable preemption to get this effect. PREEMPT_RT kernels use a per-CPU lock for serialization which keeps preemption enabled. The lock disables softirq handlers and also prevents reentrancy due to task preemption. ”h]”(hý)�”}”(hŒJThe soft interrupt related suffix (_bh()) still disables softirq handlers.”h]”hŒJThe soft interrupt related suffix (_bh()) still disables softirq handlers.”…”�”}”(hjñ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjí ubhý)�”}”(hŒ=Non-PREEMPT_RT kernels disable preemption to get this effect.”h]”hŒ=Non-PREEMPT_RT kernels disable preemption to get this effect.”…”�”}”(hjÿ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M hjí ubhý)�”}”(hŒ¯PREEMPT_RT kernels use a per-CPU lock for serialization which keeps preemption enabled. The lock disables softirq handlers and also prevents reentrancy due to task preemption.”h]”hŒ¯PREEMPT_RT kernels use a per-CPU lock for serialization which keeps preemption enabled. The lock disables softirq handlers and also prevents reentrancy due to task preemption.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M hjí ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhjº ubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´Mhj¶ ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Mhj— h²hubhý)�”}”(hŒ;PREEMPT_RT kernels preserve all other spinlock_t semantics:”h]”hŒ;PREEMPT_RT kernels preserve all other spinlock_t semantics:”…”�”}”(hj- h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhj— h²hubj )�”}”(hX]- Tasks holding a spinlock_t do not migrate. Non-PREEMPT_RT kernels avoid migration by disabling preemption. PREEMPT_RT kernels instead disable migration, which ensures that pointers to per-CPU variables remain valid even if the task is preempted. - Task state is preserved across spinlock acquisition, ensuring that the task-state rules apply to all kernel configurations. Non-PREEMPT_RT kernels leave task state untouched. However, PREEMPT_RT must change task state if the task blocks during acquisition. Therefore, it saves the current task state before blocking and the corresponding lock wakeup restores it, as shown below:: task->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() lock wakeup task->state = task->saved_state Other types of wakeups would normally unconditionally set the task state to RUNNING, but that does not work here because the task must remain blocked until the lock becomes available. Therefore, when a non-lock wakeup attempts to awaken a task blocked waiting for a spinlock, it instead sets the saved state to RUNNING. Then, when the lock acquisition completes, the lock wakeup sets the task state to the saved state, in this case setting it to RUNNING:: task->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() non lock wakeup task->saved_state = TASK_RUNNING lock wakeup task->state = task->saved_state This ensures that the real wakeup cannot be lost. ”h]”j)�”}”(hhh]”(j)�”}”(hŒøTasks holding a spinlock_t do not migrate. Non-PREEMPT_RT kernels avoid migration by disabling preemption. PREEMPT_RT kernels instead disable migration, which ensures that pointers to per-CPU variables remain valid even if the task is preempted. ”h]”hý)�”}”(hŒ÷Tasks holding a spinlock_t do not migrate. Non-PREEMPT_RT kernels avoid migration by disabling preemption. PREEMPT_RT kernels instead disable migration, which ensures that pointers to per-CPU variables remain valid even if the task is preempted.”h]”hŒ÷Tasks holding a spinlock_t do not migrate. Non-PREEMPT_RT kernels avoid migration by disabling preemption. PREEMPT_RT kernels instead disable migration, which ensures that pointers to per-CPU variables remain valid even if the task is preempted.”…”�”}”(hjF h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MhjB ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj? ubj)�”}”(hXTask state is preserved across spinlock acquisition, ensuring that the task-state rules apply to all kernel configurations. Non-PREEMPT_RT kernels leave task state untouched. However, PREEMPT_RT must change task state if the task blocks during acquisition. Therefore, it saves the current task state before blocking and the corresponding lock wakeup restores it, as shown below:: task->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() lock wakeup task->state = task->saved_state Other types of wakeups would normally unconditionally set the task state to RUNNING, but that does not work here because the task must remain blocked until the lock becomes available. Therefore, when a non-lock wakeup attempts to awaken a task blocked waiting for a spinlock, it instead sets the saved state to RUNNING. Then, when the lock acquisition completes, the lock wakeup sets the task state to the saved state, in this case setting it to RUNNING:: task->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() non lock wakeup task->saved_state = TASK_RUNNING lock wakeup task->state = task->saved_state This ensures that the real wakeup cannot be lost. ”h]”(hý)�”}”(hX~Task state is preserved across spinlock acquisition, ensuring that the task-state rules apply to all kernel configurations. Non-PREEMPT_RT kernels leave task state untouched. However, PREEMPT_RT must change task state if the task blocks during acquisition. Therefore, it saves the current task state before blocking and the corresponding lock wakeup restores it, as shown below::”h]”hX}Task state is preserved across spinlock acquisition, ensuring that the task-state rules apply to all kernel configurations. Non-PREEMPT_RT kernels leave task state untouched. However, PREEMPT_RT must change task state if the task blocks during acquisition. Therefore, it saves the current task state before blocking and the corresponding lock wakeup restores it, as shown below:”…”�”}”(hj^ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MhjZ ubhŒ literal_block”“”)�”}”(hXtask->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() lock wakeup task->state = task->saved_state”h]”hXtask->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() lock wakeup task->state = task->saved_state”…”�”}”hjn sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´MhjZ ubhý)�”}”(hXÉOther types of wakeups would normally unconditionally set the task state to RUNNING, but that does not work here because the task must remain blocked until the lock becomes available. Therefore, when a non-lock wakeup attempts to awaken a task blocked waiting for a spinlock, it instead sets the saved state to RUNNING. Then, when the lock acquisition completes, the lock wakeup sets the task state to the saved state, in this case setting it to RUNNING::”h]”hXÈOther types of wakeups would normally unconditionally set the task state to RUNNING, but that does not work here because the task must remain blocked until the lock becomes available. Therefore, when a non-lock wakeup attempts to awaken a task blocked waiting for a spinlock, it instead sets the saved state to RUNNING. Then, when the lock acquisition completes, the lock wakeup sets the task state to the saved state, in this case setting it to RUNNING:”…”�”}”(hj| h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M&hjZ ubjm )�”}”(hX‚task->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() non lock wakeup task->saved_state = TASK_RUNNING lock wakeup task->state = task->saved_state”h]”hX‚task->state = TASK_INTERRUPTIBLE lock() block() task->saved_state = task->state task->state = TASK_UNINTERRUPTIBLE schedule() non lock wakeup task->saved_state = TASK_RUNNING lock wakeup task->state = task->saved_state”…”�”}”hjŠ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´M.hjZ ubhý)�”}”(hŒ1This ensures that the real wakeup cannot be lost.”h]”hŒ1This ensures that the real wakeup cannot be lost.”…”�”}”(hj˜ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M:hjZ ubeh}”(h]”h ]”h"]”h$]”h&]”uh1jhj? ubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´Mhj; ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Mhj— h²hubeh}”(h]”Œspinlock-t-and-preempt-rt”ah ]”h"]”Œspinlock_t and preempt_rt”ah$]”h&]”uh1hÖhj* h²hh³hÇh´Kûubeh}”(h]”Œraw-spinlock-t-and-spinlock-t”ah ]”h"]”Œraw_spinlock_t and spinlock_t”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Kæubh×)�”}”(hhh]”(hÜ)�”}”(hŒrwlock_t”h]”hŒrwlock_t”…”�”}”(hjË h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjÈ h²hh³hÇh´M>ubhý)�”}”(hŒ@rwlock_t is a multiple readers and single writer lock mechanism.”h]”hŒ@rwlock_t is a multiple readers and single writer lock mechanism.”…”�”}”(hjÙ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M@hjÈ h²hubhý)�”}”(hŒ±Non-PREEMPT_RT kernels implement rwlock_t as a spinning lock and the suffix rules of spinlock_t apply accordingly. The implementation is fair, thus preventing writer starvation.”h]”hŒ±Non-PREEMPT_RT kernels implement rwlock_t as a spinning lock and the suffix rules of spinlock_t apply accordingly. The implementation is fair, thus preventing writer starvation.”…”�”}”(hjç h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MBhjÈ h²hubh×)�”}”(hhh]”(hÜ)�”}”(hŒrwlock_t and PREEMPT_RT”h]”hŒrwlock_t and PREEMPT_RT”…”�”}”(hjø h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjõ h²hh³hÇh´MGubhý)�”}”(hŒePREEMPT_RT kernels map rwlock_t to a separate rt_mutex-based implementation, thus changing semantics:”h]”hŒePREEMPT_RT kernels map rwlock_t to a separate rt_mutex-based implementation, thus changing semantics:”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MIhjõ h²hubj )�”}”(hXÉ- All the spinlock_t changes also apply to rwlock_t. - Because an rwlock_t writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers. ”h]”j)�”}”(hhh]”(j)�”}”(hŒ3All the spinlock_t changes also apply to rwlock_t. ”h]”hý)�”}”(hŒ2All the spinlock_t changes also apply to rwlock_t.”h]”hŒ2All the spinlock_t changes also apply to rwlock_t.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MLhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubj)�”}”(hX‡Because an rwlock_t writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers. ”h]”hý)�”}”(hX…Because an rwlock_t writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers.”h]”hX…Because an rwlock_t writer cannot grant its priority to multiple readers, a preempted low-priority reader will continue holding its lock, thus starving even high-priority writers. In contrast, because readers can grant their priority to a writer, a preempted low-priority writer will have its priority boosted until it releases the lock, thus preventing that writer from starving readers.”…”�”}”(hj7 h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MNhj3 ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhj ubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´MLhj ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´MLhjõ h²hubeh}”(h]”Œrwlock-t-and-preempt-rt”ah ]”h"]”Œrwlock_t and preempt_rt”ah$]”h&]”uh1hÖhjÈ h²hh³hÇh´MGubeh}”(h]”Œrwlock-t”ah ]”h"]”Œrwlock_t”ah$]”h&]”uh1hÖhhØh²hh³hÇh´M>ubh×)�”}”(hhh]”(hÜ)�”}”(hŒPREEMPT_RT caveats”h]”hŒPREEMPT_RT caveats”…”�”}”(hjj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjg h²hh³hÇh´MWubh×)�”}”(hhh]”(hÜ)�”}”(hŒlocal_lock on RT”h]”hŒlocal_lock on RT”…”�”}”(hj{ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjx h²hh³hÇh´MZubhý)�”}”(hŒ­The mapping of local_lock to spinlock_t on PREEMPT_RT kernels has a few implications. For example, on a non-PREEMPT_RT kernel the following code sequence works as expected::”h]”hŒ¬The mapping of local_lock to spinlock_t on PREEMPT_RT kernels has a few implications. For example, on a non-PREEMPT_RT kernel the following code sequence works as expected:”…”�”}”(hj‰ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M\hjx h²hubjm )�”}”(hŒ2local_lock_irq(&local_lock); raw_spin_lock(&lock);”h]”hŒ2local_lock_irq(&local_lock); raw_spin_lock(&lock);”…”�”}”hj— sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´M`hjx h²hubhý)�”}”(hŒand is fully equivalent to::”h]”hŒand is fully equivalent to:”…”�”}”(hj¥ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mchjx h²hubjm )�”}”(hŒraw_spin_lock_irq(&lock);”h]”hŒraw_spin_lock_irq(&lock);”…”�”}”hj³ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´Mehjx h²hubhý)�”}”(hXOn a PREEMPT_RT kernel this code sequence breaks because local_lock_irq() is mapped to a per-CPU spinlock_t which neither disables interrupts nor preemption. The following code sequence works perfectly correct on both PREEMPT_RT and non-PREEMPT_RT kernels::”h]”hXOn a PREEMPT_RT kernel this code sequence breaks because local_lock_irq() is mapped to a per-CPU spinlock_t which neither disables interrupts nor preemption. The following code sequence works perfectly correct on both PREEMPT_RT and non-PREEMPT_RT kernels:”…”�”}”(hjÁ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mghjx h²hubjm )�”}”(hŒ.local_lock_irq(&local_lock); spin_lock(&lock);”h]”hŒ.local_lock_irq(&local_lock); spin_lock(&lock);”…”�”}”hjÏ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´Mlhjx h²hubhý)�”}”(hŒ�Another caveat with local locks is that each local_lock has a specific protection scope. So the following substitution is wrong::”h]”hŒ€Another caveat with local locks is that each local_lock has a specific protection scope. So the following substitution is wrong:”…”�”}”(hjÝ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mohjx h²hubjm )�”}”(hX¦func1() { local_irq_save(flags); -> local_lock_irqsave(&local_lock_1, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_1, flags); } func2() { local_irq_save(flags); -> local_lock_irqsave(&local_lock_2, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_2, flags); } func3() { lockdep_assert_irqs_disabled(); access_protected_data(); }”h]”hX¦func1() { local_irq_save(flags); -> local_lock_irqsave(&local_lock_1, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_1, flags); } func2() { local_irq_save(flags); -> local_lock_irqsave(&local_lock_2, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock_2, flags); } func3() { lockdep_assert_irqs_disabled(); access_protected_data(); }”…”�”}”hjë sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´Mrhjx h²hubhý)�”}”(hXnOn a non-PREEMPT_RT kernel this works correctly, but on a PREEMPT_RT kernel local_lock_1 and local_lock_2 are distinct and cannot serialize the callers of func3(). Also the lockdep assert will trigger on a PREEMPT_RT kernel because local_lock_irqsave() does not disable interrupts due to the PREEMPT_RT-specific semantics of spinlock_t. The correct substitution is::”h]”hXmOn a non-PREEMPT_RT kernel this works correctly, but on a PREEMPT_RT kernel local_lock_1 and local_lock_2 are distinct and cannot serialize the callers of func3(). Also the lockdep assert will trigger on a PREEMPT_RT kernel because local_lock_irqsave() does not disable interrupts due to the PREEMPT_RT-specific semantics of spinlock_t. The correct substitution is:”…”�”}”(hjù h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M†hjx h²hubjm )�”}”(hX func1() { local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags); } func2() { local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags); } func3() { lockdep_assert_held(&local_lock); access_protected_data(); }”h]”hX func1() { local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags); } func2() { local_irq_save(flags); -> local_lock_irqsave(&local_lock, flags); func3(); local_irq_restore(flags); -> local_unlock_irqrestore(&local_lock, flags); } func3() { lockdep_assert_held(&local_lock); access_protected_data(); }”…”�”}”hj sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´MŒhjx h²hubeh}”(h]”Œlocal-lock-on-rt”ah ]”h"]”Œlocal_lock on rt”ah$]”h&]”uh1hÖhjg h²hh³hÇh´MZubh×)�”}”(hhh]”(hÜ)�”}”(hŒspinlock_t and rwlock_t”h]”hŒspinlock_t and rwlock_t”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj h²hh³hÇh´M¢ubhý)�”}”(hŒ¸The changes in spinlock_t and rwlock_t semantics on PREEMPT_RT kernels have a few implications. For example, on a non-PREEMPT_RT kernel the following code sequence works as expected::”h]”hŒ·The changes in spinlock_t and rwlock_t semantics on PREEMPT_RT kernels have a few implications. For example, on a non-PREEMPT_RT kernel the following code sequence works as expected:”…”�”}”(hj. h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M¤hj h²hubjm )�”}”(hŒ&local_irq_disable(); spin_lock(&lock);”h]”hŒ&local_irq_disable(); spin_lock(&lock);”…”�”}”hj< sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´M¨hj h²hubhý)�”}”(hŒand is fully equivalent to::”h]”hŒand is fully equivalent to:”…”�”}”(hjJ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M«hj h²hubjm )�”}”(hŒspin_lock_irq(&lock);”h]”hŒspin_lock_irq(&lock);”…”�”}”hjX sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´M­hj h²hubhý)�”}”(hŒlock); p->count += this_cpu_read(var2);”h]”hŒZstruct foo *p = get_cpu_ptr(&var1); spin_lock(&p->lock); p->count += this_cpu_read(var2);”…”�”}”hj� sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´M»hj h²hubhý)�”}”(hXThis is correct code on a non-PREEMPT_RT kernel, but on a PREEMPT_RT kernel this breaks. The PREEMPT_RT-specific change of spinlock_t semantics does not allow to acquire p->lock because get_cpu_ptr() implicitly disables preemption. The following substitution works on both kernels::”h]”hXThis is correct code on a non-PREEMPT_RT kernel, but on a PREEMPT_RT kernel this breaks. The PREEMPT_RT-specific change of spinlock_t semantics does not allow to acquire p->lock because get_cpu_ptr() implicitly disables preemption. The following substitution works on both kernels:”…”�”}”(hjž h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MÀhj h²hubjm )�”}”(hŒqstruct foo *p; migrate_disable(); p = this_cpu_ptr(&var1); spin_lock(&p->lock); p->count += this_cpu_read(var2);”h]”hŒqstruct foo *p; migrate_disable(); p = this_cpu_ptr(&var1); spin_lock(&p->lock); p->count += this_cpu_read(var2);”…”�”}”hj¬ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´MÅhj h²hubhý)�”}”(hŒÆmigrate_disable() ensures that the task is pinned on the current CPU which in turn guarantees that the per-CPU access to var1 and var2 are staying on the same CPU while the task remains preemptible.”h]”hŒÆmigrate_disable() ensures that the task is pinned on the current CPU which in turn guarantees that the per-CPU access to var1 and var2 are staying on the same CPU while the task remains preemptible.”…”�”}”(hjº h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MÌhj h²hubhý)�”}”(hŒLThe migrate_disable() substitution is not valid for the following scenario::”h]”hŒKThe migrate_disable() substitution is not valid for the following scenario:”…”�”}”(hjÈ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MÐhj h²hubjm )�”}”(hŒ^func() { struct foo *p; migrate_disable(); p = this_cpu_ptr(&var1); p->val = func2();”h]”hŒ^func() { struct foo *p; migrate_disable(); p = this_cpu_ptr(&var1); p->val = func2();”…”�”}”hjÖ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´MÓhj h²hubhý)�”}”(hŒ‹This breaks because migrate_disable() does not protect against reentrancy from a preempting task. A correct substitution for this case is::”h]”hŒŠThis breaks because migrate_disable() does not protect against reentrancy from a preempting task. A correct substitution for this case is:”…”�”}”(hjä h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MÛhj h²hubjm )�”}”(hŒbfunc() { struct foo *p; local_lock(&foo_lock); p = this_cpu_ptr(&var1); p->val = func2();”h]”hŒbfunc() { struct foo *p; local_lock(&foo_lock); p = this_cpu_ptr(&var1); p->val = func2();”…”�”}”hjò sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´MÞhj h²hubhý)�”}”(hŒªOn a non-PREEMPT_RT kernel this protects against reentrancy by disabling preemption. On a PREEMPT_RT kernel this is achieved by acquiring the underlying per-CPU spinlock.”h]”hŒªOn a non-PREEMPT_RT kernel this protects against reentrancy by disabling preemption. On a PREEMPT_RT kernel this is achieved by acquiring the underlying per-CPU spinlock.”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mæhj h²hubeh}”(h]”Œspinlock-t-and-rwlock-t”ah ]”h"]”Œspinlock_t and rwlock_t”ah$]”h&]”uh1hÖhjg h²hh³hÇh´M¢ubh×)�”}”(hhh]”(hÜ)�”}”(hŒraw_spinlock_t on RT”h]”hŒraw_spinlock_t on RT”…”�”}”(hj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj h²hh³hÇh´Mìubhý)�”}”(hX"Acquiring a raw_spinlock_t disables preemption and possibly also interrupts, so the critical section must avoid acquiring a regular spinlock_t or rwlock_t, for example, the critical section must avoid allocating memory. Thus, on a non-PREEMPT_RT kernel the following code works perfectly::”h]”hX!Acquiring a raw_spinlock_t disables preemption and possibly also interrupts, so the critical section must avoid acquiring a regular spinlock_t or rwlock_t, for example, the critical section must avoid allocating memory. Thus, on a non-PREEMPT_RT kernel the following code works perfectly:”…”�”}”(hj' h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mîhj h²hubjm )�”}”(hŒ6raw_spin_lock(&lock); p = kmalloc_obj(*p, GFP_ATOMIC);”h]”hŒ6raw_spin_lock(&lock); p = kmalloc_obj(*p, GFP_ATOMIC);”…”�”}”hj5 sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´Môhj h²hubhý)�”}”(hX;But this code fails on PREEMPT_RT kernels because the memory allocator is fully preemptible and therefore cannot be invoked from truly atomic contexts. However, it is perfectly fine to invoke the memory allocator while holding normal non-raw spinlocks because they do not disable preemption on PREEMPT_RT kernels::”h]”hX:But this code fails on PREEMPT_RT kernels because the memory allocator is fully preemptible and therefore cannot be invoked from truly atomic contexts. However, it is perfectly fine to invoke the memory allocator while holding normal non-raw spinlocks because they do not disable preemption on PREEMPT_RT kernels:”…”�”}”(hjC h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M÷hj h²hubjm )�”}”(hŒ2spin_lock(&lock); p = kmalloc_obj(*p, GFP_ATOMIC);”h]”hŒ2spin_lock(&lock); p = kmalloc_obj(*p, GFP_ATOMIC);”…”�”}”hjQ sbah}”(h]”h ]”h"]”h$]”h&]”hÅhÆuh1jl h³hÇh´Mýhj h²hubeh}”(h]”Œraw-spinlock-t-on-rt”ah ]”h"]”Œraw_spinlock_t on rt”ah$]”h&]”uh1hÖhjg h²hh³hÇh´Mìubh×)�”}”(hhh]”(hÜ)�”}”(hŒ bit spinlocks”h]”hŒ bit spinlocks”…”�”}”(hjj h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhjg h²hh³hÇh´Mubhý)�”}”(hŒøPREEMPT_RT cannot substitute bit spinlocks because a single bit is too small to accommodate an RT-mutex. Therefore, the semantics of bit spinlocks are preserved on PREEMPT_RT kernels, so that the raw_spinlock_t caveats also apply to bit spinlocks.”h]”hŒøPREEMPT_RT cannot substitute bit spinlocks because a single bit is too small to accommodate an RT-mutex. Therefore, the semantics of bit spinlocks are preserved on PREEMPT_RT kernels, so that the raw_spinlock_t caveats also apply to bit spinlocks.”…”�”}”(hjx h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjg h²hubhý)�”}”(hXYSome bit spinlocks are replaced with regular spinlock_t for PREEMPT_RT using conditional (#ifdef'ed) code changes at the usage site. In contrast, usage-site changes are not needed for the spinlock_t substitution. Instead, conditionals in header files and the core locking implementation enable the compiler to do the substitution transparently.”h]”hX[Some bit spinlocks are replaced with regular spinlock_t for PREEMPT_RT using conditional (#ifdef’ed) code changes at the usage site. In contrast, usage-site changes are not needed for the spinlock_t substitution. Instead, conditionals in header files and the core locking implementation enable the compiler to do the substitution transparently.”…”�”• }”(hj† h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M hjg h²hubeh}”(h]”Œ bit-spinlocks”ah ]”h"]”Œ bit spinlocks”ah$]”h&]”uh1hÖhjg h²hh³hÇh´Mubeh}”(h]”Œpreempt-rt-caveats”ah ]”h"]”Œpreempt_rt caveats”ah$]”h&]”uh1hÖhhØh²hh³hÇh´MWubh×)�”}”(hhh]”(hÜ)�”}”(hŒLock type nesting rules”h]”hŒLock type nesting rules”…”�”}”(hj§ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hÛhj¤ h²hh³hÇh´Mubhý)�”}”(hŒThe most basic rules are:”h]”hŒThe most basic rules are:”…”�”}”(hjµ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhj¤ h²hubj )�”}”(hX{- Lock types of the same lock category (sleeping, CPU local, spinning) can nest arbitrarily as long as they respect the general lock ordering rules to prevent deadlocks. - Sleeping lock types cannot nest inside CPU local and spinning lock types. - CPU local and spinning lock types can nest inside sleeping lock types. - Spinning lock types can nest inside all lock types ”h]”j)�”}”(hhh]”(j)�”}”(hŒ¨Lock types of the same lock category (sleeping, CPU local, spinning) can nest arbitrarily as long as they respect the general lock ordering rules to prevent deadlocks. ”h]”hý)�”}”(hŒ§Lock types of the same lock category (sleeping, CPU local, spinning) can nest arbitrarily as long as they respect the general lock ordering rules to prevent deadlocks.”h]”hŒ§Lock types of the same lock category (sleeping, CPU local, spinning) can nest arbitrarily as long as they respect the general lock ordering rules to prevent deadlocks.”…”�”}”(hjÎ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´MhjÊ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÇ ubj)�”}”(hŒJSleeping lock types cannot nest inside CPU local and spinning lock types. ”h]”hý)�”}”(hŒISleeping lock types cannot nest inside CPU local and spinning lock types.”h]”hŒISleeping lock types cannot nest inside CPU local and spinning lock types.”…”�”}”(hjæ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjâ ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÇ ubj)�”}”(hŒGCPU local and spinning lock types can nest inside sleeping lock types. ”h]”hý)�”}”(hŒFCPU local and spinning lock types can nest inside sleeping lock types.”h]”hŒFCPU local and spinning lock types can nest inside sleeping lock types.”…”�”}”(hjþ h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjú ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÇ ubj)�”}”(hŒ3Spinning lock types can nest inside all lock types ”h]”hý)�”}”(hŒ2Spinning lock types can nest inside all lock types”h]”hŒ2Spinning lock types can nest inside all lock types”…”�”}”(hjh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhjubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjÇ ubeh}”(h]”h ]”h"]”h$]”h&]”jejfuh1jh³hÇh´Mhjà ubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´Mhj¤ h²hubhý)�”}”(hŒ9These constraints apply both in PREEMPT_RT and otherwise.”h]”hŒ9These constraints apply both in PREEMPT_RT and otherwise.”…”�”}”(hj6h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´Mhj¤ h²hubhý)�”}”(hXThe fact that PREEMPT_RT changes the lock category of spinlock_t and rwlock_t from spinning to sleeping and substitutes local_lock with a per-CPU spinlock_t means that they cannot be acquired while holding a raw spinlock. This results in the following nesting ordering:”h]”hXThe fact that PREEMPT_RT changes the lock category of spinlock_t and rwlock_t from spinning to sleeping and substitutes local_lock with a per-CPU spinlock_t means that they cannot be acquired while holding a raw spinlock. This results in the following nesting ordering:”…”�”}”(hjDh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M!hj¤ h²hubj )�”}”(hŒZ1) Sleeping locks 2) spinlock_t, rwlock_t, local_lock 3) raw_spinlock_t and bit spinlocks ”h]”hŒenumerated_list”“”)�”}”(hhh]”(j)�”}”(hŒSleeping locks”h]”hý)�”}”(hj]h]”hŒSleeping locks”…”�”}”(hj_h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M&hj[ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjXubj)�”}”(hŒ spinlock_t, rwlock_t, local_lock”h]”hý)�”}”(hjth]”hŒ spinlock_t, rwlock_t, local_lock”…”�”}”(hjvh²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M'hjrubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjXubj)�”}”(hŒ!raw_spinlock_t and bit spinlocks ”h]”hý)�”}”(hŒ raw_spinlock_t and bit spinlocks”h]”hŒ raw_spinlock_t and bit spinlocks”…”�”}”(hj�h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M(hj‰ubah}”(h]”h ]”h"]”h$]”h&]”uh1jhjXubeh}”(h]”h ]”h"]”h$]”h&]”Œenumtype”Œarabic”Œprefix”hŒsuffix”Œ)”uh1jVhjRubah}”(h]”h ]”h"]”h$]”h&]”uh1j h³hÇh´M&hj¤ h²hubhý)�”}”(hŒZLockdep will complain if these constraints are violated, both in PREEMPT_RT and otherwise.”h]”hŒZLockdep will complain if these constraints are violated, both in PREEMPT_RT and otherwise.”…”�”}”(hj²h²hh³Nh´Nubah}”(h]”h ]”h"]”h$]”h&]”uh1hüh³hÇh´M*hj¤ h²hubeh}”(h]”Œlock-type-nesting-rules”ah ]”h"]”Œlock type nesting rules”ah$]”h&]”uh1hÖhhØh²hh³hÇh´Mubeh}”(h]”(Œlock-types-and-their-rules”hÕeh ]”h"]”(Œlock types and their rules”Œkernel_hacking_locktypes”eh$]”h&]”uh1hÖhhh²hh³hÇh´KŒexpect_referenced_by_name”}”jÎhÊsŒexpect_referenced_by_id”}”hÕhÊsubeh}”(h]”h ]”h"]”h$]”h&]”Œsource”hÇuh1hŒcurrent_source”NŒ current_line”NŒsettings”Œdocutils.frontend”ŒValues”“”)�”}”(hÛNŒ generator”NŒ datestamp”NŒ source_link”NŒ source_url”NŒ toc_backlinks”j Œfootnote_backlinks”KŒ sectnum_xform”KŒstrip_comments”NŒstrip_elements_with_classes”NŒ strip_classes”NŒ report_level”KŒ halt_level”KŒexit_status_level”KŒdebug”NŒwarning_stream”NŒ traceback”ˆŒinput_encoding”Œ utf-8-sig”Œinput_encoding_error_handler”Œstrict”Œoutput_encoding”Œutf-8”Œoutput_encoding_error_handler”j÷Œerror_encoding”Œutf-8”Œerror_encoding_error_handler”Œbackslashreplace”Œ language_code”Œen”Œrecord_dependencies”NŒconfig”NŒ id_prefix”hŒauto_id_prefix”Œid”Œ dump_settings”NŒdump_internals”NŒdump_transforms”NŒdump_pseudo_xml”NŒexpose_internals”NŒstrict_visitor”NŒ_disable_config”NŒ_source”hÇŒ _destination”NŒ _config_files”]”Œ7/var/lib/git/docbuild/linux/Documentation/docutils.conf”aŒfile_insertion_enabled”ˆŒ raw_enabled”KŒline_length_limit”M'Œpep_references”NŒ pep_base_url”Œhttps://peps.python.org/”Œpep_file_url_template”Œpep-%04d”Œrfc_references”NŒ rfc_base_url”Œ&https://datatracker.ietf.org/doc/html/”Œ tab_width”KŒtrim_footnote_reference_space”‰Œsyntax_highlight”Œlong”Œ smart_quotes”ˆŒsmartquotes_locales”]”Œcharacter_level_inline_markup”‰Œdoctitle_xform”‰Œ docinfo_xform”KŒsectsubtitle_xform”‰Œ image_loading”Œlink”Œembed_stylesheet”‰Œcloak_email_addresses”ˆŒsection_self_link”‰Œenv”NubŒreporter”NŒindirect_targets”]”Œsubstitution_defs”}”Œsubstitution_names”}”Œrefnames”}”Œrefids”}”hÕ]”hÊasŒnameids”}”(jÎhÕjÍjÊj€j}j×jÔjÙjÖj+j(jÏjÌj$j!jgjdjÃjÀj»j¸jEjBj=j:j' j$ j™j–jÎjËj j jÅ j j_ j\ j” j‘ j½ jº jd ja j\ jY j¡ jž j j j j jd ja j™ j– jÅjÂuŒ nametypes”}”(jΈj͉j€‰j׉jÙ‰j+‰jωj$‰jg‰jÉj»‰jE‰j=‰j' ‰j™‰jΉj ‰jÅ ‰j_ ‰j” ‰j½ ‰jd ‰j\ ‰j¡ ‰j ‰j ‰jd ‰j™ ‰jʼnuh}”(hÕhØjÊhØj}hëjÔjƒjÖj”j(jÜjÌj.j!jÚjdj'jÀjjj¸j—jBjÆj:jj$ jHj–jJjËjœj jÑj j* j\ j; j‘ jb jº j— ja jÈ jY jõ jž jg j jx j j ja j j– jg jÂj¤ uŒ footnote_refs”}”Œ citation_refs”}”Œ autofootnotes”]”Œautofootnote_refs”]”Œsymbol_footnotes”]”Œsymbol_footnote_refs”]”Œ footnotes”]”Œ citations”]”Œautofootnote_start”KŒsymbol_footnote_start”KŒ id_counter”Œ collections”ŒCounter”“”}”…”R”Œparse_messages”]”Œtransform_messages”]”hŒsystem_message”“”)�”}”(hhh]”hý)�”}”(hhh]”hŒ>Hyperlink target "kernel-hacking-locktypes" is not referenced.”…”�”}”hjasbah}”(h]”h ]”h"]”h$]”h&]”uh1hühj^ubah}”(h]”h ]”h"]”h$]”h&]”Œlevel”KŒtype”ŒINFO”Œsource”hÇŒline”Kuh1j\ubaŒ transformer”NŒ include_log”]”Œ decoration”Nh²hub.