1 | /* |
2 | * Copyright 2018-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/executors/TimekeeperScheduledExecutor.h> |
18 | #include <folly/futures/Future.h> |
19 | |
20 | namespace folly { |
21 | |
22 | /* static */ Executor::KeepAlive<TimekeeperScheduledExecutor> |
23 | TimekeeperScheduledExecutor::create( |
24 | Executor::KeepAlive<> parent, |
25 | Function<std::shared_ptr<Timekeeper>()> getTimekeeper) { |
26 | return makeKeepAlive<TimekeeperScheduledExecutor>( |
27 | new TimekeeperScheduledExecutor( |
28 | std::move(parent), std::move(getTimekeeper))); |
29 | } |
30 | |
31 | void TimekeeperScheduledExecutor::run(Func func) { |
32 | try { |
33 | func(); |
34 | } catch (std::exception const& ex) { |
35 | LOG(ERROR) << "func threw unhandled exception " << folly::exceptionStr(ex); |
36 | } catch (...) { |
37 | LOG(ERROR) << "func threw unhandled non-exception object" ; |
38 | } |
39 | } |
40 | |
41 | void TimekeeperScheduledExecutor::add(Func func) { |
42 | parent_->add( |
43 | [keepAlive = getKeepAliveToken(this), f = std::move(func)]() mutable { |
44 | keepAlive->run(std::move(f)); |
45 | }); |
46 | } |
47 | |
48 | void TimekeeperScheduledExecutor::scheduleAt( |
49 | Func&& func, |
50 | ScheduledExecutor::TimePoint const& t) { |
51 | auto delay = std::chrono::duration_cast<folly::Duration>( |
52 | t - std::chrono::steady_clock::now()); |
53 | if (delay.count() > 0) { |
54 | auto tk = getTimekeeper_(); |
55 | if (UNLIKELY(!tk)) { |
56 | throw TimekeeperScheduledExecutorNoTimekeeper(); |
57 | } |
58 | tk->after(delay) |
59 | .via(parent_.copy()) |
60 | .thenValue([keepAlive = getKeepAliveToken(this), f = std::move(func)]( |
61 | auto&&) mutable { keepAlive->run(std::move(f)); }); |
62 | } else { |
63 | add(std::move(func)); |
64 | } |
65 | } |
66 | |
67 | bool TimekeeperScheduledExecutor::keepAliveAcquire() { |
68 | auto keepAliveCounter = |
69 | keepAliveCounter_.fetch_add(1, std::memory_order_relaxed); |
70 | DCHECK(keepAliveCounter > 0); |
71 | return true; |
72 | } |
73 | |
74 | void TimekeeperScheduledExecutor::keepAliveRelease() { |
75 | auto keepAliveCounter = |
76 | keepAliveCounter_.fetch_sub(1, std::memory_order_acq_rel); |
77 | DCHECK(keepAliveCounter > 0); |
78 | if (keepAliveCounter == 1) { |
79 | delete this; |
80 | } |
81 | } |
82 | |
83 | } // namespace folly |
84 | |