• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 <gtest/gtest.h>
17 #include <sys/types.h>
18 #include <sys/timerfd.h>
19 #include <sys/prctl.h>
20 #include "unistd.h"
21 #include <cstdint>
22 #include <cstring>
23 #include <string>
24 #include <thread>
25 #include <mutex>
26 #include <memory>
27 #include <atomic>
28 #include <algorithm>
29 #include <list>
30 #include <map>
31 #include <functional>
32 #include <iostream>
33 #include "common_timer_errors.h"
34 #include "common_event_sys_errors.h"
35 #include "io_event_handler.h"
36 #include "io_event_reactor.h"
37 
38 using namespace testing::ext;
39 using namespace OHOS::Utils;
40 
41 namespace OHOS {
42 namespace {
43 
44 class UtilsEventTest : public testing::Test {
45 public:
SetUpTestCase(void)46     static void SetUpTestCase(void) {}
TearDownTestCase(void)47     static void TearDownTestCase(void) {}
SetUp()48     void SetUp() {}
TearDown()49     void TearDown() {}
50 };
51 
52 int g_data = 0;
TimerCallback1()53 void TimerCallback1()
54 {
55     std::cout << "timer callback1 invoked." << std::endl;
56     g_data++;
57 }
58 
59 static const int MILLI_TO_BASE = 1000;
60 static const int NANO_TO_BASE = 1000000000;
61 static constexpr int MILLI_TO_NANO = NANO_TO_BASE / MILLI_TO_BASE;
62 class TimerFdHandler : public IOEventHandler {
63 public:
64     using TimerEventCallback = std::function<void()>;
65     TimerFdHandler(int fd, const TimerEventCallback& cb);
~TimerFdHandler()66     ~TimerFdHandler() {}
67     bool Initialize(uint32_t interval);
68     void Uninitialize();
69     void TimeOut();
70 
71 private:
72     TimerEventCallback timerCallback_;
73 };
74 
TestCallback()75 void TestCallback() {}
76 
77 /*
78  * @tc.name: testIOEventHandler001
79  * @tc.desc: test basic interfaces of IOEventHandler.
80  */
81 HWTEST_F(UtilsEventTest, testIOEventHandler001, TestSize.Level0)
82 {
83     g_data = 0;
84     // 1. Create io event handler
85     std::shared_ptr<IOEventHandler> handler = std::make_shared<IOEventHandler>(-1);
86 
87     // 2. Set fd
88     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
89     ASSERT_NE(fd, -1);
90     handler->SetFd(fd);
91     EXPECT_EQ(handler->GetFd(), fd);
92 
93     // 3. Set callback
94     handler->SetCallback(&TestCallback);
95     EXPECT_NE(handler->GetCallback(), nullptr);
96 
97     // 4. Set interest events
98     handler->SetEvents(Events::EVENT_READ | Events::EVENT_WRITE);
99     EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ | Events::EVENT_WRITE);
100 
101     // 5. Check status
102     EXPECT_EQ(handler->Prev(), nullptr);
103     EXPECT_EQ(handler->Next(), nullptr);
104     EXPECT_EQ(handler->IsActive(), false);
105 
106     // 6. disable events
107     handler->DisableAll();
108     EXPECT_EQ(handler->GetEvents(), Events::EVENT_NONE);
109 
110     // 7. enable events
111     handler->EnableRead();
112     handler->EnableWrite();
113     EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ | Events::EVENT_WRITE);
114 
115     // 8. disable one of the events
116     handler->DisableWrite();
117     EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ);
118 }
119 
120 /*
121  * @tc.name: testIOEventHandler002
122  * @tc.desc: test reactor-related interfaces of IOEventHandler.
123  */
124 HWTEST_F(UtilsEventTest, testIOEventHandler002, TestSize.Level0)
125 {
126     g_data = 0;
127     // 1. Create io event handler
128     std::shared_ptr<IOEventHandler> handler = std::make_shared<IOEventHandler>(-1);
129 
130     // 2. Set fd
131     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
132     ASSERT_NE(fd, -1);
133     handler->SetFd(fd);
134     EXPECT_EQ(handler->GetFd(), fd);
135 
136     // 3. Set callback
137     handler->SetCallback(&TestCallback);
138     EXPECT_NE(handler->GetCallback(), nullptr);
139 
140     // 4. Set interest events
141     handler->EnableRead();
142     EXPECT_EQ(handler->GetEvents(), Events::EVENT_READ);
143 
144     // 5. Create a reactor but not run
145     std::shared_ptr<IOEventReactor> reactor = std::make_shared<IOEventReactor>();
146     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
147 
148     // 6. Start handler
149     handler->Start(reactor.get());
150     EXPECT_EQ(reactor->FindHandler(handler.get()), EVENT_SYS_ERR_OK);
151 
152     // 7. Change setting and update handler to the reactor
153     handler->EnableWrite();
154     EXPECT_TRUE(handler->Update(reactor.get()));
155 
156     // 8. Remove the handler
157     handler->Stop(reactor.get());
158     EXPECT_EQ(reactor->FindHandler(handler.get()), EVENT_SYS_ERR_NOT_FOUND);
159 
160     // 9. Add handler, then delete handler. handler will remove itself from the reactor during deconstruction.
161     ASSERT_TRUE(handler->Start(reactor.get()));
162     handler.reset();
163 }
164 
165 /*
166  * @tc.name: testIOEventReactor001
167  * @tc.desc: test basic interfaces of IOEventReactor.
168  */
169 HWTEST_F(UtilsEventTest, testIOEventReactor001, TestSize.Level0)
170 {
171     g_data = 0;
172     // Get fd
173     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
174     ASSERT_NE(fd, -1);
175 
176     // 1. Create io event handlers
177     std::shared_ptr<IOEventHandler> handler1 = std::make_shared<IOEventHandler>(fd);
178     std::shared_ptr<IOEventHandler> handler2 = std::make_shared<IOEventHandler>(fd);
179     std::shared_ptr<IOEventHandler> handler3 = std::make_shared<IOEventHandler>(-1); // -1: invalid fd
180     std::shared_ptr<IOEventHandler> handler4 = std::make_shared<IOEventHandler>(fd);
181 
182     // 2. Create a reactor but not run
183     std::shared_ptr<IOEventReactor> reactor = std::make_shared<IOEventReactor>();
184     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
185 
186     // 3. Add handler
187     EXPECT_EQ(reactor->AddHandler(handler1.get()), EVENT_SYS_ERR_OK);
188     EXPECT_EQ(reactor->AddHandler(handler2.get()), EVENT_SYS_ERR_OK);
189     EXPECT_NE(reactor->AddHandler(handler3.get()), EVENT_SYS_ERR_OK);
190     EXPECT_NE(reactor->AddHandler(nullptr), EVENT_SYS_ERR_OK);
191 
192     // 4. Add handler from the handler side.
193     EXPECT_NE(handler1->Start(reactor.get()), EVENT_SYS_ERR_OK); // already started.
194     EXPECT_NE(handler3->Start(reactor.get()), EVENT_SYS_ERR_OK); // Bad fd.
195 
196     // 5. Remove handler
197     EXPECT_NE(reactor->RemoveHandler(nullptr), EVENT_SYS_ERR_OK);
198     EXPECT_NE(reactor->RemoveHandler(handler3.get()), EVENT_SYS_ERR_OK); // Bad fd.
199     EXPECT_NE(reactor->RemoveHandler(handler4.get()), EVENT_SYS_ERR_OK);
200     EXPECT_EQ(reactor->RemoveHandler(handler2.get()), EVENT_SYS_ERR_OK);
201 
202     // 6. Remove handler from the handler side.
203     EXPECT_NE(handler2->Stop(reactor.get()), EVENT_SYS_ERR_OK); // Not found.
204 
205     // 7. Update handler
206     EXPECT_NE(reactor->UpdateHandler(nullptr), EVENT_SYS_ERR_OK);
207     EXPECT_NE(reactor->UpdateHandler(handler3.get()), EVENT_SYS_ERR_OK);
208     EXPECT_EQ(reactor->UpdateHandler(handler1.get()), EVENT_SYS_ERR_OK);
209     EXPECT_EQ(reactor->UpdateHandler(handler4.get()), EVENT_SYS_ERR_OK);
210 
211     // 8. Update handler from the handler side.
212     EXPECT_NE(handler2->Update(reactor.get()), EVENT_SYS_ERR_OK); // Not found.
213     EXPECT_NE(handler3->Update(reactor.get()), EVENT_SYS_ERR_OK); // Bad fd.
214 
215     // 9. Find handler
216     EXPECT_NE(reactor->FindHandler(nullptr), EVENT_SYS_ERR_OK);
217     EXPECT_NE(reactor->FindHandler(handler3.get()), EVENT_SYS_ERR_OK);
218 
219     // 10. Clean handler
220     EXPECT_NE(reactor->Clean(-1), EVENT_SYS_ERR_OK);
221     EXPECT_EQ(reactor->Clean(fd), EVENT_SYS_ERR_OK);
222 }
223 
224 /*
225  * @tc.name: testIOEventReactor002
226  * @tc.desc: test change event but not update.
227  */
228 HWTEST_F(UtilsEventTest, testIOEventReactor002, TestSize.Level0)
229 {
230     g_data = 0;
231     // 1. Open timer
232     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
233     ASSERT_NE(fd, -1);
234 
235     // 2. Create io event handlers
236     std::shared_ptr<IOEventHandler> handler1 = std::make_shared<IOEventHandler>(fd);
237     std::shared_ptr<IOEventHandler> handler2 = std::make_shared<IOEventHandler>(fd);
238 
239     // 3. Create a reactor but not run
240     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
241     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
242 
243     // 4. Add handler
244     EXPECT_EQ(reactor->AddHandler(handler1.get()), EVENT_SYS_ERR_OK);
245     EXPECT_EQ(reactor->AddHandler(handler2.get()), EVENT_SYS_ERR_OK);
246 
247     // 5. release one handler
248     handler2.reset(); // will be removed from the inner list.
249 }
250 
TimerFdHandler(int fd,const TimerEventCallback & cb)251 TimerFdHandler::TimerFdHandler(int fd, const TimerEventCallback& cb)
252     : IOEventHandler(fd),  timerCallback_(cb) {}
253 
Initialize(uint32_t interval)254 bool TimerFdHandler::Initialize(uint32_t interval)
255 {
256     if ((GetFd() == -1)) {
257         return false;
258     }
259 
260     struct itimerspec newValue = {{0, 0}, {0, 0}};
261     timespec now{0, 0};
262     if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
263         return false;
264     }
265 
266     // next time out time is now + interval
267     newValue.it_value.tv_sec = now.tv_sec + interval / MILLI_TO_BASE;
268     newValue.it_value.tv_nsec = now.tv_nsec + (interval % MILLI_TO_BASE) * MILLI_TO_NANO;
269     if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
270         newValue.it_value.tv_sec += 1;
271         newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
272     }
273 
274     // interval
275     newValue.it_interval.tv_sec  = interval / MILLI_TO_BASE;
276     newValue.it_interval.tv_nsec = (interval % MILLI_TO_BASE) * MILLI_TO_NANO;
277 
278     if (timerfd_settime(GetFd(), TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
279         std::cout << "Set timerFd failed-" << strerror(errno) << "timer_fd:" << GetFd() << ", next_time:" <<
280                   newValue.it_value.tv_sec << ", interval:" << newValue.it_interval.tv_sec << std::endl;
281         return false;
282     }
283 
284     EnableRead();
285     SetCallback(std::bind(&TimerFdHandler::TimeOut, this));
286 
287     return true;
288 }
289 
Uninitialize()290 void TimerFdHandler::Uninitialize()
291 {
292     DisableAll();
293 }
294 
TimeOut()295 void TimerFdHandler::TimeOut()
296 {
297     if (GetFd() == -1) {
298         std::cout << "Invalid timer_fd." << std::endl;
299         return;
300     }
301     uint64_t expirations = 0;
302     ssize_t n = ::read(GetFd(), &expirations, sizeof(expirations));
303     if (n != sizeof(expirations)) {
304         std::cout << "reads " << static_cast<int>(n) << "bytes instead of 8." << std::endl;
305     }
306 
307     if (timerCallback_) {
308         timerCallback_();
309     }
310 }
311 
312 /*
313  * @tc.name: testEvent001
314  * @tc.desc: test handling event of timerfd.
315  */
316 HWTEST_F(UtilsEventTest, testEvent001, TestSize.Level0)
317 {
318     g_data = 0;
319     // 1. Open timer
320     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
321     ASSERT_NE(fd, -1);
322     // 2. Create timer event handler
323     std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
324 
325     // 3. Create reactor for event loop
326     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
327     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
328     reactor->EnableHandling();
329 
330     // 4. Initialize timer handler and add it to reactor
331     ASSERT_TRUE(handler->Initialize(10));
332     ASSERT_TRUE(handler->Start(reactor.get()));
333 
334     // 5. Run event loop
__anon78a5747a0202null335     std::thread loopThread([&reactor]{
336         reactor->Run(-1);
337     });
338 
339     // 6. Wait for event handling
340     std::this_thread::sleep_for(std::chrono::milliseconds(16));
341 
342     // 7. Check result, execute once at least
343     EXPECT_GE(g_data, 1);
344 
345     // 8. terminate the event-loop (aka Run())
346     reactor->Terminate();
347     loopThread.join();
348 }
349 
350 /*
351  * @tc.name: testEvent002
352  * @tc.desc: test changing event to EVENT_NONE.
353  */
354 HWTEST_F(UtilsEventTest, testEvent002, TestSize.Level0)
355 {
356     g_data = 0;
357     // 1. Open timer
358     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
359     ASSERT_NE(fd, -1);
360     // 2. Create timer event handler
361     std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
362 
363     // 3. Create reactor for event loop
364     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
365     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
366 
367     // 4. Initialize timer handler and add it to reactor
368     ASSERT_TRUE(handler->Initialize(10));
369     ASSERT_TRUE(handler->Start(reactor.get()));
370 
371     // 5. Run event loop
__anon78a5747a0302null372     std::thread loopThread([&reactor]{
373         reactor->Run(-1);
374     });
375 
376     // 6. Change settings
377     reactor->DisableHandling();
378     std::this_thread::sleep_for(std::chrono::milliseconds(1));
379     reactor->EnableHandling();
380     handler->SetEvents(Events::EVENT_NONE);
381 
382     // 7. Wait for event handling
383     std::this_thread::sleep_for(std::chrono::milliseconds(16));
384 
385     // 8. Check result, no execution
386     EXPECT_EQ(g_data, 0);
387 
388     // 9. terminate the event-loop (aka Run())
389     reactor->Terminate();
390     loopThread.join();
391 }
392 
393 /*
394  * @tc.name: testEvent003
395  * @tc.desc: test disable single event.
396  */
397 HWTEST_F(UtilsEventTest, testEvent003, TestSize.Level0)
398 {
399     g_data = 0;
400     // 1. Open timer
401     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
402     ASSERT_NE(fd, -1);
403     // 2. Create timer event handler
404     std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
405 
406     // 3. Create reactor for event loop
407     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
408     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
409 
410     // 4. Initialize timer handler and add it to reactor
411     ASSERT_TRUE(handler->Initialize(10));
412     ASSERT_TRUE(handler->Start(reactor.get()));
413 
414     // 5. Run event loop
__anon78a5747a0402null415     std::thread loopThread([&reactor]{
416         reactor->Run(-1);
417     });
418 
419     // 6. Change settings
420     reactor->EnableHandling();
421     ASSERT_TRUE(handler->Stop(reactor.get())); // block to get lock, so no need to wait.
422 
423     // 7. Check result, no execution
424     EXPECT_EQ(g_data, 0);
425 
426     // 8. terminate the event-loop (aka Run())
427     reactor->Terminate();
428     loopThread.join();
429 }
430 
431 /*
432  * @tc.name: testEvent004
433  * @tc.desc: test removing callback.
434  */
435 HWTEST_F(UtilsEventTest, testEvent004, TestSize.Level0)
436 {
437     g_data = 0;
438     // 1. Open timer
439     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
440     ASSERT_NE(fd, -1);
441     // 2. Create timer event handler
442     std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
443 
444     // 3. Create reactor for event loop
445     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
446     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
447 
448     // 4. Initialize timer handler and add it to reactor
449     ASSERT_TRUE(handler->Initialize(10));
450     ASSERT_TRUE(handler->Start(reactor.get()));
451 
452     // 5. Run event loop
__anon78a5747a0502null453     std::thread loopThread([&reactor]{
454         reactor->Run(-1);
455     });
456 
457     // 6. Change settings
458     reactor->EnableHandling();
459     handler->SetCallback(nullptr);
460 
461     // 7. Wait for event handling
462     std::this_thread::sleep_for(std::chrono::milliseconds(16));
463 
464     // 8. Check result, no execution
465     EXPECT_EQ(g_data, 0);
466 
467     // 9. terminate the event-loop (aka Run())
468     reactor->Terminate();
469     loopThread.join();
470 }
471 
472 /*
473  * @tc.name: testEvent005
474  * @tc.desc: test change event but not update.
475  */
476 HWTEST_F(UtilsEventTest, testEvent005, TestSize.Level0)
477 {
478     g_data = 0;
479     // 1. Open timer
480     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
481     ASSERT_NE(fd, -1);
482     // 2. Create timer event handler
483     std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
484 
485     // 3. Create reactor for event loop
486     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
487     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
488 
489     // 4. Initialize timer handler and add it to reactor
490     ASSERT_TRUE(handler->Initialize(15));
491     ASSERT_TRUE(handler->Start(reactor.get()));
492 
493     // 5. Run event loop
__anon78a5747a0602null494     std::thread loopThread([&reactor]{
495         reactor->Run(-1);
496     });
497 
498     // 6. Change settings but not update
499     handler->SetEvents(Events::EVENT_WRITE);
500     reactor->EnableHandling();
501 
502     // 7. Wait for event handling
503     std::this_thread::sleep_for(std::chrono::milliseconds(16));
504 
505     // 8. Check result, no execution
506     EXPECT_EQ(g_data, 0);
507 
508     // 9. terminate the event-loop (aka Run())
509     reactor->Terminate();
510     loopThread.join();
511 }
512 
513 /*
514  * @tc.name: testEvent006
515  * @tc.desc: test release the handler when started.
516  */
517 HWTEST_F(UtilsEventTest, testEvent006, TestSize.Level0)
518 {
519     g_data = 0;
520     // 1. Open timer
521     int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
522     ASSERT_NE(fd, -1);
523     // 2. Create timer event handler
524     std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
525 
526     // 3. Create reactor for event loop
527     std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
528     ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
529 
530     // 4. Initialize timer handler and add it to reactor
531     ASSERT_TRUE(handler->Initialize(15));
532     ASSERT_TRUE(handler->Start(reactor.get()));
533 
534     // 5. Run event loop
__anon78a5747a0702null535     std::thread loopThread([&reactor]{
536         reactor->Run(-1);
537     });
538 
539     // 6. release eventhandler
540     handler.reset();
541     reactor->EnableHandling();
542 
543     // 7. Wait for event handling
544     std::this_thread::sleep_for(std::chrono::milliseconds(16));
545 
546     // 8. Check result, no execution
547     EXPECT_EQ(g_data, 0);
548 
549     // 9. terminate the event-loop (aka Run())
550     reactor->Terminate();
551     loopThread.join();
552 }
553 
554 // Try to substitue underlying implementation of OHOS::UTILS::TIMER
555 class TimerEventHandler {
556 public:
557     using TimerEventCallback = std::function<void(TimerEventHandler*)>;
558     TimerEventHandler(int timerFd, uint32_t timeout, bool once);
559     TimerEventHandler(uint32_t timeout /* ms */, bool once);
560     ~TimerEventHandler();
561 
562     TimerEventHandler(const TimerEventHandler&) = delete;
563     TimerEventHandler& operator=(const TimerEventHandler&) = delete;
564     TimerEventHandler(const TimerEventHandler&&) = delete;
565     TimerEventHandler& operator=(const TimerEventHandler&&) = delete;
566 
567     ErrCode Initialize();
568     void Uninitialize();
569 
570     bool Start(IOEventReactor* reactor);
571     bool Stop(IOEventReactor* reactor);
572 
SetTimerEventCallback(const TimerEventCallback & callback)573     inline void SetTimerEventCallback(const TimerEventCallback& callback) { timerEventCallback_ = callback; }
574 
SetTimerId(const uint32_t & id)575     inline void SetTimerId(const uint32_t& id) { timerId_ = id; }
576 
GetInterval() const577     inline uint32_t GetInterval() const { return interval_; }
GetTimerId() const578     inline uint32_t GetTimerId() const { return timerId_; }
GetTimerFd() const579     inline int GetTimerFd() const { return handler_->GetFd(); }
580 
581 private:
582     void TimeOut();
583 
584 private:
585     bool           once_;
586     uint32_t       timerId_;
587     uint32_t       interval_;
588     TimerEventCallback  timerEventCallback_;
589 
590     std::unique_ptr<IOEventHandler> handler_;
591 
592     friend class Timer;
593 };
594 
595 class Timer {
596 public:
597     using TimerCallback = std::function<void ()>;
598     using TimerCallbackPtr = std::shared_ptr<TimerCallback>;
599     using TimerEventCallback = TimerEventHandler::TimerEventCallback;
600 
601     explicit Timer(const std::string& name, int timeoutMs = 1000);
~Timer()602     virtual ~Timer() {}
603     virtual uint32_t Setup();
604     virtual void Shutdown(bool useJoin = true);
605     uint32_t Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once = false);
606     void Unregister(uint32_t timerId);
607 
608 private:
609     void MainLoop();
610     void OnTimer(TimerEventHandler* handler, const TimerCallback& callback);
611     uint32_t GetValidId() const;
612     int GetTimerFd(uint32_t interval /* ms */);
613     void EraseUnusedTimerId(uint32_t interval, const std::vector<uint32_t>& unusedIds);
614 
615 private:
616     using TimerHandlerPtr = std::shared_ptr<TimerEventHandler>;
617     using TimerHandlerList = std::list<TimerHandlerPtr>;
618 
619     ErrCode ScheduleTimer(const TimerEventCallback& callback, uint32_t interval, uint32_t timerId, int& timerFd,
620                           bool once);
621     ErrCode CancelTimer(TimerHandlerPtr target);
622 
623     std::map<uint32_t, TimerHandlerPtr> timerHandlers_;
624     std::map<uint32_t, TimerHandlerList> intervalToTimers_;
625 
626     std::string name_;
627     int timeoutMs_;
628     std::thread thread_;
629     std::unique_ptr<IOEventReactor> reactor_;
630     std::mutex mutex_;
631 };
632 
Timer(const std::string & name,int timeoutMs)633 Timer::Timer(const std::string& name, int timeoutMs) : name_(name), timeoutMs_(timeoutMs),
634     reactor_(new IOEventReactor()) {}
635 
MainLoop()636 void Timer::MainLoop()
637 {
638     prctl(PR_SET_NAME, name_.c_str(), 0, 0, 0);
639 
640     reactor_->Run(timeoutMs_);
641     std::cout << "||" << gettid() << "||" << "Loop finished" << std::endl;
642 
643     if (reactor_->CleanUp() != EVENT_SYS_ERR_OK) {
644         std::cout << "||" << gettid() << "||" <<
645                   "Reactor Clean Failed. It will clean during deconstruction" << std::endl;
646     }
647 }
648 
Setup()649 uint32_t Timer::Setup()
650 {
651     if (thread_.joinable()) { // avoid double assign to an active thread
652         return TIMER_ERR_INVALID_VALUE;
653     }
654 
655     if (reactor_->SetUp() != EVENT_SYS_ERR_OK) {
656         std::cout << "||" << gettid() << "||" << "Setup reactor failed." << std::endl;
657         return TIMER_ERR_DEAL_FAILED;
658     }
659 
660     reactor_->EnableHandling();
661 
662     std::thread loopThread(std::bind(&Timer::MainLoop, this));
663     thread_.swap(loopThread);
664 
665     return TIMER_ERR_OK;
666 }
667 
Shutdown(bool useJoin)668 void Timer::Shutdown(bool useJoin)
669 {
670     if (!thread_.joinable()) {
671         std::cout << "||" << gettid() << "||" << "Invalid operation. Already shutdown." << std::endl;
672         return;
673     }
674 
675     std::cout << "||" << gettid() << "||" << "Stop reactor." << std::endl;
676     reactor_->Terminate();
677 
678     if (!useJoin) {
679         thread_.detach();
680         return;
681     }
682     thread_.join();
683 }
684 
ScheduleTimer(const TimerEventCallback & callback,uint32_t interval,uint32_t timerId,int & timerFd,bool once)685 ErrCode Timer::ScheduleTimer(const TimerEventCallback& callback, uint32_t interval,
686                              uint32_t timerId, int& timerFd, bool once)
687 {
688     std::shared_ptr<TimerEventHandler> handler = std::make_shared<TimerEventHandler>(timerFd, interval, once);
689 
690     handler->SetTimerId(timerId);
691     handler->SetTimerEventCallback(callback);
692 
693     uint32_t ret = handler->Initialize();
694     if (ret != TIMER_ERR_OK) {
695         std::cout << "||" << gettid() << "||" << "Init timer handler failed." << std::endl;
696         return ret;
697     }
698     if (!handler->Start(reactor_.get())) {
699         std::cout << "||" << gettid() << "||" << "Start timer handler failed." << std::endl;
700         return TIMER_ERR_DEAL_FAILED;
701     }
702     timerHandlers_.emplace(timerId, handler); // Add to the id2handlers map
703     intervalToTimers_[interval].push_back(handler); // Add to interval2handlerlist map
704     timerFd = handler->GetTimerFd();
705     return TIMER_ERR_OK;
706 }
707 
708 
Register(const TimerCallback & callback,uint32_t interval,bool once)709 uint32_t Timer::Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once)
710 {
711     std::lock_guard<std::mutex> lock(mutex_);
712 
713     // wrap the callback in OnTiner
714     TimerEventCallback wrappedCb = std::bind(&Timer::OnTimer, this, std::placeholders::_1, callback);
715     int timerFd = once ? IO_EVENT_INVALID_FD : GetTimerFd(interval); // Get timerFd
716     uint32_t timerId = GetValidId();                        // Get timerId
717 
718     uint32_t ret = ScheduleTimer(wrappedCb, interval, timerId, timerFd, once);
719     if (ret != TIMER_ERR_OK) {
720         std::cout << "||" << gettid() << "||" << "Try schedule task failed. timer-id:" <<
721                   timerId << ", interval:" << interval << "timer-fd:" << timerFd << std::endl;
722         return TIMER_ERR_DEAL_FAILED;
723     }
724 
725     return timerId;
726 }
727 
CancelTimer(TimerHandlerPtr target)728 ErrCode Timer::CancelTimer(TimerHandlerPtr target)
729 {
730     std::cout << "||" << gettid() << "||" << "Cancle timer handler with fd:" <<  target->GetTimerFd() << std::endl;
731     target->Uninitialize();
732     if (!target->Stop(reactor_.get())) {
733         std::cout << "||" << gettid() << "||" << "Stop timer handler failed." << std::endl;
734         return TIMER_ERR_DEAL_FAILED;
735     }
736 
737     timerHandlers_.erase(target->timerId_);
738 
739     auto handlerList = intervalToTimers_[target->interval_];
740     auto itor = std::find(handlerList.begin(), handlerList.end(), target);
741     if (itor != handlerList.end()) {
742         handlerList.erase(itor);
743     }
744 
745     if (handlerList.empty()) {
746         intervalToTimers_.erase(target->interval_);
747     }
748 
749     return TIMER_ERR_OK;
750 }
751 
Unregister(uint32_t timerId)752 void Timer::Unregister(uint32_t timerId)
753 {
754     std::lock_guard<std::mutex> lock(mutex_);
755 
756     if (timerHandlers_.find(timerId) == timerHandlers_.end()) {
757         std::cout << "||" << gettid() << "||" <<
758                   "Unregister failed. timer-id:" << timerId << " not found." << std::endl;
759         return;
760     }
761 
762     auto entry = timerHandlers_[timerId];
763     std::cout << "||" << gettid() << "||" << "Try remove timer handler from reactor. timerId:" << timerId <<
764               ", interval:" << entry->interval_ << std::endl;
765 
766     if (CancelTimer(entry) != TIMER_ERR_OK) {
767         std::cout << "||" << gettid() << "||" << "Unregister timer handler failed." << std::endl;
768     }
769 }
770 
OnTimer(TimerEventHandler * handler,const TimerCallback & callback)771 void Timer::OnTimer(TimerEventHandler* handler, const TimerCallback& callback)
772 {
773     callback();
774 
775     if (handler->once_) {
776         Unregister(handler->timerId_);
777     }
778 }
779 
GetValidId() const780 uint32_t Timer::GetValidId() const
781 {
782     static std::atomic_uint32_t timerId = 1;
783 
784     while (timerHandlers_.find(timerId) != timerHandlers_.end()) {
785         timerId++;
786         if (timerId == UINT32_MAX) {
787             timerId = 1;
788         }
789 
790         if (timerId == TIMER_ERR_DEAL_FAILED) {
791             timerId++;
792         }
793     }
794 
795     return timerId;
796 }
797 
GetTimerFd(uint32_t interval)798 int Timer::GetTimerFd(uint32_t interval /* ms */)
799 {
800     if (intervalToTimers_.find(interval) == intervalToTimers_.end()) {
801         return IO_EVENT_INVALID_FD;
802     }
803     auto &handlerList = intervalToTimers_[interval];
804     for (const TimerHandlerPtr &ptr : handlerList) {
805         if (!ptr->once_) {
806             return ptr->GetTimerFd();
807         }
808     }
809     return IO_EVENT_INVALID_FD;
810 }
811 
TimerEventHandler(int timerFd,uint32_t timeout,bool once)812 TimerEventHandler::TimerEventHandler(int timerFd, uint32_t timeout /* ms */, bool once)
813     : once_(once), interval_(timeout)
814 {
815     if (timerFd == IO_EVENT_INVALID_FD) {
816         handler_ = std::make_unique<IOEventHandler>(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC));
817     } else {
818         handler_ = std::make_unique<IOEventHandler>(timerFd);
819     }
820 }
821 
~TimerEventHandler()822 TimerEventHandler::~TimerEventHandler()
823 {
824     if (close(handler_->GetFd()) != 0) {
825         std::cout << "||" << gettid() << "||" << "Close timer-fd failed. fd:" << handler_->GetFd() << ", interval:" <<
826                   interval_ << ", once:" << once_ << std::endl;
827     }
828     handler_->SetFd(IO_EVENT_INVALID_FD);
829 }
830 
Initialize()831 ErrCode TimerEventHandler::Initialize()
832 {
833     if (handler_->GetFd() == IO_EVENT_INVALID_FD) {
834         std::cout << "||" << gettid() << "||" << "Invalid timer-fd:" << handler_->GetFd() << ", interval:" <<
835                   interval_ << ", once:" << once_ << std::endl;
836         return TIMER_ERR_INVALID_VALUE;
837     }
838 
839     struct itimerspec newValue = {{0, 0}, {0, 0}};
840     timespec now{0, 0};
841     if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
842         std::cout << "||" << gettid() << "||" << "Get current time failed." << std::endl;
843         return TIMER_ERR_DEAL_FAILED;
844     }
845 
846     // next time out time is now + interval
847     newValue.it_value.tv_sec = now.tv_sec + interval_ / MILLI_TO_BASE;
848     newValue.it_value.tv_nsec = now.tv_nsec + (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
849     if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
850         newValue.it_value.tv_sec += 1;
851         newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
852     }
853 
854     if (once_) {
855         // interval, 0 means time out only once
856         newValue.it_interval.tv_sec  = 0;
857         newValue.it_interval.tv_nsec = 0;
858     } else {
859         // interval
860         newValue.it_interval.tv_sec  = interval_ / MILLI_TO_BASE;
861         newValue.it_interval.tv_nsec = (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
862     }
863 
864     if (timerfd_settime(handler_->GetFd(), TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
865         std::cout << "||" << gettid() << "||" << "Set timer-fd failed. next:" <<
866                   static_cast<long long>(newValue.it_value.tv_sec) << "interval:" <<
867                   static_cast<long long>(newValue.it_interval.tv_sec) << std::endl;
868         return TIMER_ERR_DEAL_FAILED;
869     }
870 
871     handler_->SetCallback(std::bind(&TimerEventHandler::TimeOut, this));
872     handler_->EnableRead();
873 
874     return TIMER_ERR_OK;
875 }
876 
Uninitialize()877 void TimerEventHandler::Uninitialize()
878 {
879     handler_->DisableAll();
880 }
881 
Start(IOEventReactor * reactor)882 bool TimerEventHandler::Start(IOEventReactor* reactor)
883 {
884     if (handler_ == nullptr || !handler_->Start(reactor)) {
885         return false;
886     }
887 
888     return true;
889 }
890 
Stop(IOEventReactor * reactor)891 bool TimerEventHandler::Stop(IOEventReactor* reactor)
892 {
893     if (handler_ == nullptr || !handler_->Stop(reactor)) {
894         return false;
895     }
896 
897     return true;
898 }
899 
TimeOut()900 void TimerEventHandler::TimeOut()
901 {
902     if (handler_->GetFd() == IO_EVENT_INVALID_FD) {
903         std::cout << "||" << gettid() << "||" << "Invalid timerfd." << std::endl;
904         return;
905     }
906     uint64_t expirations = 0;
907     ssize_t n = ::read(handler_->GetFd(), &expirations, sizeof(expirations));
908     if (n != sizeof(expirations)) {
909         std::cout << "||" << gettid() << "||" << "Reads " << static_cast<int>(n) <<
910                   " bytes instead of 8 from timer fd." << std::endl;
911     }
912 
913     if (timerEventCallback_) {
914         timerEventCallback_(this);
915     }
916 }
917 
CurMs()918 int64_t CurMs()
919 {
920     struct timeval tpend;
921     gettimeofday(&tpend, nullptr);
922     return (tpend.tv_sec * 1000000 + tpend.tv_usec) / 1000; // 1000000: s to us, 1000: us to ms
923 }
924 
925 std::atomic<int> g_data1(0);
TimeOutCallback1()926 void TimeOutCallback1()
927 {
928     g_data1 += 1;
929 }
930 
931 std::atomic<int> g_data2(0);
TimeOutCallback2()932 void TimeOutCallback2()
933 {
934     g_data2 += 1;
935 }
936 
937 /*
938  * @tc.name: testNewTimer001
939  * @tc.desc: test basic function of timer implemented by new event-system.
940  */
941 HWTEST_F(UtilsEventTest, testNewTimer001, TestSize.Level0)
942 {
943     g_data1 = 0;
944     Timer timer("test_timer");
945     uint32_t ret = timer.Setup();
946     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
947     timer.Register(TimeOutCallback1, 1, true);
948     std::this_thread::sleep_for(std::chrono::milliseconds(15));
949     timer.Shutdown();
950     EXPECT_EQ(1, g_data1);
951 }
952 
953 /*
954  * @tc.name: testNewTimer002
955  * @tc.desc: test basic function of timer implemented by new event-system.
956  */
957 HWTEST_F(UtilsEventTest, testNewTimer002, TestSize.Level0)
958 {
959     g_data1 = 0;
960     g_data2 = 0;
961     Timer timer("test_timer");
962     uint32_t ret = timer.Setup();
963     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
964     timer.Register(TimeOutCallback1, 1);
965     timer.Register(TimeOutCallback2, 50);
966     std::this_thread::sleep_for(std::chrono::milliseconds(500));
967     timer.Shutdown();
968     EXPECT_GE(g_data1, 8);
969     EXPECT_GE(g_data2, 2);
970 }
971 
972 /*
973  * @tc.name: testNewTimer003
974  * @tc.desc: test basic function of timer implemented by new event-system.
975  */
976 HWTEST_F(UtilsEventTest, testNewTimer003, TestSize.Level0)
977 {
978     g_data1 = 0;
979     Timer timer("test_timer");
980     uint32_t ret = timer.Setup();
981     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
982     timer.Register(TimeOutCallback1, 1);
983     timer.Register(TimeOutCallback1, 2);
984     std::this_thread::sleep_for(std::chrono::milliseconds(30));
985     timer.Shutdown();
986     EXPECT_GE(g_data1, 5);
987 }
988 
989 class A {
990 public:
A(int data)991     explicit A(int data) : data_(data), timer_("ATimer") {}
992     ~A() = default;
993     bool Init();
994     bool StartTimer(int milliseconds, bool once);
995     void StopTimer();
GetData() const996     int GetData() const {return data_;}
997 private:
TimeOutProc()998     void TimeOutProc()
999     {
1000         data_ -= 1;
1001     };
1002     int data_;
1003     Timer timer_;
1004 };
1005 
Init()1006 bool A::Init()
1007 {
1008     return timer_.Setup() == Utils::TIMER_ERR_OK;
1009 }
1010 
StartTimer(int milliseconds,bool once)1011 bool A::StartTimer(int milliseconds, bool once)
1012 {
1013     uint32_t timerId = timer_.Register(std::bind(&A::TimeOutProc, this), milliseconds, once);
1014     return timerId != Utils::TIMER_ERR_DEAL_FAILED;
1015 }
1016 
StopTimer()1017 void A::StopTimer()
1018 {
1019     timer_.Shutdown();
1020 }
1021 
1022 /*
1023  * @tc.name: testNewTimer004
1024  * @tc.desc: test wrapper of the timer implemented by new event-system.
1025  */
1026 HWTEST_F(UtilsEventTest, testNewTimer004, TestSize.Level0)
1027 {
1028     A a(10);
1029     EXPECT_TRUE(a.Init());
1030     EXPECT_TRUE(a.StartTimer(1, true));
1031     std::this_thread::sleep_for(std::chrono::milliseconds(20));
1032     a.StopTimer();
1033     EXPECT_EQ(9, a.GetData());
1034 }
1035 
1036 /*
1037  * @tc.name: testNewTimer005
1038  * @tc.desc: test abnormal case of timer implemented by new event-system.
1039  */
1040 HWTEST_F(UtilsEventTest, testNewTimer005, TestSize.Level0)
1041 {
1042     g_data1 = 0;
1043     Timer timer("test_timer", -1);
1044     uint32_t ret = timer.Setup();
1045     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1046 
1047     uint32_t timerId = 0;
1048     for (uint32_t i = 0; i < 10; i++) {
1049         timerId = timer.Register(TimeOutCallback1, 7, true);
1050         std::this_thread::sleep_for(std::chrono::milliseconds(10));
1051     }
1052     timer.Unregister(timerId);
1053     timer.Unregister(timerId);
1054 
1055     timer.Shutdown();
1056     timer.Shutdown(false);
1057     EXPECT_GE(g_data1, 5);
1058 }
1059 
1060 /*
1061  * @tc.name: testNewTimer006
1062  * @tc.desc: sleep test for ivi of timer implemented by new event-system.
1063  */
1064 HWTEST_F(UtilsEventTest, testNewTimer006, TestSize.Level0)
1065 {
1066     g_data1 = 0;
1067     Timer timer("test_timer");
1068     uint32_t ret = timer.Setup();
1069     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1070     timer.Register(TimeOutCallback1, 10);
1071 
1072     for (int i = 0; i < 11; i++) {
1073         int64_t pre = CurMs();
1074         std::this_thread::sleep_for(std::chrono::milliseconds(10));
1075         int64_t cur = CurMs();
1076         EXPECT_GE(cur - pre, 10);
1077     }
1078     timer.Shutdown();
1079     EXPECT_GE(g_data1, 10);
1080 }
1081 
1082 /*
1083  * @tc.name: testNewTimer007
1084  * @tc.desc: recursive test of timer implemented by new event-system.
1085  */
DoFunc(Timer & timer,int & count)1086 void DoFunc(Timer &timer, int &count)
1087 {
1088     (void)timer.Register(
1089         [&timer, &count]() {
1090             count += 1;
1091             if (count > 9) { // 9: recursion depth
1092                 return;
1093             }
1094             DoFunc(timer, count);
1095         },
1096         10, true); // 10: interval
1097     g_data1++;
1098 }
1099 
DoFunc2(Timer & timer,int & count)1100 void DoFunc2(Timer &timer, int &count)
1101 {
1102     (void)timer.Register(
1103         [&timer, &count]() {
1104             count += 1;
1105             if (count > 9) { // 9: recursion depth
1106                 return;
1107             }
1108             DoFunc2(timer, count);
1109         },
1110         10, true); // 10: interval
1111     g_data1++;
1112 }
1113 
1114 HWTEST_F(UtilsEventTest, testNewTimer007, TestSize.Level0)
1115 {
1116     g_data1 = 0;
1117     Timer timer("test_timer");
1118     uint32_t ret = timer.Setup();
1119     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1120 
1121     int cnt = 0, cnt1 = 0;
1122     DoFunc(timer, cnt);
1123     DoFunc2(timer, cnt1);
1124     std::this_thread::sleep_for(std::chrono::milliseconds(50));
1125     EXPECT_GE(g_data1, 5);  /* 8 for max */
1126     EXPECT_GE(14, g_data1); /* 10 for min */
1127     std::this_thread::sleep_for(std::chrono::milliseconds(50));
1128     timer.Shutdown();
1129     EXPECT_GE(g_data1, 10); /* 18 for max */
1130 }
1131 
1132 /*
1133  * @tc.name: testNewTimer008
1134  * @tc.desc: test execute-once and execute-periodly tasks.
1135  */
1136 HWTEST_F(UtilsEventTest, testNewTimer008, TestSize.Level0)
1137 {
1138     g_data1 = 0;
1139     Timer timer("test_timer");
1140     uint32_t ret = timer.Setup();
1141     EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1142     timer.Register(TimeOutCallback1, 10, true);
1143     timer.Register(TimeOutCallback1, 10);
1144     timer.Register(TimeOutCallback1, 10, true);
1145     timer.Register(TimeOutCallback1, 10);
1146     std::this_thread::sleep_for(std::chrono::milliseconds(52));
1147     timer.Shutdown();
1148     EXPECT_GE(g_data1, 8); /* 12 for max */
1149 }
1150 
1151 
1152 }  // namespace
1153 }  // namespace OHOS