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 void TimeOut();
68 bool Initialize(uint32_t interval);
69 void Uninitialize();
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 = 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
InitAndRun(std::shared_ptr<TimerFdHandler> & handler,const uint32_t interval,std::unique_ptr<IOEventReactor> & reactor,std::thread & loopThread)312 static void InitAndRun(std::shared_ptr<TimerFdHandler>& handler, const uint32_t interval,
313 std::unique_ptr<IOEventReactor>& reactor, std::thread& loopThread)
314 {
315 // Initialize timer handler and add it to reactor
316 ASSERT_TRUE(handler->Initialize(interval));
317 ASSERT_TRUE(handler->Start(reactor.get()));
318
319 // Run event loop
320 loopThread = std::thread([&reactor] {
321 reactor->Run(-1);
322 }
323 );
324 }
325
326 /*
327 * @tc.name: testEvent001
328 * @tc.desc: test handling event of timerfd.
329 */
330 HWTEST_F(UtilsEventTest, testEvent001, TestSize.Level0)
331 {
332 g_data = 0;
333 // 1. Open timer
334 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
335 ASSERT_NE(fd, -1);
336 // 2. Create timer event handler
337 std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
338
339 // 3. Create reactor for event loop
340 std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
341 ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
342 reactor->EnableHandling();
343
344 // 4. Initialize timer handler and add it to reactor. Run event loop
345 uint32_t interval = 10;
346 std::thread loopThread;
347 InitAndRun(handler, interval, reactor, loopThread);
348
349 // 5. Wait for event handling
350 std::this_thread::sleep_for(std::chrono::milliseconds(16));
351
352 // 6. Check result, execute once at least
353 EXPECT_GE(g_data, 1);
354
355 // 7. terminate the event-loop (aka Run())
356 reactor->Terminate();
357 loopThread.join();
358 }
359
360 /*
361 * @tc.name: testEvent002
362 * @tc.desc: test changing event to EVENT_NONE.
363 */
364 HWTEST_F(UtilsEventTest, testEvent002, TestSize.Level0)
365 {
366 g_data = 0;
367 // 1. Open timer
368 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
369 ASSERT_NE(fd, -1);
370 // 2. Create timer event handler
371 std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
372
373 // 3. Create reactor for event loop
374 std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
375 ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
376
377 // 4. Initialize timer handler and add it to reactor. Run event loop
378 uint32_t interval = 10;
379 std::thread loopThread;
380 InitAndRun(handler, interval, reactor, loopThread);
381
382 // 5. Change settings
383 reactor->DisableHandling();
384 std::this_thread::sleep_for(std::chrono::milliseconds(1));
385 reactor->EnableHandling();
386 handler->SetEvents(Events::EVENT_NONE);
387
388 // 6. Wait for event handling
389 std::this_thread::sleep_for(std::chrono::milliseconds(16));
390
391 // 7. Check result, no execution
392 EXPECT_EQ(g_data, 0);
393
394 // 8. terminate the event-loop (aka Run())
395 reactor->Terminate();
396 loopThread.join();
397 }
398
399 /*
400 * @tc.name: testEvent003
401 * @tc.desc: test disable single event.
402 */
403 HWTEST_F(UtilsEventTest, testEvent003, TestSize.Level0)
404 {
405 g_data = 0;
406 // 1. Open timer
407 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
408 ASSERT_NE(fd, -1);
409 // 2. Create timer event handler
410 std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
411
412 // 3. Create reactor for event loop
413 std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
414 ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
415
416 // 4. Initialize timer handler and add it to reactor. Run event loop
417 uint32_t interval = 10;
418 std::thread loopThread;
419 InitAndRun(handler, interval, reactor, loopThread);
420
421 // 5. Change settings
422 reactor->EnableHandling();
423 ASSERT_TRUE(handler->Stop(reactor.get())); // block to get lock, so no need to wait.
424
425 // 6. Check result, no execution
426 EXPECT_EQ(g_data, 0);
427
428 // 7. terminate the event-loop (aka Run())
429 reactor->Terminate();
430 loopThread.join();
431 }
432
433 /*
434 * @tc.name: testEvent004
435 * @tc.desc: test removing callback.
436 */
437 HWTEST_F(UtilsEventTest, testEvent004, TestSize.Level0)
438 {
439 g_data = 0;
440 // 1. Open timer
441 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
442 ASSERT_NE(fd, -1);
443 // 2. Create timer event handler
444 std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
445
446 // 3. Create reactor for event loop
447 std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
448 ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
449
450 // 4. Initialize timer handler and add it to reactor. Run event loop
451 uint32_t interval = 10;
452 std::thread loopThread;
453 InitAndRun(handler, interval, reactor, loopThread);
454
455 // 5. Change settings
456 reactor->EnableHandling();
457 handler->SetCallback(nullptr);
458
459 // 6. Wait for event handling
460 std::this_thread::sleep_for(std::chrono::milliseconds(16));
461
462 // 7. Check result, no execution
463 EXPECT_EQ(g_data, 0);
464
465 // 8. terminate the event-loop (aka Run())
466 reactor->Terminate();
467 loopThread.join();
468 }
469
470 /*
471 * @tc.name: testEvent005
472 * @tc.desc: test change event but not update.
473 */
474 HWTEST_F(UtilsEventTest, testEvent005, TestSize.Level0)
475 {
476 g_data = 0;
477 // 1. Open timer
478 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
479 ASSERT_NE(fd, -1);
480 // 2. Create timer event handler
481 std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
482
483 // 3. Create reactor for event loop
484 std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
485 ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
486
487 // 4. Initialize timer handler and add it to reactor. Run event loop
488 uint32_t interval = 15;
489 std::thread loopThread;
490 InitAndRun(handler, interval, reactor, loopThread);
491
492 // 5. Change settings but not update
493 handler->SetEvents(Events::EVENT_WRITE);
494 reactor->EnableHandling();
495
496 // 6. Wait for event handling
497 std::this_thread::sleep_for(std::chrono::milliseconds(16));
498
499 // 7. Check result, no execution
500 EXPECT_EQ(g_data, 0);
501
502 // 8. terminate the event-loop (aka Run())
503 reactor->Terminate();
504 loopThread.join();
505 }
506
507 /*
508 * @tc.name: testEvent006
509 * @tc.desc: test release the handler when started.
510 */
511 HWTEST_F(UtilsEventTest, testEvent006, TestSize.Level0)
512 {
513 g_data = 0;
514 // 1. Open timer
515 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
516 ASSERT_NE(fd, -1);
517 // 2. Create timer event handler
518 std::shared_ptr<TimerFdHandler> handler = std::make_shared<TimerFdHandler>(fd, &TimerCallback1);
519
520 // 3. Create reactor for event loop
521 std::unique_ptr<IOEventReactor> reactor = std::make_unique<IOEventReactor>();
522 ASSERT_EQ(reactor->SetUp(), EVENT_SYS_ERR_OK);
523
524 // 4. Initialize timer handler and add it to reactor. Run event loop
525 uint32_t interval = 15;
526 std::thread loopThread;
527 InitAndRun(handler, interval, reactor, loopThread);
528
529 // 5. release eventhandler
530 handler.reset();
531 reactor->EnableHandling();
532
533 // 6. Wait for event handling
534 std::this_thread::sleep_for(std::chrono::milliseconds(16));
535
536 // 7. Check result, no execution
537 EXPECT_EQ(g_data, 0);
538
539 // 8. terminate the event-loop (aka Run())
540 reactor->Terminate();
541 loopThread.join();
542 }
543
544 // Try to substitue underlying implementation of OHOS::UTILS::TIMER
545 class TimerEventHandler {
546 public:
547 using TimerEventCallback = std::function<void(TimerEventHandler*)>;
548 TimerEventHandler(int timerFd, uint32_t timeout, bool once);
549 TimerEventHandler(uint32_t timeout /* ms */, bool once);
550 ~TimerEventHandler();
551
552 TimerEventHandler(const TimerEventHandler&&) = delete;
553 TimerEventHandler& operator=(const TimerEventHandler&&) = delete;
554 TimerEventHandler(const TimerEventHandler&) = delete;
555 TimerEventHandler& operator=(const TimerEventHandler&) = delete;
556
557 ErrCode Initialize();
558 void Uninitialize();
559
560 bool Start(IOEventReactor* reactor);
561 bool Stop(IOEventReactor* reactor);
562
SetTimerId(const uint32_t & id)563 inline void SetTimerId(const uint32_t& id) { timerId_ = id; }
564
SetTimerEventCallback(const TimerEventCallback & callback)565 inline void SetTimerEventCallback(const TimerEventCallback& callback) { timerEventCallback_ = callback; }
566
GetInterval() const567 inline uint32_t GetInterval() const { return interval_; }
GetTimerFd() const568 inline int GetTimerFd() const { return handler_->GetFd(); }
GetTimerId() const569 inline uint32_t GetTimerId() const { return timerId_; }
570
571 private:
572 void TimeOut();
573
574 private:
575 bool once_;
576 uint32_t timerId_;
577 uint32_t interval_;
578 std::unique_ptr<IOEventHandler> handler_;
579 TimerEventCallback timerEventCallback_;
580
581 friend class Timer;
582 };
583
584 class Timer {
585 public:
586 using TimerCallback = std::function<void ()>;
587 using TimerCallbackPtr = std::shared_ptr<TimerCallback>;
588 using TimerEventCallback = TimerEventHandler::TimerEventCallback;
589
590 explicit Timer(const std::string& name, int timeoutMs = 1000);
~Timer()591 virtual ~Timer()
592 {
593 }
594 virtual uint32_t Setup();
595 virtual void Shutdown(bool useJoin = true);
596 uint32_t Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once = false);
597 void Unregister(uint32_t timerId);
598
599 private:
600 void MainLoop();
601 void OnTimer(TimerEventHandler* handler, const TimerCallback& callback);
602 int GetTimerFd(uint32_t interval /* ms */);
603 uint32_t GetValidId() const;
604 void EraseUnusedTimerId(uint32_t interval, const std::vector<uint32_t>& unusedIds);
605
606 private:
607 using TimerHandlerPtr = std::shared_ptr<TimerEventHandler>;
608 using TimerHandlerList = std::list<TimerHandlerPtr>;
609
610 ErrCode ScheduleTimer(const TimerEventCallback& callback, uint32_t interval, uint32_t timerId, int& timerFd,
611 bool once);
612 void EraseExistNode(TimerHandlerPtr target);
613 ErrCode CancelTimer(TimerHandlerPtr target);
614
615 std::map<uint32_t, TimerHandlerList> intervalToTimers_;
616 std::map<uint32_t, TimerHandlerPtr> timerHandlers_;
617
618 std::string name_;
619 int timeoutMs_;
620 std::thread thread_;
621 std::unique_ptr<IOEventReactor> reactor_;
622 std::mutex mutex_;
623 };
624
Timer(const std::string & name,int timeoutMs)625 Timer::Timer(const std::string& name, int timeoutMs) : name_(name), timeoutMs_(timeoutMs),
626 reactor_(new IOEventReactor()) {}
627
MainLoop()628 void Timer::MainLoop()
629 {
630 prctl(PR_SET_NAME, name_.c_str(), 0, 0, 0);
631
632 reactor_->Run(timeoutMs_);
633 std::cout << "||" << gettid() << "||" << "Loop finished" << std::endl;
634
635 if (reactor_->CleanUp() != EVENT_SYS_ERR_OK) {
636 std::cout << "||" << gettid() << "||" <<
637 "Reactor Clean Failed. It will clean during deconstruction" << std::endl;
638 }
639 }
640
Setup()641 uint32_t Timer::Setup()
642 {
643 if (thread_.joinable()) { // avoid double assign to an active thread
644 return TIMER_ERR_INVALID_VALUE;
645 }
646
647 if (reactor_->SetUp() != EVENT_SYS_ERR_OK) {
648 std::cout << "||" << gettid() << "||" << "Setup reactor failed." << std::endl;
649 return TIMER_ERR_DEAL_FAILED;
650 }
651
652 reactor_->EnableHandling();
653
654 std::thread loopThread(std::bind(&Timer::MainLoop, this));
655 thread_.swap(loopThread);
656
657 return TIMER_ERR_OK;
658 }
659
Shutdown(bool useJoin)660 void Timer::Shutdown(bool useJoin)
661 {
662 if (!thread_.joinable()) {
663 std::cout << "||" << gettid() << "||" << "Invalid operation. Already shutdown." << std::endl;
664 return;
665 }
666
667 std::cout << "||" << gettid() << "||" << "Stop reactor." << std::endl;
668 reactor_->Terminate();
669
670 if (!useJoin) {
671 thread_.detach();
672 return;
673 }
674 thread_.join();
675 }
676
ScheduleTimer(const TimerEventCallback & callback,uint32_t interval,uint32_t timerId,int & timerFd,bool once)677 ErrCode Timer::ScheduleTimer(const TimerEventCallback& callback, uint32_t interval, uint32_t timerId,
678 int& timerFd, bool once)
679 {
680 std::shared_ptr<TimerEventHandler> handler = std::make_shared<TimerEventHandler>(timerFd, interval, once);
681
682 handler->SetTimerId(timerId);
683 handler->SetTimerEventCallback(callback);
684
685 uint32_t ret = handler->Initialize();
686 if (ret != TIMER_ERR_OK) {
687 std::cout << "||" << gettid() << "||" << "Init timer handler failed." << std::endl;
688 return ret;
689 }
690 if (!handler->Start(reactor_.get())) {
691 std::cout << "||" << gettid() << "||" << "Start timer handler failed." << std::endl;
692 return TIMER_ERR_DEAL_FAILED;
693 }
694 timerHandlers_.emplace(timerId, handler); // Add to the id2handlers map
695 intervalToTimers_[interval].push_back(handler); // Add to interval2handlerlist map
696 timerFd = handler->GetTimerFd();
697 return TIMER_ERR_OK;
698 }
699
700
Register(const TimerCallback & callback,uint32_t interval,bool once)701 uint32_t Timer::Register(const TimerCallback& callback, uint32_t interval /* ms */, bool once)
702 {
703 std::lock_guard<std::mutex> lock(mutex_);
704
705 // wrap the callback in OnTiner
706 TimerEventCallback wrappedCb = std::bind(&Timer::OnTimer, this, std::placeholders::_1, callback);
707 int timerFd = once ? IO_EVENT_INVALID_FD : GetTimerFd(interval); // Get timerFd
708 uint32_t timerId = GetValidId(); // Get timerId
709
710 uint32_t ret = ScheduleTimer(wrappedCb, interval, timerId, timerFd, once);
711 if (ret != TIMER_ERR_OK) {
712 std::cout << "||" << gettid() << "||" << "Try schedule task failed. timer-id:" <<
713 timerId << ", interval:" << interval << "timer-fd:" << timerFd << std::endl;
714 return TIMER_ERR_DEAL_FAILED;
715 }
716
717 return timerId;
718 }
719
EraseExistNode(TimerHandlerPtr target)720 void Timer::EraseExistNode(TimerHandlerPtr target)
721 {
722 auto handlerList = intervalToTimers_[target->interval_];
723 auto itor = std::find(handlerList.begin(), handlerList.end(), target);
724 if (itor != handlerList.end()) {
725 handlerList.erase(itor);
726 }
727
728 if (handlerList.empty()) {
729 intervalToTimers_.erase(target->interval_);
730 }
731 }
732
CancelTimer(TimerHandlerPtr target)733 ErrCode Timer::CancelTimer(TimerHandlerPtr target)
734 {
735 std::cout << "||" << gettid() << "||" << "Cancle timer handler with fd:" << target->GetTimerFd() << std::endl;
736 target->Uninitialize();
737 if (!target->Stop(reactor_.get())) {
738 std::cout << "||" << gettid() << "||" << "Stop timer handler failed." << std::endl;
739 return TIMER_ERR_DEAL_FAILED;
740 }
741 timerHandlers_.erase(target->timerId_);
742 EraseExistNode(target);
743 return TIMER_ERR_OK;
744 }
745
Unregister(uint32_t timerId)746 void Timer::Unregister(uint32_t timerId)
747 {
748 std::lock_guard<std::mutex> lock(mutex_);
749
750 if (timerHandlers_.find(timerId) == timerHandlers_.end()) {
751 std::cout << "||" << gettid() << "||" <<
752 "Unregister failed. timer-id:" << timerId << " not found." << std::endl;
753 return;
754 }
755
756 auto entry = timerHandlers_[timerId];
757 std::cout << "||" << gettid() << "||" << "Try remove timer handler from reactor. timerId:" << timerId <<
758 ", interval:" << entry->interval_ << std::endl;
759
760 if (CancelTimer(entry) != TIMER_ERR_OK) {
761 std::cout << "||" << gettid() << "||" << "Unregister timer handler failed." << std::endl;
762 }
763 }
764
OnTimer(TimerEventHandler * handler,const TimerCallback & callback)765 void Timer::OnTimer(TimerEventHandler* handler, const TimerCallback& callback)
766 {
767 callback();
768
769 if (handler->once_) {
770 Unregister(handler->timerId_);
771 }
772 }
773
GetValidId() const774 uint32_t Timer::GetValidId() const
775 {
776 static std::atomic_uint32_t timerId = 1;
777
778 while (timerHandlers_.find(timerId) != timerHandlers_.end()) {
779 timerId = timerId + 1;
780 if (timerId == UINT32_MAX) {
781 timerId = 1;
782 }
783
784 if (timerId == TIMER_ERR_DEAL_FAILED) {
785 timerId = timerId + 1;
786 }
787 }
788
789 return timerId;
790 }
791
GetTimerFd(uint32_t interval)792 int Timer::GetTimerFd(uint32_t interval /* ms */)
793 {
794 if (intervalToTimers_.find(interval) == intervalToTimers_.end()) {
795 return IO_EVENT_INVALID_FD;
796 }
797 auto &handlerList = intervalToTimers_[interval];
798 for (const TimerHandlerPtr &ptr : handlerList) {
799 if (!ptr->once_) {
800 return ptr->GetTimerFd();
801 }
802 }
803 return IO_EVENT_INVALID_FD;
804 }
805
TimerEventHandler(int timerFd,uint32_t timeout,bool once)806 TimerEventHandler::TimerEventHandler(int timerFd, uint32_t timeout /* ms */, bool once)
807 : once_(once), interval_(timeout)
808 {
809 if (timerFd == IO_EVENT_INVALID_FD) {
810 handler_ = std::make_unique<IOEventHandler>(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC));
811 } else {
812 handler_ = std::make_unique<IOEventHandler>(timerFd);
813 }
814 }
815
~TimerEventHandler()816 TimerEventHandler::~TimerEventHandler()
817 {
818 if (close(handler_->GetFd()) != 0) {
819 std::cout << "||" << gettid() << "||" << "Close timer-fd failed. fd:" << handler_->GetFd() << ", interval:" <<
820 interval_ << ", once:" << once_ << std::endl;
821 }
822 handler_->SetFd(IO_EVENT_INVALID_FD);
823 }
824
Initialize()825 ErrCode TimerEventHandler::Initialize()
826 {
827 if (handler_->GetFd() == IO_EVENT_INVALID_FD) {
828 std::cout << "||" << gettid() << "||" << "Invalid timer-fd:" << handler_->GetFd() << ", interval:" <<
829 interval_ << ", once:" << once_ << std::endl;
830 return TIMER_ERR_INVALID_VALUE;
831 }
832
833 struct itimerspec newValue = {{0, 0}, {0, 0}};
834 timespec now{0, 0};
835 if (clock_gettime(CLOCK_MONOTONIC, &now) == -1) {
836 std::cout << "||" << gettid() << "||" << "Get current time failed." << std::endl;
837 return TIMER_ERR_DEAL_FAILED;
838 }
839
840 // next time out time is now + interval
841 newValue.it_value.tv_sec = now.tv_sec + interval_ / MILLI_TO_BASE;
842 newValue.it_value.tv_nsec = now.tv_nsec + (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
843 if (newValue.it_value.tv_nsec >= NANO_TO_BASE) {
844 newValue.it_value.tv_sec = newValue.it_value.tv_sec + 1;
845 newValue.it_value.tv_nsec = newValue.it_value.tv_nsec % NANO_TO_BASE;
846 }
847
848 if (once_) {
849 // interval, 0 means time out only once
850 newValue.it_interval.tv_sec = 0;
851 newValue.it_interval.tv_nsec = 0;
852 } else {
853 // interval
854 newValue.it_interval.tv_sec = interval_ / MILLI_TO_BASE;
855 newValue.it_interval.tv_nsec = (interval_ % MILLI_TO_BASE) * MILLI_TO_NANO;
856 }
857
858 if (timerfd_settime(handler_->GetFd(), TFD_TIMER_ABSTIME, &newValue, nullptr) == -1) {
859 std::cout << "||" << gettid() << "||" << "Set timer-fd failed. next:" <<
860 static_cast<long long>(newValue.it_value.tv_sec) << "interval:" <<
861 static_cast<long long>(newValue.it_interval.tv_sec) << std::endl;
862 return TIMER_ERR_DEAL_FAILED;
863 }
864
865 handler_->SetCallback(std::bind(&TimerEventHandler::TimeOut, this));
866 handler_->EnableRead();
867
868 return TIMER_ERR_OK;
869 }
870
Uninitialize()871 void TimerEventHandler::Uninitialize()
872 {
873 handler_->DisableAll();
874 }
875
Start(IOEventReactor * reactor)876 bool TimerEventHandler::Start(IOEventReactor* reactor)
877 {
878 if (handler_ == nullptr || !handler_->Start(reactor)) {
879 return false;
880 }
881
882 return true;
883 }
884
Stop(IOEventReactor * reactor)885 bool TimerEventHandler::Stop(IOEventReactor* reactor)
886 {
887 if (handler_ == nullptr || !handler_->Stop(reactor)) {
888 return false;
889 }
890
891 return true;
892 }
893
TimeOut()894 void TimerEventHandler::TimeOut()
895 {
896 if (handler_->GetFd() == IO_EVENT_INVALID_FD) {
897 std::cout << "||" << gettid() << "||" << "Invalid timerfd." << std::endl;
898 return;
899 }
900 uint64_t expirations = 0;
901 ssize_t n = ::read(handler_->GetFd(), &expirations, sizeof(expirations));
902 if (n != sizeof(expirations)) {
903 std::cout << "||" << gettid() << "||" << "Reads " << static_cast<int>(n) <<
904 " bytes instead of 8 from timer fd." << std::endl;
905 }
906
907 if (timerEventCallback_) {
908 timerEventCallback_(this);
909 }
910 }
911
912 std::atomic<int> g_data1(0);
TimeOutCallback1()913 void TimeOutCallback1()
914 {
915 g_data1 += 1;
916 }
917
918 std::atomic<int> g_data2(0);
TimeOutCallback2()919 void TimeOutCallback2()
920 {
921 g_data2 = g_data2 + 1;
922 }
923
CurMs()924 int64_t CurMs()
925 {
926 struct timeval tpend;
927 gettimeofday(&tpend, nullptr);
928 return (tpend.tv_sec * 1000000 + tpend.tv_usec) / 1000; // 1000000: s to us, 1000: us to ms
929 }
930
931 /*
932 * @tc.name: testNewTimer001
933 * @tc.desc: test basic function of timer implemented by new event-system.
934 */
935 HWTEST_F(UtilsEventTest, testNewTimer001, TestSize.Level0)
936 {
937 g_data1 = 0;
938 Timer timer("test_timer");
939 uint32_t ret = timer.Setup();
940 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
941 timer.Register(TimeOutCallback1, 1, true);
942 std::this_thread::sleep_for(std::chrono::milliseconds(15));
943 timer.Shutdown();
944 EXPECT_EQ(1, g_data1);
945 }
946
947 /*
948 * @tc.name: testNewTimer002
949 * @tc.desc: test basic function of timer implemented by new event-system.
950 */
951 HWTEST_F(UtilsEventTest, testNewTimer002, TestSize.Level0)
952 {
953 g_data1 = 0;
954 g_data2 = 0;
955 Timer timer("test_timer");
956 uint32_t ret = timer.Setup();
957 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
958 timer.Register(TimeOutCallback1, 1);
959 timer.Register(TimeOutCallback2, 50);
960 std::this_thread::sleep_for(std::chrono::milliseconds(500));
961 timer.Shutdown();
962 EXPECT_GE(g_data1, 8);
963 EXPECT_GE(g_data2, 2);
964 }
965
TestTimerEvent(Timer & timer)966 static void TestTimerEvent(Timer& timer)
967 {
968 uint32_t interval = 1;
969 timer.Register(TimeOutCallback1, interval);
970 uint32_t interval2 = 2;
971 timer.Register(TimeOutCallback1, interval2);
972 int sleepTime = 30;
973 std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
974 timer.Shutdown();
975 }
976
977 /*
978 * @tc.name: testNewTimer003
979 * @tc.desc: test basic function of timer implemented by new event-system.
980 */
981 HWTEST_F(UtilsEventTest, testNewTimer003, TestSize.Level0)
982 {
983 g_data1 = 0;
984 Timer timer("test_timer");
985 uint32_t ret = timer.Setup();
986 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
987 TestTimerEvent(timer);
988 EXPECT_GE(g_data1, 5);
989 }
990
991 class A {
992 public:
A(int data)993 explicit A(int data) : data_(data), timer_("ATimer") {}
994 ~A() = default;
995 bool Init();
GetData() const996 int GetData() const {return data_;}
997 bool StartTimer(int milliseconds, bool once);
998 void StopTimer();
999 private:
TimeOutProc()1000 void TimeOutProc()
1001 {
1002 data_ -= 1;
1003 };
1004 int data_;
1005 Timer timer_;
1006 };
1007
Init()1008 bool A::Init()
1009 {
1010 return timer_.Setup() == Utils::TIMER_ERR_OK;
1011 }
1012
StopTimer()1013 void A::StopTimer()
1014 {
1015 timer_.Shutdown();
1016 }
1017
StartTimer(int milliseconds,bool once)1018 bool A::StartTimer(int milliseconds, bool once)
1019 {
1020 uint32_t timerId = timer_.Register(std::bind(&A::TimeOutProc, this), milliseconds, once);
1021 return timerId != Utils::TIMER_ERR_DEAL_FAILED;
1022 }
1023
1024 /*
1025 * @tc.name: testNewTimer004
1026 * @tc.desc: test wrapper of the timer implemented by new event-system.
1027 */
1028 HWTEST_F(UtilsEventTest, testNewTimer004, TestSize.Level0)
1029 {
1030 A a(10);
1031 EXPECT_TRUE(a.Init());
1032 EXPECT_TRUE(a.StartTimer(1, true));
1033 std::this_thread::sleep_for(std::chrono::milliseconds(20));
1034 a.StopTimer();
1035 EXPECT_EQ(9, a.GetData());
1036 }
1037
SleepLoop()1038 static void SleepLoop()
1039 {
1040 int loops = 11;
1041 int64_t desiredVal = 10;
1042 int sleepTime = 10;
1043 for (int i = 0; i < loops; i++) {
1044 int64_t pre = CurMs();
1045 std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
1046 int64_t cur = CurMs();
1047 EXPECT_GE(cur - pre, desiredVal);
1048 }
1049 }
1050
TimerEvent(Timer & timer)1051 static void TimerEvent(Timer& timer)
1052 {
1053 uint32_t timerId = 0;
1054 uint32_t loops = 10;
1055 uint32_t interval = 7;
1056 int sleepTime = 10;
1057 for (uint32_t i = 0; i < loops; i++) {
1058 timerId = timer.Register(TimeOutCallback1, interval, true);
1059 std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
1060 }
1061 timer.Unregister(timerId);
1062 timer.Unregister(timerId);
1063 }
1064
1065 /*
1066 * @tc.name: testNewTimer005
1067 * @tc.desc: test abnormal case of timer implemented by new event-system.
1068 */
1069 HWTEST_F(UtilsEventTest, testNewTimer005, TestSize.Level0)
1070 {
1071 g_data1 = 0;
1072 Timer timer("test_timer", -1);
1073 uint32_t ret = timer.Setup();
1074 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1075 TimerEvent(timer);
1076 timer.Shutdown();
1077 timer.Shutdown(false);
1078 EXPECT_GE(g_data1, 5);
1079 }
1080
1081 /*
1082 * @tc.name: testNewTimer006
1083 * @tc.desc: sleep test for ivi of timer implemented by new event-system.
1084 */
1085 HWTEST_F(UtilsEventTest, testNewTimer006, TestSize.Level0)
1086 {
1087 g_data1 = 0;
1088 Timer timer("test_timer");
1089 uint32_t ret = timer.Setup();
1090 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1091 timer.Register(TimeOutCallback1, 10);
1092
1093 SleepLoop();
1094 timer.Shutdown();
1095 EXPECT_GE(g_data1, 10);
1096 }
1097
1098 /*
1099 * @tc.name: testNewTimer007
1100 * @tc.desc: recursive test of timer implemented by new event-system.
1101 */
DoFunc(Timer & timer,int & count)1102 void DoFunc(Timer &timer, int &count)
1103 {
1104 (void)timer.Register(
1105 [&timer, &count]() {
1106 count = count + 1;
1107 if (count > 9) { // 9: recursion depth
1108 return;
1109 }
1110 DoFunc(timer, count);
1111 },
1112 10, true); // 10: interval
1113 g_data1++;
1114 }
1115
DoFunc2(Timer & timer,int & count)1116 void DoFunc2(Timer &timer, int &count)
1117 {
1118 (void)timer.Register(
1119 [&timer, &count]() {
1120 count = count + 1;
1121 if (count > 9) { // 9: recursion depth
1122 return;
1123 }
1124 DoFunc2(timer, count);
1125 },
1126 10, true); // 10: interval
1127 g_data1++;
1128 }
1129
1130 HWTEST_F(UtilsEventTest, testNewTimer007, TestSize.Level0)
1131 {
1132 g_data1 = 0;
1133 Timer timer("test_timer");
1134 uint32_t ret = timer.Setup();
1135 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1136
1137 int cnt = 0;
1138 int cnt1 = 0;
1139 DoFunc(timer, cnt);
1140 DoFunc2(timer, cnt1);
1141 std::this_thread::sleep_for(std::chrono::milliseconds(50));
1142 EXPECT_GE(g_data1, 5); /* 8 for max */
1143 EXPECT_GE(14, g_data1); /* 10 for min */
1144 std::this_thread::sleep_for(std::chrono::milliseconds(50));
1145 timer.Shutdown();
1146 EXPECT_GE(g_data1, 10); /* 18 for max */
1147 }
1148
TimerRegisterMechanism(Timer & timer)1149 static void TimerRegisterMechanism(Timer& timer)
1150 {
1151 uint32_t interval = 10;
1152 timer.Register(TimeOutCallback1, interval, true);
1153 timer.Register(TimeOutCallback1, interval);
1154 timer.Register(TimeOutCallback1, interval, true);
1155 timer.Register(TimeOutCallback1, interval);
1156 }
1157
1158 /*
1159 * @tc.name: testNewTimer008
1160 * @tc.desc: test execute-once and execute-periodly tasks.
1161 */
1162 HWTEST_F(UtilsEventTest, testNewTimer008, TestSize.Level0)
1163 {
1164 g_data1 = 0;
1165 Timer timer("test_timer");
1166 uint32_t ret = timer.Setup();
1167 EXPECT_EQ(Utils::TIMER_ERR_OK, ret);
1168 TimerRegisterMechanism(timer);
1169 std::this_thread::sleep_for(std::chrono::milliseconds(52));
1170 timer.Shutdown();
1171 EXPECT_GE(g_data1, 8); /* 12 for max */
1172 }
1173
1174
1175 } // namespace
1176 } // namespace OHOS