2 * Copyright 2004-present 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.
17 #include <folly/io/async/AsyncTimeout.h>
18 #include <folly/io/async/EventBase.h>
19 #include <folly/io/async/EventUtil.h>
20 #include <folly/io/async/Request.h>
23 #include <glog/logging.h>
27 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager)
28 : timeoutManager_(timeoutManager) {
31 &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
32 event_.ev_base = nullptr;
33 timeoutManager_->attachTimeoutManager(
35 TimeoutManager::InternalEnum::NORMAL);
36 RequestContext::saveContext();
39 AsyncTimeout::AsyncTimeout(EventBase* eventBase)
40 : timeoutManager_(eventBase) {
43 &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
44 event_.ev_base = nullptr;
46 timeoutManager_->attachTimeoutManager(
48 TimeoutManager::InternalEnum::NORMAL);
50 RequestContext::saveContext();
53 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager,
54 InternalEnum internal)
55 : timeoutManager_(timeoutManager) {
58 &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
59 event_.ev_base = nullptr;
60 timeoutManager_->attachTimeoutManager(this, internal);
61 RequestContext::saveContext();
64 AsyncTimeout::AsyncTimeout(EventBase* eventBase, InternalEnum internal)
65 : timeoutManager_(eventBase) {
68 &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
69 event_.ev_base = nullptr;
70 timeoutManager_->attachTimeoutManager(this, internal);
71 RequestContext::saveContext();
74 AsyncTimeout::AsyncTimeout(): timeoutManager_(nullptr) {
76 &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
77 event_.ev_base = nullptr;
78 RequestContext::saveContext();
81 AsyncTimeout::~AsyncTimeout() {
85 bool AsyncTimeout::scheduleTimeout(TimeoutManager::timeout_type timeout) {
86 assert(timeoutManager_ != nullptr);
87 context_ = RequestContext::saveContext();
88 return timeoutManager_->scheduleTimeout(this, timeout);
91 bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
92 return scheduleTimeout(TimeoutManager::timeout_type(milliseconds));
95 void AsyncTimeout::cancelTimeout() {
97 timeoutManager_->cancelTimeout(this);
101 bool AsyncTimeout::isScheduled() const {
102 return EventUtil::isEventRegistered(&event_);
105 void AsyncTimeout::attachTimeoutManager(
106 TimeoutManager* timeoutManager,
107 InternalEnum internal) {
108 // This also implies no timeout is scheduled.
109 assert(timeoutManager_ == nullptr);
110 assert(timeoutManager->isInTimeoutManagerThread());
111 timeoutManager_ = timeoutManager;
113 timeoutManager_->attachTimeoutManager(this, internal);
116 void AsyncTimeout::attachEventBase(
117 EventBase* eventBase,
118 InternalEnum internal) {
119 attachTimeoutManager(eventBase, internal);
122 void AsyncTimeout::detachTimeoutManager() {
123 // Only allow the event base to be changed if the timeout is not
124 // currently installed.
126 // Programmer bug. Abort the program.
127 LOG(FATAL) << "detachEventBase() called on scheduled timeout; aborting";
130 if (timeoutManager_) {
131 timeoutManager_->detachTimeoutManager(this);
132 timeoutManager_ = nullptr;
136 void AsyncTimeout::detachEventBase() {
137 detachTimeoutManager();
140 void AsyncTimeout::libeventCallback(libevent_fd_t fd, short events, void* arg) {
141 AsyncTimeout* timeout = reinterpret_cast<AsyncTimeout*>(arg);
142 assert(libeventFdToFd(fd) == -1);
143 assert(events == EV_TIMEOUT);
144 // prevent unused variable warnings
148 // double check that ev_flags gets reset when the timeout is not running
149 assert((event_ref_flags(&timeout->event_) & ~EVLIST_INTERNAL) == EVLIST_INIT);
151 // this can't possibly fire if timeout->eventBase_ is nullptr
152 timeout->timeoutManager_->bumpHandlingTime();
154 RequestContextScopeGuard rctx(timeout->context_);
156 timeout->timeoutExpired();