1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 #pragma once
18 
19 #include <chrono>
20 
21 #include <folly/concurrency/UnboundedQueue.h>
22 #include <folly/executors/DrivableExecutor.h>
23 
24 namespace folly {
25 
26 /*
27  * A DrivableExecutor can be driven via its drive() method or its driveUntil()
28  * that drives until some time point.
29  */
30 class TimedDrivableExecutor : public DrivableExecutor {
31  public:
32   TimedDrivableExecutor();
33   ~TimedDrivableExecutor() noexcept override;
34 
35   /// Implements DrivableExecutor
36   void drive() noexcept override;
37 
38   // Make progress if there is work to do and return true. Otherwise return
39   // false.
40   bool try_drive() noexcept;
41 
42   // Make progress on this Executor's work. Acts as drive, except it will only
43   // wait for a period of timeout for work to be enqueued. If no work is
44   // enqueued by that point, it will return.
45   template <typename Rep, typename Period>
try_drive_for(const std::chrono::duration<Rep,Period> & timeout)46   bool try_drive_for(
47       const std::chrono::duration<Rep, Period>& timeout) noexcept {
48     return try_wait_for(timeout) && run() > 0;
49   }
50 
51   // Make progress on this Executor's work. Acts as drive, except it will only
52   // wait until deadline for work to be enqueued. If no work is enqueued by
53   // that point, it will return.
54   template <typename Clock, typename Duration>
try_drive_until(const std::chrono::time_point<Clock,Duration> & deadline)55   bool try_drive_until(
56       const std::chrono::time_point<Clock, Duration>& deadline) noexcept {
57     return try_wait_until(deadline) && run() > 0;
58   }
59 
60   void add(Func) override;
61 
62   /// Do work. Returns the number of functions that were executed (maybe 0).
63   /// Non-blocking, in the sense that we don't wait for work (we can't
64   /// control whether one of the functions blocks).
65   /// This is stable, it will not chase an ever-increasing tail of work.
66   /// This also means, there may be more work available to perform at the
67   /// moment that this returns.
68   size_t run() noexcept;
69 
70   // Do work until there is no more work to do.
71   // Returns the number of functions that were executed (maybe 0).
72   // Unlike run, this method is not stable. It will chase an infinite tail of
73   // work so should be used with care.
74   // There will be no work available to perform at the moment that this
75   // returns.
76   size_t drain() noexcept;
77 
78   /// Wait for work to do.
79   void wait() noexcept;
80 
81   // Return true if there is work to do, false otherwise
82   bool try_wait() noexcept;
83 
84   /// Wait for work to do or for a period of timeout, whichever is sooner.
85   template <typename Rep, typename Period>
try_wait_for(const std::chrono::duration<Rep,Period> & timeout)86   bool try_wait_for(
87       const std::chrono::duration<Rep, Period>& timeout) noexcept {
88     return func_ || queue_.try_dequeue_for(func_, timeout);
89   }
90 
91   /// Wait for work to do or until deadline passes, whichever is sooner.
92   template <typename Clock, typename Duration>
try_wait_until(const std::chrono::time_point<Clock,Duration> & deadline)93   bool try_wait_until(
94       const std::chrono::time_point<Clock, Duration>& deadline) noexcept {
95     return func_ || queue_.try_dequeue_until(func_, deadline);
96   }
97 
98  private:
99   UMPSCQueue<Func, true> queue_;
100   Func func_;
101 };
102 
103 } // namespace folly
104