Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to use futex APIs for spinlock #149

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ project(libcuckoo

# put these in the cache so they show up in ccmake
option (BUILD_EXAMPLES "build example libcuckoo programs")
option (LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT "Optimize the spinlock implementation with C++20 futex support" OFF)

# Add the libcuckoo interface target
add_subdirectory(libcuckoo)
Expand Down
4 changes: 4 additions & 0 deletions libcuckoo/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ add_library(libcuckoo::libcuckoo ALIAS libcuckoo)
# will have c++11 turned on in their compile when they use this target.
# XXX: newer cmakes have a "cxx_std_11" feature that could be used
target_compile_features (libcuckoo INTERFACE cxx_constexpr)
if (LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT)
target_compile_features(libcuckoo INTERFACE cxx_std_20)
target_compile_definitions(libcuckoo INTERFACE LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT=1)
endif ()

# Include relative to the base directory
target_include_directories(libcuckoo INTERFACE
Expand Down
44 changes: 39 additions & 5 deletions libcuckoo/cuckoohash_map.hh
Original file line number Diff line number Diff line change
Expand Up @@ -819,12 +819,29 @@ private:
LIBCUCKOO_SQUELCH_PADDING_WARNING
class LIBCUCKOO_ALIGNAS(64) spinlock {
public:
spinlock() : elem_counter_(0), is_migrated_(true) { lock_.clear(); }
spinlock() noexcept
:
#if LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
lock_(),
#endif
elem_counter_(0), is_migrated_(true) {

#if !LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
lock_.clear();
#endif
}

spinlock(const spinlock &other) noexcept
: elem_counter_(other.elem_counter()),
:
#if LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
lock_(),
#endif
elem_counter_(other.elem_counter()),
is_migrated_(other.is_migrated()) {

#if !LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
lock_.clear();
#endif
}

spinlock &operator=(const spinlock &other) noexcept {
Expand All @@ -834,14 +851,31 @@ private:
}

void lock() noexcept {
while (lock_.test_and_set(std::memory_order_acq_rel))
;
// Optimistically assume the lock is free
while (lock_.test_and_set(std::memory_order_acq_rel)) {
#if LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
// Wait for lock to be released utilizing C++20 futex support
lock_.wait(true, std::memory_order::relaxed);
#endif
}
}

void unlock() noexcept { lock_.clear(std::memory_order_release); }
void unlock() noexcept {
lock_.clear(std::memory_order_release);
#if LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
lock_.notify_one();
#endif
}

bool try_lock() noexcept {
#if LIBCUCKOO_USE_CXX20_FUTEX_SUPPORT
// First do a relaxed load to check if lock is free in order to prevent
// unnecessary cache misses if someone does while(!try_lock())
return !lock_.test(std::memory_order_relaxed) &&
!lock_.test_and_set(std::memory_order_acq_rel);
#else
return !lock_.test_and_set(std::memory_order_acq_rel);
#endif
}

counter_type &elem_counter() noexcept { return elem_counter_; }
Expand Down