blob: 01de499bd04a3652994f30b08516a97b2ea80a70 (
plain)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/utils/port/config.h"
#include "td/utils/common.h"
#include "td/utils/Status.h"
#if TD_PORT_POSIX
#include <pthread.h>
#endif
#include <memory>
namespace td {
class RwMutex {
public:
RwMutex() {
init();
}
RwMutex(const RwMutex &) = delete;
RwMutex &operator=(const RwMutex &) = delete;
RwMutex(RwMutex &&other) noexcept {
init();
other.clear();
}
RwMutex &operator=(RwMutex &&other) noexcept {
other.clear();
return *this;
}
~RwMutex() {
clear();
}
bool empty() const {
return !is_valid_;
}
void init();
void clear();
struct ReadUnlock {
void operator()(RwMutex *ptr) {
ptr->unlock_read_unsafe();
}
};
struct WriteUnlock {
void operator()(RwMutex *ptr) {
ptr->unlock_write_unsafe();
}
};
using ReadLock = std::unique_ptr<RwMutex, ReadUnlock>;
using WriteLock = std::unique_ptr<RwMutex, WriteUnlock>;
Result<ReadLock> lock_read() TD_WARN_UNUSED_RESULT {
lock_read_unsafe();
return ReadLock(this);
}
Result<WriteLock> lock_write() TD_WARN_UNUSED_RESULT {
lock_write_unsafe();
return WriteLock(this);
}
void lock_read_unsafe();
void lock_write_unsafe();
void unlock_read_unsafe();
void unlock_write_unsafe();
private:
bool is_valid_ = false;
#if TD_PORT_POSIX
pthread_rwlock_t mutex_;
#elif TD_PORT_WINDOWS
unique_ptr<SRWLOCK> mutex_;
#endif
};
inline void RwMutex::init() {
CHECK(empty());
is_valid_ = true;
#if TD_PORT_POSIX
pthread_rwlock_init(&mutex_, nullptr);
#elif TD_PORT_WINDOWS
mutex_ = make_unique<SRWLOCK>();
InitializeSRWLock(mutex_.get());
#endif
}
inline void RwMutex::clear() {
if (is_valid_) {
#if TD_PORT_POSIX
pthread_rwlock_destroy(&mutex_);
#elif TD_PORT_WINDOWS
mutex_.release();
#endif
is_valid_ = false;
}
}
inline void RwMutex::lock_read_unsafe() {
CHECK(!empty());
// TODO error handling
#if TD_PORT_POSIX
pthread_rwlock_rdlock(&mutex_);
#elif TD_PORT_WINDOWS
AcquireSRWLockShared(mutex_.get());
#endif
}
inline void RwMutex::lock_write_unsafe() {
CHECK(!empty());
#if TD_PORT_POSIX
pthread_rwlock_wrlock(&mutex_);
#elif TD_PORT_WINDOWS
AcquireSRWLockExclusive(mutex_.get());
#endif
}
inline void RwMutex::unlock_read_unsafe() {
CHECK(!empty());
#if TD_PORT_POSIX
pthread_rwlock_unlock(&mutex_);
#elif TD_PORT_WINDOWS
ReleaseSRWLockShared(mutex_.get());
#endif
}
inline void RwMutex::unlock_write_unsafe() {
CHECK(!empty());
#if TD_PORT_POSIX
pthread_rwlock_unlock(&mutex_);
#elif TD_PORT_WINDOWS
ReleaseSRWLockExclusive(mutex_.get());
#endif
}
} // namespace td
|