# Making unwinding through JIT-ed code scalable - Optimistic Lock Coupling

DevFeed: [Making unwinding through JIT-ed code scalable - Optimistic Lock Coupling](<https://devfeed.tech/articles/making-unwinding-through-jit-ed-code-scalable-optimistic-lock-coupling-25079.md>)

Original publisher: [Read original article](<https://databasearchitects.blogspot.com/2022/06/optimisticlockcoupling.html>)

Author: Thomas Neumann (noreply@blogger.com)

Published: 2022-06-26T08:52:00Z

Content type: article

Language: en

Sources: [Database Architects](<https://devfeed.tech/sources/database-architects.md>)

Topics: [Exception](<https://devfeed.tech/topics/exception.md>), [Data structures](<https://devfeed.tech/topics/data-structures.md>), [Concurrency](<https://devfeed.tech/topics/concurrency.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [data-structure](<https://devfeed.tech/tags/data-structure.md>), [exception](<https://devfeed.tech/tags/exception.md>), [exception-handling](<https://devfeed.tech/tags/exception-handling.md>), [locking](<https://devfeed.tech/tags/locking.md>), [mutex](<https://devfeed.tech/tags/mutex.md>), [performance](<https://devfeed.tech/tags/performance.md>), [set](<https://devfeed.tech/tags/set.md>)

## AI overview

The article explains a scalable approach to unwinding through JIT-ed code using a read-optimized B-tree with optimistic lock coupling. Writers use conventional exclusive lock coupling, while readers use version locks and validate their reads so they can run in parallel when writes are uncommon.

## Source excerpt

This article is part of the series about scalable unwinding that starts here. When thinking about exception handling it is reasonable to assume that we will have far more unwinding requests than changes to the unwinding tables. In our setup, the tables only change when JITed code is added to or removed from the program. That is always expensive to begin with due the mprotect calls, TLB shootdowns, etc. Thus we can safely assume that we will have at most a few hundred updates per second even in extreme cases, probably far less. Lookups however can easily reach thousands or even millions per second, as we do one lookup per frame. This motivates us to use a read-optimized data structure, a b-tree with optimistic lock coupling: Writers use traditional lock coupling (lock parent node exclusive, lock child node exclusive, release parent node, lock child of child, etc.), which works fine as long as there is not too much contention. Readers however have to do something else, as we expect thousands of them. One might be tempted to use a rw-lock for readers, but that does not help. Locking an rw-lock in shared mode causes an atomic write, which makes the threads fight over the cache line of the lock even if there is no (logical) contention. Instead, we use version locks, where readers do no write at all: // Common logic for version locks struct version_lock { // The lock itself. The lowest bit indicates an exclusive lock, // the second bit indicates waiting threads. All other bits are // used as counter to recognize changes. // Overflows are okay here, we must only prevent overflow to the // same value within one lock_optimistic/validate // range. Even on 32 bit platforms that would require 1 billion // frame registrations within the time span of a few assembler // instructions. uintptr_t version_lock; }; #ifdef __GTHREAD_HAS_COND // We should never get contention within the tree as it rarely changes. // But if we ever do get contention we use these for waiting static __gthre