aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/clickhouse/src/Common/CancelableSharedMutex.h
blob: af87b213479cb35e0759b8f3128dedae85f310f7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#pragma once

#include <shared_mutex>

#ifdef OS_LINUX /// Because of futex

#include <Common/CancelToken.h>
#include <base/types.h>
#include <base/defines.h>
#include <atomic>

namespace DB
{

// 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.
class TSA_CAPABILITY("CancelableSharedMutex") CancelableSharedMutex
{
public:
    CancelableSharedMutex();
    ~CancelableSharedMutex() = default;
    CancelableSharedMutex(const CancelableSharedMutex &) = delete;
    CancelableSharedMutex & operator=(const CancelableSharedMutex &) = delete;

    // Exclusive ownership
    void lock() TSA_ACQUIRE();
    bool try_lock() TSA_TRY_ACQUIRE(true);
    void unlock() TSA_RELEASE();

    // Shared ownership
    void lock_shared() TSA_ACQUIRE_SHARED();
    bool try_lock_shared() TSA_TRY_ACQUIRE_SHARED(true);
    void unlock_shared() TSA_RELEASE_SHARED();

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