Move address caching logic from AsyncSSLSocket to AsyncSocket.
[folly.git] / folly / io / async / AsyncTimeout.cpp
1 /*
2  * Copyright 2004-present 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/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>
21
22 #include <assert.h>
23 #include <glog/logging.h>
24
25 namespace folly {
26
27 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager)
28     : timeoutManager_(timeoutManager) {
29
30   folly_event_set(
31       &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
32   event_.ev_base = nullptr;
33   timeoutManager_->attachTimeoutManager(
34       this,
35       TimeoutManager::InternalEnum::NORMAL);
36   RequestContext::saveContext();
37 }
38
39 AsyncTimeout::AsyncTimeout(EventBase* eventBase)
40     : timeoutManager_(eventBase) {
41
42   folly_event_set(
43       &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
44   event_.ev_base = nullptr;
45   if (eventBase) {
46     timeoutManager_->attachTimeoutManager(
47       this,
48       TimeoutManager::InternalEnum::NORMAL);
49   }
50   RequestContext::saveContext();
51 }
52
53 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager,
54                              InternalEnum internal)
55     : timeoutManager_(timeoutManager) {
56
57   folly_event_set(
58       &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
59   event_.ev_base = nullptr;
60   timeoutManager_->attachTimeoutManager(this, internal);
61   RequestContext::saveContext();
62 }
63
64 AsyncTimeout::AsyncTimeout(EventBase* eventBase, InternalEnum internal)
65     : timeoutManager_(eventBase) {
66
67   folly_event_set(
68       &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
69   event_.ev_base = nullptr;
70   timeoutManager_->attachTimeoutManager(this, internal);
71   RequestContext::saveContext();
72 }
73
74 AsyncTimeout::AsyncTimeout(): timeoutManager_(nullptr) {
75   folly_event_set(
76       &event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
77   event_.ev_base = nullptr;
78   RequestContext::saveContext();
79 }
80
81 AsyncTimeout::~AsyncTimeout() {
82   cancelTimeout();
83 }
84
85 bool AsyncTimeout::scheduleTimeout(TimeoutManager::timeout_type timeout) {
86   assert(timeoutManager_ != nullptr);
87   context_ = RequestContext::saveContext();
88   return timeoutManager_->scheduleTimeout(this, timeout);
89 }
90
91 bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
92   return scheduleTimeout(TimeoutManager::timeout_type(milliseconds));
93 }
94
95 void AsyncTimeout::cancelTimeout() {
96   if (isScheduled()) {
97     timeoutManager_->cancelTimeout(this);
98   }
99 }
100
101 bool AsyncTimeout::isScheduled() const {
102   return EventUtil::isEventRegistered(&event_);
103 }
104
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;
112
113   timeoutManager_->attachTimeoutManager(this, internal);
114 }
115
116 void AsyncTimeout::attachEventBase(
117     EventBase* eventBase,
118     InternalEnum internal) {
119   attachTimeoutManager(eventBase, internal);
120 }
121
122 void AsyncTimeout::detachTimeoutManager() {
123   // Only allow the event base to be changed if the timeout is not
124   // currently installed.
125   if (isScheduled()) {
126     // Programmer bug.  Abort the program.
127     LOG(FATAL) << "detachEventBase() called on scheduled timeout; aborting";
128   }
129
130   if (timeoutManager_) {
131     timeoutManager_->detachTimeoutManager(this);
132     timeoutManager_ = nullptr;
133   }
134 }
135
136 void AsyncTimeout::detachEventBase() {
137   detachTimeoutManager();
138 }
139
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
145   (void)fd;
146   (void)events;
147
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);
150
151   // this can't possibly fire if timeout->eventBase_ is nullptr
152   timeout->timeoutManager_->bumpHandlingTime();
153
154   RequestContextScopeGuard rctx(timeout->context_);
155
156   timeout->timeoutExpired();
157 }
158
159 } // folly