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

Update net_plugin to support clang Thread Safety Analysis features #1268

Merged
merged 22 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d897dfe
Thread Safety Analysis - wip
greg7mdp Jun 9, 2023
7a8be73
Fix one warning
greg7mdp Jun 9, 2023
1508378
Fix thread safety warnings for `sync_mtx`
greg7mdp Jun 10, 2023
337e96c
Add thread safety directives for two other mutexes.
greg7mdp Jun 10, 2023
5ec8c2a
Add thread safety directives to some other mutexes.
greg7mdp Jun 10, 2023
25bb155
Add thread safety directives for queued_buffer class.
greg7mdp Jun 10, 2023
902fdaa
Remove explicit template parameters `<std::mutex>`.
greg7mdp Jun 10, 2023
8368562
Add thread safety directives for conn_mtx
greg7mdp Jun 10, 2023
563bbba
whitespace
greg7mdp Jun 10, 2023
6fdb21d
Add version check for enabling `-Wthread-safety` (version >= 14)
greg7mdp Jun 12, 2023
d954698
Whitespace cleanup
greg7mdp Jun 12, 2023
a0a1eff
Address PR comments
greg7mdp Jun 12, 2023
28ad1c3
Address PR comments
greg7mdp Jun 12, 2023
6124256
Restore exception safety as discussed with Kevin.
greg7mdp Jun 12, 2023
30ffccc
Do not pass the `mutex *` as suggested in PR comment.
greg7mdp Jun 12, 2023
3a8584c
Hold the lock during `request_next_chunk` method as suggested
greg7mdp Jun 12, 2023
76129fd
Revert unnecessary logic changes.
greg7mdp Jun 12, 2023
994b547
Remove `fc::unique_lock` copy constructor which I am not sure how to …
greg7mdp Jun 12, 2023
07e2a9b
Merge branch 'main' of github.com:AntelopeIO/leap into gh-1230
greg7mdp Jun 12, 2023
45844e0
Fix a couple issues from the previous merge.
greg7mdp Jun 12, 2023
a4c07cf
Merge branch 'main' of github.com:AntelopeIO/leap into gh-1230
greg7mdp Jun 12, 2023
28f6e59
Merge branch 'main' of github.com:AntelopeIO/leap into gh-1230
greg7mdp Jun 22, 2023
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
210 changes: 210 additions & 0 deletions libraries/libfc/include/fc/mutex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
#pragma once

// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__) && (!defined(SWIG))
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif

#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))

#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)

#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))

#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))

#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))

#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))

#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))

#define REQUIRES_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))

#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))

#define ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))

#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))

#define RELEASE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))

#define RELEASE_GENERIC(...) THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))

#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))

#define TRY_ACQUIRE_SHARED(...) THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))

#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))

#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))

#define ASSERT_SHARED_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))

#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))

#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)

#include <mutex>
#include <shared_mutex>

