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