1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "os/fake_timer/fake_timerfd.h"
18
19 #include <sys/eventfd.h>
20 #include <unistd.h>
21
22 #include <map>
23
24 namespace bluetooth {
25 namespace os {
26 namespace fake_timer {
27
28 class FakeTimerFd {
29 public:
30 int fd;
31 bool active;
32 uint64_t trigger_ms;
33 uint64_t period_ms;
34 };
35
36 static std::map<int, FakeTimerFd*> fake_timers;
37 static uint64_t clock = 0;
38 static uint64_t max_clock = UINT64_MAX;
39
timespec_to_ms(const timespec * t)40 static uint64_t timespec_to_ms(const timespec* t) {
41 return t->tv_sec * 1000 + t->tv_nsec / 1000000;
42 }
43
fake_timerfd_create(int,int)44 int fake_timerfd_create(int /* clockid */, int /* flags */) {
45 int fd = eventfd(0, EFD_SEMAPHORE);
46 if (fd == -1) {
47 return fd;
48 }
49
50 FakeTimerFd* entry = new FakeTimerFd();
51 fake_timers[fd] = entry;
52 entry->fd = fd;
53 return fd;
54 }
55
fake_timerfd_settime(int fd,int,const struct itimerspec * new_value,struct itimerspec *)56 int fake_timerfd_settime(
57 int fd,
58 int /* flags */,
59 const struct itimerspec* new_value,
60 struct itimerspec* /* old_value */) {
61 if (fake_timers.find(fd) == fake_timers.end()) {
62 return -1;
63 }
64
65 FakeTimerFd* entry = fake_timers[fd];
66
67 uint64_t trigger_delta_ms = timespec_to_ms(&new_value->it_value);
68 entry->active = trigger_delta_ms != 0;
69 if (!entry->active) {
70 return 0;
71 }
72
73 uint64_t period_ms = timespec_to_ms(&new_value->it_interval);
74 entry->trigger_ms = clock + trigger_delta_ms;
75 entry->period_ms = period_ms;
76 return 0;
77 }
78
fake_timerfd_close(int fd)79 int fake_timerfd_close(int fd) {
80 auto timer_iterator = fake_timers.find(fd);
81 if (timer_iterator != fake_timers.end()) {
82 delete timer_iterator->second;
83 fake_timers.erase(timer_iterator);
84 }
85 return close(fd);
86 }
87
fake_timerfd_reset()88 void fake_timerfd_reset() {
89 clock = 0;
90 max_clock = UINT64_MAX;
91 // if there are entries still here, it is a failure of our users to clean up
92 // so let them leak and trigger errors
93 fake_timers.clear();
94 }
95
fire_next_event(uint64_t new_clock)96 static bool fire_next_event(uint64_t new_clock) {
97 uint64_t earliest_time = new_clock;
98 FakeTimerFd* to_fire = nullptr;
99 for (auto it = fake_timers.begin(); it != fake_timers.end(); it++) {
100 FakeTimerFd* entry = it->second;
101 if (!entry->active) {
102 continue;
103 }
104
105 if (entry->trigger_ms > clock && entry->trigger_ms <= new_clock) {
106 if (to_fire == nullptr || entry->trigger_ms < earliest_time) {
107 to_fire = entry;
108 earliest_time = entry->trigger_ms;
109 }
110 }
111 }
112
113 if (to_fire == nullptr) {
114 return false;
115 }
116
117 bool is_periodic = to_fire->period_ms != 0;
118 if (is_periodic) {
119 to_fire->trigger_ms += to_fire->period_ms;
120 }
121 to_fire->active = is_periodic;
122 uint64_t value = 1;
123 write(to_fire->fd, &value, sizeof(uint64_t));
124 return true;
125 }
126
fake_timerfd_advance(uint64_t ms)127 void fake_timerfd_advance(uint64_t ms) {
128 uint64_t new_clock = clock + ms;
129 if (new_clock < clock) {
130 new_clock = max_clock;
131 }
132 while (fire_next_event(new_clock)) {
133 }
134 clock = new_clock;
135 }
136
fake_timerfd_cap_at(uint64_t ms)137 void fake_timerfd_cap_at(uint64_t ms) {
138 max_clock = ms;
139 }
140
fake_timerfd_get_clock()141 uint64_t fake_timerfd_get_clock() {
142 return clock;
143 }
144
145 } // namespace fake_timer
146 } // namespace os
147 } // namespace bluetooth
148