Fix ASAN failure in FutureDAG test
[folly.git] / folly / TimeoutQueue.cpp
1 /*
2  * Copyright 2017 Facebook, Inc.
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 <folly/TimeoutQueue.h>
18 #include <algorithm>
19 #include <vector>
20
21 namespace folly {
22
23 TimeoutQueue::Id TimeoutQueue::add(
24   int64_t now,
25   int64_t delay,
26   Callback callback) {
27   Id id = nextId_++;
28   timeouts_.insert({id, now + delay, -1, std::move(callback)});
29   return id;
30 }
31
32 TimeoutQueue::Id TimeoutQueue::addRepeating(
33   int64_t now,
34   int64_t interval,
35   Callback callback) {
36   Id id = nextId_++;
37   timeouts_.insert({id, now + interval, interval, std::move(callback)});
38   return id;
39 }
40
41 int64_t TimeoutQueue::nextExpiration() const {
42   return (timeouts_.empty() ? std::numeric_limits<int64_t>::max() :
43           timeouts_.get<BY_EXPIRATION>().begin()->expiration);
44 }
45
46 bool TimeoutQueue::erase(Id id) {
47   return timeouts_.get<BY_ID>().erase(id);
48 }
49
50 int64_t TimeoutQueue::runInternal(int64_t now, bool onceOnly) {
51   auto& byExpiration = timeouts_.get<BY_EXPIRATION>();
52   int64_t nextExp;
53   do {
54     auto end = byExpiration.upper_bound(now);
55     std::vector<Event> expired;
56     std::move(byExpiration.begin(), end, std::back_inserter(expired));
57     byExpiration.erase(byExpiration.begin(), end);
58     for (auto& event : expired) {
59       // Reinsert if repeating, do this before executing callbacks
60       // so the callbacks have a chance to call erase
61       if (event.repeatInterval >= 0) {
62         timeouts_.insert({event.id, now + event.repeatInterval,
63                           event.repeatInterval, event.callback});
64       }
65     }
66
67     // Call callbacks
68     for (auto& event : expired) {
69       event.callback(event.id, now);
70     }
71     nextExp = nextExpiration();
72   } while (!onceOnly && nextExp <= now);
73   return nextExp;
74 }
75
76 } // namespace folly