• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 gRPC authors.
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 #ifndef GRPC_SRC_CORE_UTIL_WORK_SERIALIZER_H
18 #define GRPC_SRC_CORE_UTIL_WORK_SERIALIZER_H
19 
20 #include <grpc/event_engine/event_engine.h>
21 #include <grpc/support/port_platform.h>
22 
23 #include <functional>
24 #include <memory>
25 
26 #include "absl/base/thread_annotations.h"
27 #include "src/core/util/debug_location.h"
28 #include "src/core/util/orphanable.h"
29 
30 namespace grpc_core {
31 
32 // WorkSerializer is a mechanism to schedule callbacks in a synchronized manner.
33 // All callbacks scheduled on a WorkSerializer instance will be executed
34 // serially in a borrowed thread. The API provides a FIFO guarantee to the
35 // execution of callbacks scheduled on the thread.
36 // When a thread calls Run() with a callback, the thread is considered borrowed.
37 // The callback might run inline, or it might run asynchronously in a different
38 // thread that is already inside of Run(). If the callback runs directly inline,
39 // other callbacks from other threads might also be executed before Run()
40 // returns. Since an arbitrary set of callbacks might be executed when Run() is
41 // called, generally no locks should be held while calling Run().
42 // If a thread wants to preclude the possibility of the callback being invoked
43 // inline in Run() (for example, if a mutex lock is held and executing callbacks
44 // inline would cause a deadlock), it should use Schedule() instead and then
45 // invoke DrainQueue() when it is safe to invoke the callback.
46 class ABSL_LOCKABLE WorkSerializer {
47  public:
48   explicit WorkSerializer(
49       std::shared_ptr<grpc_event_engine::experimental::EventEngine>
50           event_engine);
51   ~WorkSerializer();
52 
53   WorkSerializer(const WorkSerializer&) = delete;
54   WorkSerializer& operator=(const WorkSerializer&) = delete;
55   WorkSerializer(WorkSerializer&&) noexcept = default;
56   WorkSerializer& operator=(WorkSerializer&&) noexcept = default;
57 
58   // Runs a given callback on the work serializer.
59   //
60   // If experiment `work_serializer_dispatch` is enabled:
61   // The callback will be executed as an EventEngine callback, that then
62   // arranges for the next callback in the queue to execute.
63   //
64   // If experiment `work_serializer_dispatch` is NOT enabled:
65   // If there is no other thread currently executing the WorkSerializer, the
66   // callback is run immediately. In this case, the current thread is also
67   // borrowed for draining the queue for any callbacks that get added in the
68   // meantime.
69   // This behavior is deprecated and will be removed soon.
70   //
71   // If you want to use clang thread annotation to make sure that callback is
72   // called by WorkSerializer only, you need to add the annotation to both the
73   // lambda function given to Run and the actual callback function like;
74   //
75   //   void run_callback() {
76   //     work_serializer.Run(
77   //         []() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer) {
78   //            callback();
79   //         }, DEBUG_LOCATION);
80   //   }
81   //   void callback() ABSL_EXCLUSIVE_LOCKS_REQUIRED(work_serializer) { ... }
82   void Run(std::function<void()> callback, const DebugLocation& location);
83 
84   // Schedule \a callback to be run later when the queue of callbacks is
85   // drained.
86   void Schedule(std::function<void()> callback, const DebugLocation& location);
87   // Drains the queue of callbacks.
88   void DrainQueue();
89 
90 #ifndef NDEBUG
91   // Returns true if the current thread is running in the WorkSerializer.
92   bool RunningInWorkSerializer() const;
93 #endif
94 
95  private:
96   class WorkSerializerImpl;
97   class LegacyWorkSerializer;
98   class DispatchingWorkSerializer;
99 
100   OrphanablePtr<WorkSerializerImpl> impl_;
101 };
102 
103 }  // namespace grpc_core
104 
105 #endif  // GRPC_SRC_CORE_UTIL_WORK_SERIALIZER_H
106