2 * Copyright 2016 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 #include "ThreadWheelTimekeeper.h"
18 #include <folly/Singleton.h>
19 #include <folly/futures/Future.h>
25 Singleton<ThreadWheelTimekeeper> timekeeperSingleton_;
27 // Our Callback object for HHWheelTimer
28 struct WTCallback : public std::enable_shared_from_this<WTCallback>,
29 public folly::HHWheelTimer::Callback {
31 // Only allow creation by this factory, to ensure heap allocation.
32 static std::shared_ptr<WTCallback> create(EventBase* base) {
33 // optimization opportunity: memory pool
34 auto cob = std::shared_ptr<WTCallback>(new WTCallback(base));
35 // Capture shared_ptr of cob in lambda so that Core inside Promise will
36 // hold a ref count to it. The ref count will be released when Core goes
37 // away which happens when both Promise and Future go away
38 cob->promise_->setInterruptHandler([cob](const folly::exception_wrapper&) {
39 cob->interruptHandler();
44 Future<Unit> getFuture() {
45 return promise_->getFuture();
48 void releasePromise() {
49 // Don't need promise anymore. Break the circular reference as promise_
50 // is holding a ref count to us via Core. Core won't go away until both
51 // Promise and Future go away.
57 std::shared_ptr<Promise<Unit>> promise_;
59 explicit WTCallback(EventBase* base)
61 promise_ = std::make_shared<Promise<Unit>>();
64 void timeoutExpired() noexcept override {
66 // Don't need Promise anymore, break the circular reference
70 void interruptHandler() {
71 // Capture shared_ptr of self in lambda, if we don't do this, object
72 // may go away before the lambda is executed from event base thread.
73 // This is not racing with timeoutExpired anymore because this is called
74 // through Future, which means Core is still alive and keeping a ref count
75 // on us, so what timeouExpired is doing won't make the object go away
76 auto me = shared_from_this();
77 base_->runInEventBaseThread([me] {
79 // Don't need Promise anymore, break the circular reference
87 ThreadWheelTimekeeper::ThreadWheelTimekeeper()
88 : thread_([this] { eventBase_.loopForever(); }),
90 HHWheelTimer::newTimer(&eventBase_, std::chrono::milliseconds(1))) {
91 eventBase_.waitUntilRunning();
92 eventBase_.runInEventBaseThread([this]{
94 eventBase_.setName("FutureTimekeepr");
98 ThreadWheelTimekeeper::~ThreadWheelTimekeeper() {
99 eventBase_.runInEventBaseThreadAndWait([this]{
100 wheelTimer_->cancelAll();
101 eventBase_.terminateLoopSoon();
106 Future<Unit> ThreadWheelTimekeeper::after(Duration dur) {
107 auto cob = WTCallback::create(&eventBase_);
108 auto f = cob->getFuture();
110 // Even shared_ptr of cob is captured in lambda this is still somewhat *racy*
111 // because it will be released once timeout is scheduled. So technically there
112 // is no gurantee that EventBase thread can safely call timeout callback.
113 // However due to fact that we are having circular reference here:
114 // WTCallback->Promise->Core->WTCallbak, so three of them won't go away until
115 // we break the circular reference. The break happens either in
116 // WTCallback::timeoutExpired or WTCallback::interruptHandler. Former means
117 // timeout callback is being safely executed. Latter captures shared_ptr of
118 // WTCallback again in another lambda for canceling timeout. The moment
119 // canceling timeout is executed in EventBase thread, the actual timeout
120 // callback has either been executed, or will never be executed. So we are
123 if (!eventBase_.runInEventBaseThread([this, cob, dur]{
124 wheelTimer_->scheduleTimeout(cob.get(), dur);
126 // Release promise to break the circular reference. Because if
127 // scheduleTimeout fails, there is nothing to *promise*. Internally
128 // Core would automatically set an exception result when Promise is
129 // destructed before fulfilling.
130 // This is either called from EventBase thread, or here.
131 // They are somewhat racy but given the rare chance this could fail,
132 // I don't see it is introducing any problem yet.
133 cob->releasePromise();
140 std::shared_ptr<Timekeeper> getTimekeeperSingleton() {
141 return timekeeperSingleton_.try_get();