| /* |
| * Copyright 2015 Facebook, Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #include "ThreadWheelTimekeeper.h" |
| |
| #include <folly/futures/Future.h> |
| #include <future> |
| #include <memory> |
| #include <vector> |
| |
| namespace folly { namespace detail { |
| |
| using std::vector; |
| |
| namespace { |
| using lock_guard = std::lock_guard<std::mutex>; |
| using unique_lock = std::unique_lock<std::mutex>; |
| using std::make_shared; |
| |
| std::mutex g_timekeeperSingletonCreateionMutex_; |
| ThreadWheelTimekeeper *g_timekeeperSingleton_{}; |
| } // namespace |
| |
| |
| ThreadWheelTimekeeper::ThreadWheelTimekeeper() : |
| timerMap_(std::chrono::milliseconds(1)), |
| thread_([this]{ thread_run(); }) |
| { |
| } |
| |
| ThreadWheelTimekeeper::~ThreadWheelTimekeeper() { |
| unique_lock lock(mutex_); |
| running_ = false; |
| cond_.notify_one(); |
| lock.unlock(); |
| |
| thread_.join(); |
| } |
| |
| void ThreadWheelTimekeeper::thread_run() |
| { |
| unique_lock lock(mutex_); |
| |
| while (running_) { |
| if (timerMap_.empty()) { |
| cond_.wait(lock); |
| continue; |
| } |
| |
| auto tp = timerMap_.nextTimeout(); |
| cond_.wait_until(lock, tp); |
| |
| vector<TimerMap::data_type> vec; |
| timerMap_.popExpiredTimers(std::inserter(vec, vec.begin())); |
| lock.unlock(); |
| TimerMap::invokeTimers(vec.begin(), vec.end()); |
| lock.lock(); |
| } |
| } |
| |
| Future<Unit> ThreadWheelTimekeeper::after(Duration dur) { |
| // first: the promise, second: a cancellation |
| using two_type = std::pair< Promise<Unit>, unsigned >; |
| auto twoptr = make_shared<two_type>(Promise<Unit>(), 0); |
| auto& prom = twoptr->first; |
| auto& cx = twoptr->second; |
| |
| prom.setInterruptHandler([twoptr, &prom, &cx] (exception_wrapper const& w) { |
| cx = 1; |
| prom.setException(w); |
| }); |
| |
| auto f = prom.getFuture(); |
| |
| lock_guard lock(mutex_); |
| timerMap_.scheduleTimeout(dur, [twoptr, &prom, &cx] () { |
| if (cx) { |
| return; |
| } |
| prom.setValue(); |
| }); |
| cond_.notify_one(); |
| |
| return f; |
| } |
| |
| Timekeeper* getTimekeeperSingleton() { |
| if (!g_timekeeperSingleton_) |
| { |
| lock_guard lock{g_timekeeperSingletonCreateionMutex_}; |
| if (!g_timekeeperSingleton_) |
| { |
| g_timekeeperSingleton_ = new ThreadWheelTimekeeper; |
| } |
| } |
| |
| return g_timekeeperSingleton_; |
| } |
| |
| }} // folly::detail |