namespace fc {

// Defines an annotated interface for mutexes.
// These methods can be implemented to use any internal mutex implementation.
class CAPABILITY("mutex") mutex {
private:
std::mutex mutex_;

public:
// Acquire/lock this mutex exclusively. Only one thread can have exclusive
// access at any one time. Write operations to guarded data require an
// exclusive lock.
void lock() ACQUIRE() { mutex_.lock(); }

// Release/unlock an exclusive mutex.
void unlock() RELEASE() { mutex_.unlock(); }

// Try to acquire the mutex. Returns true on success, and false on failure.
bool try_lock() TRY_ACQUIRE(true) { return mutex_.try_lock(); }
};

// Defines an annotated interface for mutexes.
// These methods can be implemented to use any internal mutex implementation.
class CAPABILITY("shared_mutex") shared_mutex {
private:
std::shared_mutex mutex_;

public:
// Acquire/lock this mutex exclusively. Only one thread can have exclusive
// access at any one time. Write operations to guarded data require an
// exclusive lock.
void lock() ACQUIRE() { mutex_.lock(); }

// Acquire/lock this mutex for read operations, which require only a shared
// lock. This assumes a multiple-reader, single writer semantics. Multiple
// threads may acquire the mutex simultaneously as readers, but a writer
// must wait for all of them to release the mutex before it can acquire it
// exclusively.
void lock_shared() ACQUIRE_SHARED() { mutex_.lock_shared(); }

// Release/unlock an exclusive mutex.
void unlock() RELEASE() { mutex_.unlock(); }

// Release/unlock a shared mutex.
void unlock_shared() RELEASE_SHARED() { mutex_.unlock_shared(); }

// Try to acquire the mutex. Returns true on success, and false on failure.
bool try_lock() TRY_ACQUIRE(true) { return mutex_.try_lock(); }

// Try to acquire the mutex for read operations.
bool try_lock_shared() TRY_ACQUIRE_SHARED(true) { return mutex_.try_lock_shared(); }

// Assert that this mutex is currently held by the calling thread.
// void AssertHeld() ASSERT_CAPABILITY(this);

// Assert that is mutex is currently held for read operations.
// void AssertReaderHeld() ASSERT_SHARED_CAPABILITY(this);

// For negative capabilities.
// const Mutex& operator!() const { return *this; }
};

// Tag types for selecting a constructor.
struct adopt_lock_t {} inline constexpr adopt_lock = {};
struct defer_lock_t {} inline constexpr defer_lock = {};
struct shared_lock_t {} inline constexpr shared_lock = {};

// LockGuard is an RAII class that acquires a mutex in its constructor, and
// releases it in its destructor.
template <typename M>
class SCOPED_CAPABILITY lock_guard {
private:
M& mut;

public:
// Acquire mu, implicitly acquire *this and associate it with mu.
lock_guard(M& mu) ACQUIRE(mu)
: mut(mu) {
mu.lock();
}

// Assume mu is held, implicitly acquire *this and associate it with mu.
lock_guard(M& mu, adopt_lock_t) REQUIRES(mu)
: mut(mu) {}

~lock_guard() RELEASE() { mut.unlock(); }
};

// unique_lock is an RAII class that acquires a mutex in its constructor, and
// releases it in its destructor.
template <typename M>
class SCOPED_CAPABILITY unique_lock {
private:
using mutex_type = M;

M* mut;
bool locked;

public:
unique_lock() noexcept
: mut(nullptr)
, locked(false) {}

// Acquire mu, implicitly acquire *this and associate it with mu.
explicit unique_lock(M& mu) ACQUIRE(mu)
: mut(&mu)
, locked(true) {
mut->lock();
}

// Assume mu is held, implicitly acquire *this and associate it with mu.
unique_lock(M& mu, adopt_lock_t) REQUIRES(mu)
: mut(&mu)
, locked(true) {}

// Assume mu is not held, implicitly acquire *this and associate it with mu.
unique_lock(M& mu, defer_lock_t) EXCLUDES(mu)
: mut(mu)
, locked(false) {}

// Release *this and all associated mutexes, if they are still held.
// There is no warning if the scope was already unlocked before.
~unique_lock() RELEASE() {
if (locked)
mut->unlock();
}

// Acquire all associated mutexes exclusively.
void lock() ACQUIRE() {
mut->lock();
locked = true;
}

// Try to acquire all associated mutexes exclusively.
bool try_lock() TRY_ACQUIRE(true) { return locked = mut->try_lock(); }

// Release all associated mutexes. Warn on double unlock.
void unlock() RELEASE() {
mut->unlock();
locked = false;
}

mutex_type* release() noexcept RETURN_CAPABILITY(this) {
mutex_type* res = mut;
mut = nullptr;
locked = false;
return res;
}

mutex_type* mutex() const noexcept { return mut; }

bool owns_lock() const noexcept { return locked; }

explicit operator bool() const noexcept { return locked; }
};

} // namespace fc
4 changes: 4 additions & 0 deletions plugins/net_plugin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ add_library( net_plugin
net_plugin.cpp
${HEADERS} )

if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 14.0)
target_compile_options(net_plugin PUBLIC -Wthread-safety)
endif()

target_link_libraries( net_plugin chain_plugin producer_plugin appbase fc )
target_include_directories( net_plugin PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include "${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/appbase/include")

Expand Down
Loading