1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "event_impl.h"
17 #include "db_errno.h"
18 #include "log_print.h"
19 #include "event_loop_impl.h"
20
21 namespace DistributedDB {
EventImpl(EventTime timeout)22 EventImpl::EventImpl(EventTime timeout)
23 : events_(ET_TIMEOUT),
24 revents_(0),
25 timeout_(timeout),
26 start_(0),
27 loop_(nullptr),
28 ignoreFinalizer_(false)
29 {
30 if (timeout_ < 0) {
31 timeout_ = MAX_TIME_VALUE;
32 }
33
34 OnKill([this]() {
35 UnlockObj();
36 (void)Detach(false);
37 LockObj();
38 });
39
40 OnLastRef([this]() {
41 if (finalizer_ && !ignoreFinalizer_) {
42 finalizer_();
43 }
44 });
45 }
46
EventImpl(const EventFd & fd,EventsMask events,EventTime timeout)47 EventImpl::EventImpl(const EventFd &fd, EventsMask events, EventTime timeout)
48 : fd_(fd),
49 events_(events),
50 revents_(0),
51 timeout_(timeout),
52 start_(0),
53 loop_(nullptr),
54 ignoreFinalizer_(false)
55 {
56 if (!(events & ET_TIMEOUT) || (timeout_ < 0)) {
57 timeout_ = MAX_TIME_VALUE;
58 }
59 if (!fd_.IsValid()) {
60 events_ &= ~(ET_READ | ET_WRITE | ET_ERROR);
61 }
62
63 OnKill([this]() {
64 UnlockObj();
65 (void)Detach(false);
66 LockObj();
67 });
68
69 OnLastRef([this]() {
70 if (finalizer_ && !ignoreFinalizer_) {
71 finalizer_();
72 }
73 });
74 }
75
~EventImpl()76 EventImpl::~EventImpl()
77 {
78 if (loop_ != nullptr) {
79 loop_->DecObjRef(loop_);
80 loop_ = nullptr;
81 }
82 if (fd_.IsValid()) {
83 fd_.Close();
84 }
85 }
86
SetAction(const EventAction & action,const EventFinalizer & finalizer)87 int EventImpl::SetAction(const EventAction &action, const EventFinalizer &finalizer)
88 {
89 if (!action || action_) {
90 return -E_INVALID_ARGS;
91 }
92 if (IsKilled()) {
93 return -E_OBJ_IS_KILLED;
94 }
95
96 action_ = action;
97 finalizer_ = finalizer;
98 return E_OK;
99 }
100
AddEvents(EventsMask events)101 int EventImpl::AddEvents(EventsMask events)
102 {
103 if (!IsValidArg(events)) {
104 return -E_INVALID_ARGS;
105 }
106
107 EventsMask genericEvents = ET_READ | ET_WRITE | ET_ERROR;
108 if ((genericEvents & events) && !IsValidFd()) {
109 LOGE("ev add events failed, fd is invalid.");
110 return -E_INVALID_ARGS;
111 }
112
113 EventLoopImpl *loop = nullptr;
114 {
115 RefObject::AutoLock lockGuard(this);
116 if (loop_ == nullptr) {
117 events_ |= events;
118 return E_OK;
119 }
120 loop = loop_;
121 loop->IncObjRef(loop);
122 }
123
124 int errCode = loop->Modify(this, true, events);
125 loop->DecObjRef(loop);
126 if (errCode != E_OK) {
127 LOGE("ev add events failed, err: '%d'.", errCode);
128 }
129 return errCode;
130 }
131
RemoveEvents(EventsMask events)132 int EventImpl::RemoveEvents(EventsMask events)
133 {
134 if (!IsValidArg(events)) {
135 return -E_INVALID_ARGS;
136 }
137
138 EventsMask genericEvents = ET_READ | ET_WRITE | ET_ERROR;
139 if ((genericEvents & events) && !IsValidFd()) {
140 LOGE("ev remove events failed, fd is invalid.");
141 return -E_INVALID_ARGS;
142 }
143
144 EventLoopImpl *loop = nullptr;
145 {
146 RefObject::AutoLock lockGuard(this);
147 if (loop_ == nullptr) {
148 events_ &= ~events;
149 return E_OK;
150 }
151 loop = loop_;
152 loop->IncObjRef(loop);
153 }
154
155 int errCode = loop->Modify(this, false, events);
156 loop->DecObjRef(loop);
157 if (errCode != E_OK) {
158 LOGE("ev remove events failed, err: '%d'.", errCode);
159 }
160 return errCode;
161 }
162
SetTimeout(EventTime timeout)163 int EventImpl::SetTimeout(EventTime timeout)
164 {
165 if (!IsValidArg(timeout)) {
166 return -E_INVALID_ARGS;
167 }
168
169 EventLoopImpl *loop = nullptr;
170 {
171 RefObject::AutoLock lockGuard(this);
172 if (loop_ == nullptr) {
173 timeout_ = timeout;
174 return E_OK;
175 }
176 loop = loop_;
177 loop->IncObjRef(loop);
178 }
179
180 int errCode = loop->Modify(this, timeout);
181 loop->DecObjRef(loop);
182 if (errCode != E_OK) {
183 LOGE("ev set timeout failed, err: '%d'.", errCode);
184 }
185 return errCode;
186 }
187
Detach(bool wait)188 int EventImpl::Detach(bool wait)
189 {
190 EventLoopImpl *loop = nullptr;
191 {
192 RefObject::AutoLock lockGuard(this);
193 if (loop_ == nullptr) {
194 return E_OK;
195 }
196 loop = loop_;
197 loop->IncObjRef(loop);
198 }
199
200 int errCode = loop->Remove(this);
201 if (errCode == -E_OBJ_IS_KILLED) {
202 errCode = E_OK;
203 }
204
205 if ((errCode == E_OK) && wait) {
206 bool started = true;
207 if (!loop->IsInLoopThread(started)) {
208 Wait();
209 }
210 loop->DecObjRef(loop);
211 return E_OK;
212 }
213
214 loop->DecObjRef(loop);
215 return errCode;
216 }
217
IgnoreFinalizer()218 void EventImpl::IgnoreFinalizer()
219 {
220 ignoreFinalizer_ = true;
221 }
222
CheckStatus() const223 int EventImpl::CheckStatus() const
224 {
225 RefObject::AutoLock lockGuard(this);
226 if (IsKilled()) {
227 return -E_OBJ_IS_KILLED;
228 }
229 if (!action_) {
230 return -E_INVALID_ARGS;
231 }
232 return E_OK;
233 }
234
IsTimer() const235 bool EventImpl::IsTimer() const
236 {
237 return !IsValidFd();
238 }
239
IsValidFd() const240 bool EventImpl::IsValidFd() const
241 {
242 return fd_.IsValid();
243 }
244
GetEventFd() const245 EventFd EventImpl::GetEventFd() const
246 {
247 return fd_;
248 }
249
GetEvents() const250 EventsMask EventImpl::GetEvents() const
251 {
252 return events_;
253 }
254
SetLoop(EventLoopImpl * loop)255 bool EventImpl::SetLoop(EventLoopImpl *loop)
256 {
257 RefObject::AutoLock lockGuard(this);
258 if (loop == nullptr) {
259 if (loop_ != nullptr) {
260 loop_->DecObjRef(loop_);
261 loop_ = nullptr;
262 }
263 detached_.notify_one();
264 return true;
265 }
266 if (loop_ == nullptr) {
267 loop->IncObjRef(loop);
268 loop_ = loop;
269 return true;
270 }
271 return false;
272 }
273
Wait()274 void EventImpl::Wait()
275 {
276 RefObject::AutoLock lockGuard(this);
277 WaitLockedUntil(detached_, [this]()->bool { return loop_ == nullptr; });
278 }
279
Attached(const EventLoopImpl * loop,bool & isLoopConfused) const280 bool EventImpl::Attached(const EventLoopImpl *loop, bool &isLoopConfused) const
281 {
282 RefObject::AutoLock lockGuard(this);
283 if (loop_ != nullptr && loop != nullptr && loop_ != loop) {
284 // the event object is attached to another loop.
285 isLoopConfused = true;
286 } else {
287 isLoopConfused = false;
288 }
289 // returns true when both are nullptr.
290 return loop_ == loop;
291 }
292
SetEvents(bool isAdd,EventsMask events)293 void EventImpl::SetEvents(bool isAdd, EventsMask events)
294 {
295 if (isAdd) {
296 events_ |= events;
297 } else {
298 events_ &= ~events;
299 }
300 }
301
SetRevents(EventsMask events)302 void EventImpl::SetRevents(EventsMask events)
303 {
304 EventsMask genericEvents = ET_READ | ET_WRITE | ET_ERROR;
305 EventsMask revents = events & genericEvents;
306 if (revents) {
307 revents_ = revents;
308 } else {
309 revents_ = events & ET_TIMEOUT;
310 }
311 }
312
SetTimeoutPeriod(EventTime timeout)313 void EventImpl::SetTimeoutPeriod(EventTime timeout)
314 {
315 if (timeout < 0) {
316 timeout_ = MAX_TIME_VALUE;
317 } else {
318 timeout_ = timeout;
319 }
320 }
321
SetStartTime(EventTime startTime)322 void EventImpl::SetStartTime(EventTime startTime)
323 {
324 start_ = startTime;
325 }
326
GetTimeoutPoint(EventTime & timePoint) const327 bool EventImpl::GetTimeoutPoint(EventTime &timePoint) const
328 {
329 if (events_ & ET_TIMEOUT) {
330 timePoint = start_ + timeout_;
331 return true;
332 }
333 timePoint = MAX_TIME_VALUE;
334 return false;
335 }
336
UpdateElapsedTime(EventTime now)337 void EventImpl::UpdateElapsedTime(EventTime now)
338 {
339 if (events_ & ET_TIMEOUT) {
340 EventTime timePoint = start_ + timeout_;
341 if ((now >= timePoint) || (now < start_)) {
342 start_ = now;
343 if (!revents_) {
344 revents_ = ET_TIMEOUT;
345 }
346 }
347 }
348 }
349
Dispatch()350 int EventImpl::Dispatch()
351 {
352 if (!action_) {
353 return -E_INVALID_ARGS;
354 }
355
356 int errCode = E_OK;
357 if (!IsKilled()) {
358 if (revents_) {
359 errCode = action_(revents_);
360 }
361 }
362 return errCode;
363 }
364
IsValidArg(EventsMask events) const365 bool EventImpl::IsValidArg(EventsMask events) const
366 {
367 EventsMask allEvents = ET_READ | ET_WRITE | ET_ERROR | ET_TIMEOUT;
368 return ((events != 0) && ((events & (~allEvents)) == 0));
369 }
370
IsValidArg(EventTime timeout) const371 bool EventImpl::IsValidArg(EventTime timeout) const
372 {
373 return (timeout >= 0) && (timeout <= MAX_TIME_VALUE);
374 }
375
376 DEFINE_OBJECT_TAG_FACILITIES(EventImpl)
377 } // namespace DistributedDB
378