• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/fuzz/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 fuzz {
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 clockid,int flags)44 int fake_timerfd_create(int clockid, int flags) {
45   int fd = eventfd(0, 0);
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 flags,const struct itimerspec * new_value,struct itimerspec * old_value)56 int fake_timerfd_settime(int fd, int flags, const struct itimerspec* new_value, struct itimerspec* old_value) {
57   if (fake_timers.find(fd) == fake_timers.end()) {
58     return -1;
59   }
60 
61   FakeTimerFd* entry = fake_timers[fd];
62 
63   uint64_t trigger_delta_ms = timespec_to_ms(&new_value->it_value);
64   entry->active = trigger_delta_ms != 0;
65   if (!entry->active) {
66     return 0;
67   }
68 
69   uint64_t period_ms = timespec_to_ms(&new_value->it_value);
70   entry->trigger_ms = clock + trigger_delta_ms;
71   entry->period_ms = period_ms;
72   return 0;
73 }
74 
fake_timerfd_close(int fd)75 int fake_timerfd_close(int fd) {
76   auto timer_iterator = fake_timers.find(fd);
77   if (timer_iterator != fake_timers.end()) {
78     delete timer_iterator->second;
79     fake_timers.erase(timer_iterator);
80   }
81   return close(fd);
82 }
83 
fake_timerfd_reset()84 void fake_timerfd_reset() {
85   clock = 0;
86   max_clock = UINT64_MAX;
87   // if there are entries still here, it is a failure of our users to clean up
88   // so let them leak and trigger errors
89   fake_timers.clear();
90 }
91 
fire_next_event(uint64_t new_clock)92 static bool fire_next_event(uint64_t new_clock) {
93   uint64_t earliest_time = new_clock;
94   FakeTimerFd* to_fire = nullptr;
95   for (auto it = fake_timers.begin(); it != fake_timers.end(); it++) {
96     FakeTimerFd* entry = it->second;
97     if (!entry->active) {
98       continue;
99     }
100 
101     if (entry->trigger_ms > clock && entry->trigger_ms <= new_clock) {
102       if (to_fire == nullptr || entry->trigger_ms < earliest_time) {
103         to_fire = entry;
104         earliest_time = entry->trigger_ms;
105       }
106     }
107   }
108 
109   if (to_fire == nullptr) {
110     return false;
111   }
112 
113   bool is_periodic = to_fire->period_ms != 0;
114   if (is_periodic) {
115     to_fire->trigger_ms += to_fire->period_ms;
116   }
117   to_fire->active = is_periodic;
118   uint64_t value = 1;
119   write(to_fire->fd, &value, sizeof(uint64_t));
120   return true;
121 }
122 
fake_timerfd_advance(uint64_t ms)123 void fake_timerfd_advance(uint64_t ms) {
124   uint64_t new_clock = clock + ms;
125   if (new_clock > max_clock) {
126     new_clock = max_clock;
127   }
128   while (fire_next_event(new_clock)) {
129   }
130   clock = new_clock;
131 }
132 
fake_timerfd_cap_at(uint64_t ms)133 void fake_timerfd_cap_at(uint64_t ms) {
134   max_clock = ms;
135 }
136 
137 }  // namespace fuzz
138 }  // namespace os
139 }  // namespace bluetooth
140