#pragma once #include"srw_lock.h" #include"my_atomic_wrapper.h" #ifdef UNIV_DEBUG # include <unordered_set> #endif
/** A "fat" rw-lock that supports S(shared),U(update,orshared-exclusive),andX(exclusive)modes aswellasrecursiveUandXlatchacquisition
@tparam ssux ssux_lock_impl or ssux_lock */ template<typename ssux> class sux_lock final
{ /** The underlying non-recursive lock */
ssux lock; /** Numbers of U and X locks. Protected by lock. */
uint32_t recursive; /** The owner of the U or X lock (0 if none); protected by lock */
std::atomic<pthread_t> writer; /** Special writer!=0 value to indicate that the lock is non-recursive
and will be released by an I/O thread */ #ifdefined __linux__ || defined _WIN32 static constexpr pthread_t FOR_IO= pthread_t(~0UL); #else # define FOR_IO ((pthread_t) ~0UL) /* it could be a pointer */ #endif #ifdef UNIV_DEBUG /** Protects readers */ mutable srw_mutex readers_lock; /** Threads that hold the lock in shared mode */
std::atomic<std::unordered_multiset<pthread_t>*> readers; #endif
/** The multiplier in recursive for X locks */ static constexpr uint32_t RECURSIVE_X= 1U; /** The multiplier in recursive for U locks */ static constexpr uint32_t RECURSIVE_U= 1U << 16; /** The maximum allowed level of recursion */ static constexpr uint32_t RECURSIVE_MAX= RECURSIVE_U - 1;
private: /** Transfer the ownership of a write lock to another thread
@param id the new owner of the U or X lock */ void set_new_owner(pthread_t id)
{
writer.store(id, std::memory_order_relaxed);
} /** Assign the ownership of a write lock to a thread
@param id the owner of the U or X lock */ void set_first_owner(pthread_t id)
{
writer.store(id, std::memory_order_relaxed);
} #ifdef UNIV_DEBUG /** Register the current thread as a holder of a shared lock */ void s_lock_register()
{ const pthread_t id= pthread_self();
readers_lock.wr_lock(); auto r= readers.load(std::memory_order_relaxed); if (!r)
{
r= new std::unordered_multiset<pthread_t>();
readers.store(r, std::memory_order_relaxed);
}
r->emplace(id);
readers_lock.wr_unlock();
} #endif
public: /** In crash recovery, claim the ownership
of the exclusive block lock to the current thread */ void claim_ownership() { set_new_owner(pthread_self()); }
/** @return whether the current thread is holding X or U latch */ bool have_u_or_x() const
{ if (pthread_self() != writer.load(std::memory_order_relaxed)) returnfalse;
ut_ad(recursive); returntrue;
} /** @return whether the current thread is holding U but not X latch */ bool have_u_not_x() const
{ return have_u_or_x() && !((recursive / RECURSIVE_X) & RECURSIVE_MAX); } /** @return whether the current thread is holding X latch */ bool have_x() const
{ return have_u_or_x() && ((recursive / RECURSIVE_X) & RECURSIVE_MAX); } #ifdef UNIV_DEBUG /** @return whether the current thread is holding S latch */ bool have_s() const
{ if (auto r= readers.load(std::memory_order_relaxed))
{
readers_lock.wr_lock(); bool found= r->find(pthread_self()) != r->end();
readers_lock.wr_unlock(); return found;
} returnfalse;
} /** @return whether the current thread is holding the latch */ bool have_any() const { return have_u_or_x() || have_s(); } #endif
/** Acquire a shared lock */ inlinevoid s_lock(); inlinevoid s_lock(constchar *file, unsigned line); /** Acquire a shared lock, skipping any spin loop */ inlinevoid s_lock_nospin() noexcept; /** Acquire an update lock */ inlinevoid u_lock(); inlinevoid u_lock(constchar *file, unsigned line); /** Acquire an exclusive lock */ inlinevoid x_lock(bool for_io= false); inlinevoid x_lock(constchar *file, unsigned line); /** Acquire a recursive exclusive lock */ void x_lock_recursive() { writer_recurse<false>(); } /** Upgrade an update lock */ inlinevoid u_x_upgrade(); inlinevoid u_x_upgrade(constchar *file, unsigned line); /** @return whether a shared lock was upgraded to exclusive */ bool s_x_upgrade_try()
{
ut_ad(have_s());
ut_ad(!have_u_or_x()); if (!lock.rd_u_upgrade_try()) returnfalse;
claim_ownership();
s_unlock();
lock.u_wr_upgrade();
recursive= RECURSIVE_X; returntrue;
}
__attribute__((warn_unused_result)) /** @return whether the operation succeeded without waiting */ bool s_x_upgrade()
{ if (s_x_upgrade_try()) returntrue;
s_unlock();
x_lock(); returnfalse;
}
/** Downgrade a single exclusive lock to an update lock */ void x_u_downgrade()
{
ut_ad(have_u_or_x());
ut_ad(recursive <= RECURSIVE_MAX);
recursive*= RECURSIVE_U;
lock.wr_u_downgrade();
} /** Downgrade a single update lock to a shared lock */ void u_s_downgrade()
{
ut_ad(have_u_or_x());
ut_ad(recursive == RECURSIVE_U);
recursive= 0;
set_new_owner(0);
lock.u_rd_downgrade();
ut_d(s_lock_register());
}
/** Acquire an exclusive lock or upgrade an update lock
@return whether U locks were upgraded to X */ inlinebool x_lock_upgraded();
/** Try to acquire an update lock @paramfor_iowhetherthelockwillbereleasedbyanotherthread
@return whether the update lock was acquired */ inlinebool u_lock_try(bool for_io);
/** Try to acquire an exclusive lock
@return whether an exclusive lock was acquired */ inlinebool x_lock_try();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.