2023-01-09 14:58:44 +00:00
|
|
|
#pragma once
|
|
|
|
|
2023-01-11 12:23:33 +00:00
|
|
|
#include <shared_mutex>
|
|
|
|
|
2023-01-09 14:58:44 +00:00
|
|
|
#ifdef OS_LINUX /// Because of futex
|
|
|
|
|
|
|
|
#include <Common/CancelToken.h>
|
|
|
|
#include <base/types.h>
|
2023-01-09 16:46:07 +00:00
|
|
|
#include <base/defines.h>
|
2023-01-09 14:58:44 +00:00
|
|
|
#include <atomic>
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2023-01-10 01:26:59 +00:00
|
|
|
// Reimplementation of `std::shared_mutex` that can interoperate with thread cancellation via `CancelToken::signal()`.
|
|
|
|
// It has cancellation point on waiting during `lock()` and `shared_lock()`.
|
|
|
|
// NOTE: It has NO cancellation points on fast code path, when locking does not require waiting.
|
2023-01-09 16:46:07 +00:00
|
|
|
class TSA_CAPABILITY("CancelableSharedMutex") CancelableSharedMutex
|
2023-01-09 14:58:44 +00:00
|
|
|
{
|
|
|
|
public:
|
|
|
|
CancelableSharedMutex();
|
|
|
|
~CancelableSharedMutex() = default;
|
|
|
|
CancelableSharedMutex(const CancelableSharedMutex &) = delete;
|
|
|
|
CancelableSharedMutex & operator=(const CancelableSharedMutex &) = delete;
|
|
|
|
|
|
|
|
// Exclusive ownership
|
2023-01-09 16:46:07 +00:00
|
|
|
void lock() TSA_ACQUIRE();
|
|
|
|
bool try_lock() TSA_TRY_ACQUIRE(true);
|
|
|
|
void unlock() TSA_RELEASE();
|
2023-01-09 14:58:44 +00:00
|
|
|
|
|
|
|
// Shared ownership
|
2023-01-09 16:46:07 +00:00
|
|
|
void lock_shared() TSA_ACQUIRE_SHARED();
|
|
|
|
bool try_lock_shared() TSA_TRY_ACQUIRE_SHARED(true);
|
|
|
|
void unlock_shared() TSA_RELEASE_SHARED();
|
2023-01-09 14:58:44 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
// State 64-bits layout:
|
|
|
|
// 1b - 31b - 1b - 31b
|
|
|
|
// signaled - writers - signaled - readers
|
|
|
|
// 63------------------------------------0
|
|
|
|
// Two 32-bit words are used for cancelable waiting, so each has its own separate signaled bit
|
|
|
|
static constexpr UInt64 readers = (1ull << 32ull) - 1ull - CancelToken::signaled;
|
|
|
|
static constexpr UInt64 readers_signaled = CancelToken::signaled;
|
|
|
|
static constexpr UInt64 writers = readers << 32ull;
|
|
|
|
static constexpr UInt64 writers_signaled = readers_signaled << 32ull;
|
|
|
|
|
|
|
|
alignas(64) std::atomic<UInt64> state;
|
|
|
|
std::atomic<UInt32> waiters;
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
// WARNING: We support cancelable synchronization primitives only on linux for now
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
using CancelableSharedMutex = std::shared_mutex;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|