Move thrift/lib/cpp/async to folly.
[folly.git] / folly / io / async / AsyncTimeout.cpp
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 #include "folly/io/async/AsyncTimeout.h"
20 #include "folly/io/async/EventBase.h"
21 #include "folly/io/async/EventUtil.h"
22 #include "folly/io/async/Request.h"
23
24 #include <assert.h>
25 #include <glog/logging.h>
26
27 namespace folly {
28
29 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager)
30     : timeoutManager_(timeoutManager) {
31
32   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
33   event_.ev_base = nullptr;
34   timeoutManager_->attachTimeoutManager(
35       this,
36       TimeoutManager::InternalEnum::NORMAL);
37   RequestContext::getStaticContext();
38 }
39
40 AsyncTimeout::AsyncTimeout(EventBase* eventBase)
41     : timeoutManager_(eventBase) {
42
43   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
44   event_.ev_base = nullptr;
45   timeoutManager_->attachTimeoutManager(
46       this,
47       TimeoutManager::InternalEnum::NORMAL);
48   RequestContext::getStaticContext();
49 }
50
51 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager,
52                              InternalEnum internal)
53     : timeoutManager_(timeoutManager) {
54
55   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
56   event_.ev_base = nullptr;
57   timeoutManager_->attachTimeoutManager(this, internal);
58   RequestContext::getStaticContext();
59 }
60
61 AsyncTimeout::AsyncTimeout(EventBase* eventBase, InternalEnum internal)
62     : timeoutManager_(eventBase) {
63
64   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
65   event_.ev_base = nullptr;
66   timeoutManager_->attachTimeoutManager(this, internal);
67   RequestContext::getStaticContext();
68 }
69
70 AsyncTimeout::AsyncTimeout(): timeoutManager_(nullptr) {
71   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
72   event_.ev_base = nullptr;
73   RequestContext::getStaticContext();
74 }
75
76 AsyncTimeout::~AsyncTimeout() {
77   cancelTimeout();
78 }
79
80 bool AsyncTimeout::scheduleTimeout(std::chrono::milliseconds timeout) {
81   assert(timeoutManager_ != nullptr);
82   context_ = RequestContext::saveContext();
83   return timeoutManager_->scheduleTimeout(this, timeout);
84 }
85
86 bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
87   return scheduleTimeout(std::chrono::milliseconds(milliseconds));
88 }
89
90 void AsyncTimeout::cancelTimeout() {
91   if (isScheduled()) {
92     timeoutManager_->cancelTimeout(this);
93   }
94 }
95
96 bool AsyncTimeout::isScheduled() const {
97   return EventUtil::isEventRegistered(&event_);
98 }
99
100 void AsyncTimeout::attachTimeoutManager(
101     TimeoutManager* timeoutManager,
102     InternalEnum internal) {
103   // This also implies no timeout is scheduled.
104   assert(timeoutManager_ == nullptr);
105   assert(timeoutManager->isInTimeoutManagerThread());
106   timeoutManager_ = timeoutManager;
107
108   timeoutManager_->attachTimeoutManager(this, internal);
109 }
110
111 void AsyncTimeout::attachEventBase(
112     EventBase* eventBase,
113     InternalEnum internal) {
114   attachTimeoutManager(eventBase, internal);
115 }
116
117 void AsyncTimeout::detachTimeoutManager() {
118   // Only allow the event base to be changed if the timeout is not
119   // currently installed.
120   if (isScheduled()) {
121     // Programmer bug.  Abort the program.
122     LOG(ERROR) << "detachEventBase() called on scheduled timeout; aborting";
123     abort();
124     return;
125   }
126
127   if (timeoutManager_) {
128     timeoutManager_->detachTimeoutManager(this);
129     timeoutManager_ = nullptr;
130   }
131 }
132
133 void AsyncTimeout::detachEventBase() {
134   detachTimeoutManager();
135 }
136
137 void AsyncTimeout::libeventCallback(int fd, short events, void* arg) {
138   AsyncTimeout* timeout = reinterpret_cast<AsyncTimeout*>(arg);
139   assert(fd == -1);
140   assert(events == EV_TIMEOUT);
141
142   // double check that ev_flags gets reset when the timeout is not running
143   assert((timeout->event_.ev_flags & ~EVLIST_INTERNAL) == EVLIST_INIT);
144
145   // this can't possibly fire if timeout->eventBase_ is nullptr
146   (void) timeout->timeoutManager_->bumpHandlingTime();
147
148   auto old_ctx =
149     RequestContext::setContext(timeout->context_);
150
151   timeout->timeoutExpired();
152
153   RequestContext::setContext(old_ctx);
154 }
155
156 } // folly