diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:07:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 18:07:14 +0000 |
commit | a175314c3e5827eb193872241446f2f8f5c9d33c (patch) | |
tree | cd3d60ca99ae00829c52a6ca79150a5b6e62528b /storage/innobase/include/rw_lock.h | |
parent | Initial commit. (diff) | |
download | mariadb-10.5-upstream/1%10.5.12.tar.xz mariadb-10.5-upstream/1%10.5.12.zip |
Adding upstream version 1:10.5.12.upstream/1%10.5.12upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/innobase/include/rw_lock.h')
-rw-r--r-- | storage/innobase/include/rw_lock.h | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/storage/innobase/include/rw_lock.h b/storage/innobase/include/rw_lock.h new file mode 100644 index 00000000..b50a76fa --- /dev/null +++ b/storage/innobase/include/rw_lock.h @@ -0,0 +1,112 @@ +/***************************************************************************** + +Copyright (c) 2020, MariaDB Corporation. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +*****************************************************************************/ + +#pragma once +#include <atomic> +#include "my_dbug.h" + +/** Simple read-write lock based on std::atomic */ +class rw_lock +{ + /** The lock word */ + std::atomic<uint32_t> lock; + +protected: + /** Available lock */ + static constexpr uint32_t UNLOCKED= 0; + /** Flag to indicate that write_lock() is being held */ + static constexpr uint32_t WRITER= 1U << 31; + /** Flag to indicate that write_lock_wait() is pending */ + static constexpr uint32_t WRITER_WAITING= 1U << 30; + /** Flag to indicate that write_lock() or write_lock_wait() is pending */ + static constexpr uint32_t WRITER_PENDING= WRITER | WRITER_WAITING; + + /** Start waiting for an exclusive lock. */ + void write_lock_wait_start() + { lock.fetch_or(WRITER_WAITING, std::memory_order_relaxed); } + /** Try to acquire a shared lock. + @param l the value of the lock word + @return whether the lock was acquired */ + bool read_trylock(uint32_t &l) + { + l= UNLOCKED; + while (!lock.compare_exchange_strong(l, l + 1, std::memory_order_acquire, + std::memory_order_relaxed)) + { + DBUG_ASSERT(!(WRITER & l) || !(~WRITER_PENDING & l)); + if (l & WRITER_PENDING) + return false; + } + return true; + } + /** Wait for an exclusive lock. + @return whether the exclusive lock was acquired */ + bool write_lock_poll() + { + auto l= WRITER_WAITING; + if (lock.compare_exchange_strong(l, WRITER, std::memory_order_acquire, + std::memory_order_relaxed)) + return true; + if (!(l & WRITER_WAITING)) + /* write_lock() must have succeeded for another thread */ + write_lock_wait_start(); + return false; + } + +public: + /** Default constructor */ + rw_lock() : lock(UNLOCKED) {} + + /** Release a shared lock */ + void read_unlock() + { + IF_DBUG_ASSERT(auto l=,) lock.fetch_sub(1, std::memory_order_release); + DBUG_ASSERT(l & ~WRITER_PENDING); /* at least one read lock */ + DBUG_ASSERT(!(l & WRITER)); /* no write lock must have existed */ + } + /** Release an exclusive lock */ + void write_unlock() + { + IF_DBUG_ASSERT(auto l=,) lock.fetch_sub(WRITER, std::memory_order_release); + DBUG_ASSERT(l & WRITER); /* the write lock must have existed */ + } + /** Try to acquire a shared lock. + @return whether the lock was acquired */ + bool read_trylock() { uint32_t l; return read_trylock(l); } + /** Try to acquire an exclusive lock. + @return whether the lock was acquired */ + bool write_trylock() + { + auto l= UNLOCKED; + return lock.compare_exchange_strong(l, WRITER, std::memory_order_acquire, + std::memory_order_relaxed); + } + + /** @return whether an exclusive lock is being held by any thread */ + bool is_write_locked() const + { return !!(lock.load(std::memory_order_relaxed) & WRITER); } + /** @return whether a shared lock is being held by any thread */ + bool is_read_locked() const + { + auto l= lock.load(std::memory_order_relaxed); + return (l & ~WRITER_PENDING) && !(l & WRITER); + } + /** @return whether any lock is being held by any thread */ + bool is_locked() const + { return (lock.load(std::memory_order_relaxed) & ~WRITER_WAITING) != 0; } +}; |