Add a default timeout parameter to HHWheelTimer.
[folly.git] / folly / io / async / AsyncTimeout.cpp
1 /*
2  * Copyright 2015 Facebook, Inc.
3  *
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
11  *
12  *   http://www.apache.org/licenses/LICENSE-2.0
13  *
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
19  * under the License.
20  */
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>
25
26 #include <assert.h>
27 #include <glog/logging.h>
28
29 namespace folly {
30
31 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager)
32     : timeoutManager_(timeoutManager) {
33
34   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
35   event_.ev_base = nullptr;
36   timeoutManager_->attachTimeoutManager(
37       this,
38       TimeoutManager::InternalEnum::NORMAL);
39   RequestContext::saveContext();
40 }
41
42 AsyncTimeout::AsyncTimeout(EventBase* eventBase)
43     : timeoutManager_(eventBase) {
44
45   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
46   event_.ev_base = nullptr;
47   if (eventBase) {
48     timeoutManager_->attachTimeoutManager(
49       this,
50       TimeoutManager::InternalEnum::NORMAL);
51   }
52   RequestContext::saveContext();
53 }
54
55 AsyncTimeout::AsyncTimeout(TimeoutManager* timeoutManager,
56                              InternalEnum internal)
57     : timeoutManager_(timeoutManager) {
58
59   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
60   event_.ev_base = nullptr;
61   timeoutManager_->attachTimeoutManager(this, internal);
62   RequestContext::saveContext();
63 }
64
65 AsyncTimeout::AsyncTimeout(EventBase* eventBase, InternalEnum internal)
66     : timeoutManager_(eventBase) {
67
68   event_set(&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   event_set(&event_, -1, EV_TIMEOUT, &AsyncTimeout::libeventCallback, this);
76   event_.ev_base = nullptr;
77   RequestContext::saveContext();
78 }
79
80 AsyncTimeout::~AsyncTimeout() {
81   cancelTimeout();
82 }
83
84 bool AsyncTimeout::scheduleTimeout(TimeoutManager::timeout_type timeout) {
85   assert(timeoutManager_ != nullptr);
86   context_ = RequestContext::saveContext();
87   return timeoutManager_->scheduleTimeout(this, timeout);
88 }
89
90 bool AsyncTimeout::scheduleTimeout(uint32_t milliseconds) {
91   return scheduleTimeout(TimeoutManager::timeout_type(milliseconds));
92 }
93
94 void AsyncTimeout::cancelTimeout() {
95   if (isScheduled()) {
96     timeoutManager_->cancelTimeout(this);
97   }
98 }
99
100 bool AsyncTimeout::isScheduled() const {
101   return EventUtil::isEventRegistered(&event_);
102 }
103
104 void AsyncTimeout::attachTimeoutManager(
105     TimeoutManager* timeoutManager,
106     InternalEnum internal) {
107   // This also implies no timeout is scheduled.
108   assert(timeoutManager_ == nullptr);
109   assert(timeoutManager->isInTimeoutManagerThread());
110   timeoutManager_ = timeoutManager;
111
112   timeoutManager_->attachTimeoutManager(this, internal);
113 }
114
115 void AsyncTimeout::attachEventBase(
116     EventBase* eventBase,
117     InternalEnum internal) {
118   attachTimeoutManager(eventBase, internal);
119 }
120
121 void AsyncTimeout::detachTimeoutManager() {
122   // Only allow the event base to be changed if the timeout is not
123   // currently installed.
124   if (isScheduled()) {
125     // Programmer bug.  Abort the program.
126     LOG(ERROR) << "detachEventBase() called on scheduled timeout; aborting";
127     abort();
128     return;
129   }
130
131   if (timeoutManager_) {
132     timeoutManager_->detachTimeoutManager(this);
133     timeoutManager_ = nullptr;
134   }
135 }
136
137 void AsyncTimeout::detachEventBase() {
138   detachTimeoutManager();
139 }
140
141 void AsyncTimeout::libeventCallback(int fd, short events, void* arg) {
142   AsyncTimeout* timeout = reinterpret_cast<AsyncTimeout*>(arg);
143   assert(fd == -1);
144   assert(events == EV_TIMEOUT);
145
146   // double check that ev_flags gets reset when the timeout is not running
147   assert((timeout->event_.ev_flags & ~EVLIST_INTERNAL) == EVLIST_INIT);
148
149   // this can't possibly fire if timeout->eventBase_ is nullptr
150   (void) timeout->timeoutManager_->bumpHandlingTime();
151
152   auto old_ctx =
153     RequestContext::setContext(timeout->context_);
154
155   timeout->timeoutExpired();
156
157   RequestContext::setContext(old_ctx);
158 }
159
160 } // folly