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