2 * Copyright 2014 Facebook, Inc.
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
21 #include <folly/io/async/AsyncTimeout.h>
22 #include <folly/io/async/EventBase.h>
23 #include <folly/io/async/EventUtil.h>
24 #include <folly/io/async/Request.h>
27 #include <glog/logging.h>
31 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager)
32 : timeoutManager_(timeoutManager) {
34 event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
35 event_.ev_base = nullptr;
36 timeoutManager_->attachTimeoutManager(
38 TimeoutManager::InternalEnum::NORMAL);
39 RequestContext::getStaticContext();
42 AsyncTimeout::AsyncTimeout(EventBase* eventBase)
43 : timeoutManager_(eventBase) {
45 event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
46 event_.ev_base = nullptr;
47 timeoutManager_->attachTimeoutManager(
49 TimeoutManager::InternalEnum::NORMAL);
50 RequestContext::getStaticContext();
53 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager,
54 InternalEnum internal)
55 : timeoutManager_(timeoutManager) {
57 event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
58 event_.ev_base = nullptr;
59 timeoutManager_->attachTimeoutManager(this, internal);
60 RequestContext::getStaticContext();
63 AsyncTimeout::AsyncTimeout(EventBase* eventBase, InternalEnum internal)
64 : timeoutManager_(eventBase) {
66 event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
67 event_.ev_base = nullptr;
68 timeoutManager_->attachTimeoutManager(this, internal);
69 RequestContext::getStaticContext();
72 AsyncTimeout::AsyncTimeout(): timeoutManager_(nullptr) {
73 event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
74 event_.ev_base = nullptr;
75 RequestContext::getStaticContext();
78 AsyncTimeout::~AsyncTimeout() {
82 bool AsyncTimeout::scheduleTimeout(std::chrono::milliseconds timeout) {
83 assert(timeoutManager_ != nullptr);
84 context_ = RequestContext::saveContext();
85 return timeoutManager_->scheduleTimeout(this, timeout);
88 bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
89 return scheduleTimeout(std::chrono::milliseconds(milliseconds));
92 void AsyncTimeout::cancelTimeout() {
94 timeoutManager_->cancelTimeout(this);
98 bool AsyncTimeout::isScheduled() const {
99 return EventUtil::isEventRegistered(&event_);
102 void AsyncTimeout::attachTimeoutManager(
103 TimeoutManager* timeoutManager,
104 InternalEnum internal) {
105 // This also implies no timeout is scheduled.
106 assert(timeoutManager_ == nullptr);
107 assert(timeoutManager->isInTimeoutManagerThread());
108 timeoutManager_ = timeoutManager;
110 timeoutManager_->attachTimeoutManager(this, internal);
113 void AsyncTimeout::attachEventBase(
114 EventBase* eventBase,
115 InternalEnum internal) {
116 attachTimeoutManager(eventBase, internal);
119 void AsyncTimeout::detachTimeoutManager() {
120 // Only allow the event base to be changed if the timeout is not
121 // currently installed.
123 // Programmer bug. Abort the program.
124 LOG(ERROR) << "detachEventBase() called on scheduled timeout; aborting";
129 if (timeoutManager_) {
130 timeoutManager_->detachTimeoutManager(this);
131 timeoutManager_ = nullptr;
135 void AsyncTimeout::detachEventBase() {
136 detachTimeoutManager();
139 void AsyncTimeout::libeventCallback(int fd, short events, void* arg) {
140 AsyncTimeout* timeout = reinterpret_cast<AsyncTimeout*>(arg);
142 assert(events == EV_TIMEOUT);
144 // double check that ev_flags gets reset when the timeout is not running
145 assert((timeout->event_.ev_flags & ~EVLIST_INTERNAL) == EVLIST_INIT);
147 // this can't possibly fire if timeout->eventBase_ is nullptr
148 (void) timeout->timeoutManager_->bumpHandlingTime();
151 RequestContext::setContext(timeout->context_);
153 timeout->timeoutExpired();
155 RequestContext::setContext(old_ctx);