1 #include "filezilla.h"
2
3 #include "controlsocket.h"
4 #include "oplock_manager.h"
5
6 #include <assert.h>
7
OpLock(OpLockManager * mgr,size_t socket,size_t lock)8 OpLock::OpLock(OpLockManager * mgr, size_t socket, size_t lock)
9 : mgr_(mgr)
10 , socket_(socket)
11 , lock_(lock)
12 {
13 }
14
~OpLock()15 OpLock::~OpLock()
16 {
17 if (mgr_) {
18 mgr_->Unlock(*this);
19 mgr_ = nullptr;
20 }
21 }
22
OpLock(OpLock && op)23 OpLock::OpLock(OpLock && op) noexcept
24 {
25 if (mgr_) {
26 mgr_->Unlock(*this);
27 }
28 mgr_ = op.mgr_;
29 socket_ = op.socket_;
30 lock_ = op.lock_;
31
32 op.mgr_ = nullptr;
33 }
34
operator =(OpLock && op)35 OpLock& OpLock::operator=(OpLock && op) noexcept
36 {
37 if (this != &op) {
38 if (mgr_) {
39 mgr_->Unlock(*this);
40 }
41 mgr_ = op.mgr_;
42 socket_ = op.socket_;
43 lock_ = op.lock_;
44
45 op.mgr_ = nullptr;
46 }
47
48 return *this;
49 }
50
waiting() const51 bool OpLock::waiting() const
52 {
53 if (mgr_) {
54 return mgr_->Waiting(*this);
55 }
56
57 return false;
58 }
59
Lock(CControlSocket * socket,locking_reason reason,CServerPath const & path,bool inclusive)60 OpLock OpLockManager::Lock(CControlSocket * socket, locking_reason reason, CServerPath const& path, bool inclusive)
61 {
62 fz::scoped_lock l(mtx_);
63
64 size_t socket_index = get_or_create(socket);
65 auto & sli = socket_locks_[socket_index];
66
67 lock_info info;
68 info.reason = reason;
69 info.inclusive = inclusive;
70 info.path = path;
71
72 for (auto const& other_sli : socket_locks_) {
73 if (other_sli.control_socket_ == socket || other_sli.server_ != sli.server_) {
74 continue;
75 }
76
77 for (auto const& lock : other_sli.locks_) {
78 if (reason != lock.reason || lock.waiting || lock.released) {
79 continue;
80 }
81 if (lock.path == path || (lock.inclusive && lock.path.IsParentOf(path, false))) {
82 info.waiting = true;
83 break;
84 }
85 if (inclusive && path.IsParentOf(lock.path, false)) {
86 info.waiting = true;
87 break;
88 }
89 }
90 if (info.waiting) {
91 break;
92 }
93 }
94
95 sli.locks_.push_back(info);
96
97 return OpLock(this, socket_index, sli.locks_.size() - 1);
98 }
99
Unlock(OpLock & lock)100 void OpLockManager::Unlock(OpLock & lock)
101 {
102 fz::scoped_lock l(mtx_);
103 assert(lock.socket_ < socket_locks_.size());
104 assert(lock.lock_ < socket_locks_[lock.socket_].locks_.size());
105
106 bool was_waiting = false;
107
108 auto & sli = socket_locks_[lock.socket_];
109
110 was_waiting = sli.locks_[lock.lock_].waiting;
111
112 if (lock.lock_ + 1 == sli.locks_.size()) {
113 sli.locks_.pop_back();
114 while (!sli.locks_.empty() && sli.locks_.back().released) {
115 sli.locks_.pop_back();
116 }
117 if (sli.locks_.empty()) {
118 if (lock.socket_ + 1 == socket_locks_.size()) {
119 socket_locks_.pop_back();
120 while (!socket_locks_.empty() && !socket_locks_.back().control_socket_) {
121 socket_locks_.pop_back();
122 }
123 }
124 else {
125 socket_locks_[lock.socket_].control_socket_ = nullptr;
126 }
127 }
128 }
129 else {
130 sli.locks_[lock.lock_].waiting = false;
131 sli.locks_[lock.lock_].released = true;
132 }
133
134 lock.mgr_ = nullptr;
135
136 if (!was_waiting) {
137 Wakeup();
138 }
139 }
140
Wakeup()141 void OpLockManager::Wakeup()
142 {
143 for (auto & sli : socket_locks_) {
144 for (auto & lock : sli.locks_) {
145 if (lock.waiting) {
146 sli.control_socket_->send_event<CObtainLockEvent>();
147 break;
148 }
149 }
150 }
151 }
152
ObtainWaiting(CControlSocket * socket)153 bool OpLockManager::ObtainWaiting(CControlSocket * socket)
154 {
155 bool obtained = false;
156
157 fz::scoped_lock l(mtx_);
158 for (auto & sli : socket_locks_) {
159 if (sli.control_socket_ == socket) {
160 for (auto & lock : sli.locks_) {
161 if (lock.waiting) {
162 obtained |= ObtainWaiting(sli, lock);
163 }
164 }
165 }
166 }
167
168 return obtained;
169 }
170
ObtainWaiting(socket_lock_info const & sli,lock_info & lock)171 bool OpLockManager::ObtainWaiting(socket_lock_info const& sli, lock_info& lock)
172 {
173 for (auto const& other_sli : socket_locks_) {
174 if (&other_sli == &sli) {
175 continue;
176 }
177
178 for (auto const& other_lock : other_sli.locks_) {
179 if (lock.reason != other_lock.reason || other_lock.waiting || other_lock.released) {
180 continue;
181 }
182 if (other_lock.path == lock.path || (other_lock.inclusive && other_lock.path.IsParentOf(lock.path, false))) {
183 return false;
184 }
185 if (lock.inclusive && lock.path.IsParentOf(other_lock.path, false)) {
186 return false;
187 }
188 }
189 }
190
191 lock.waiting = false;
192 return true;
193 }
194
get_or_create(CControlSocket * socket)195 size_t OpLockManager::get_or_create(CControlSocket * socket)
196 {
197 for (size_t i = 0; i < socket_locks_.size(); ++i) {
198 if (socket_locks_[i].control_socket_ == socket) {
199 return i;
200 }
201 }
202
203 socket_lock_info info;
204 info.control_socket_ = socket;
205 info.server_ = socket->GetCurrentServer();
206 socket_locks_.push_back(info);
207
208 return socket_locks_.size() - 1;
209 }
210
Waiting(OpLock const & lock) const211 bool OpLockManager::Waiting(OpLock const& lock) const
212 {
213 fz::scoped_lock l(mtx_);
214 assert(lock.socket_ < socket_locks_.size());
215 assert(lock.lock_ < socket_locks_[lock.socket_].locks_.size());
216
217 auto & sli = socket_locks_[lock.socket_];
218 return sli.locks_[lock.lock_].waiting;
219 }
220
Waiting(CControlSocket * socket) const221 bool OpLockManager::Waiting(CControlSocket * socket) const
222 {
223 fz::scoped_lock l(mtx_);
224 for (auto const& sli : socket_locks_) {
225 if (sli.control_socket_ == socket) {
226 for (auto const& lock : sli.locks_) {
227 if (lock.waiting) {
228 return true;
229 }
230 }
231 }
232 }
233
234 return false;
235 }
236